diff options
-rw-r--r-- | sys/conf/NOTES | 24 | ||||
-rw-r--r-- | sys/conf/files | 11 | ||||
-rw-r--r-- | sys/dev/sound/isa/emu8000.c | 1980 | ||||
-rw-r--r-- | sys/dev/sound/isa/gusmidi.c | 537 | ||||
-rw-r--r-- | sys/dev/sound/isa/mpu.c | 805 | ||||
-rw-r--r-- | sys/dev/sound/isa/opl.c | 1885 | ||||
-rw-r--r-- | sys/dev/sound/isa/uartsio.c | 527 | ||||
-rw-r--r-- | sys/dev/sound/midi/midi.c | 1054 | ||||
-rw-r--r-- | sys/dev/sound/midi/midi.h | 334 | ||||
-rw-r--r-- | sys/dev/sound/midi/midibuf.c | 403 | ||||
-rw-r--r-- | sys/dev/sound/midi/midibuf.h | 65 | ||||
-rw-r--r-- | sys/dev/sound/midi/midisynth.c | 532 | ||||
-rw-r--r-- | sys/dev/sound/midi/midisynth.h | 110 | ||||
-rw-r--r-- | sys/dev/sound/midi/miditypes.h | 34 | ||||
-rw-r--r-- | sys/dev/sound/midi/sequencer.c | 2603 | ||||
-rw-r--r-- | sys/dev/sound/midi/sequencer.h | 272 | ||||
-rw-r--r-- | sys/dev/sound/midi/timer.c | 564 | ||||
-rw-r--r-- | sys/dev/sound/midi/timer.h | 80 | ||||
-rw-r--r-- | sys/dev/sound/pci/csamidi.c | 586 |
19 files changed, 0 insertions, 12406 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index df2eef6804b6..3213eeee2035 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1801,30 +1801,6 @@ hint.pcm.0.irq="10" hint.pcm.0.drq="1" hint.pcm.0.flags="0x0" -# -# 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 separately configured # for providing services to the likes of new-midi. # When used with 'device pcm' they also provide pcm sound services. diff --git a/sys/conf/files b/sys/conf/files index 0d48a92d164e..a6bc61519182 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -663,33 +663,22 @@ dev/sn/if_sn_pccard.c optional sn card dev/sn/if_sn_pccard.c optional sn pccard dev/snp/snp.c optional snp 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/sb16.c optional pcm isa dev/sound/isa/sb8.c optional pcm isa dev/sound/isa/sbc.c optional pcm isa dev/sound/isa/sbc.c optional sbc isa dev/sound/isa/sndbuf_dma.c optional pcm 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/midi/timer.c optional seq midi dev/sound/pci/als4000.c optional pcm pci #dev/sound/pci/au88x0.c optional pcm pci dev/sound/pci/cmi.c optional pcm pci dev/sound/pci/cs4281.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 dependency "emu10k1-alsa%diked.h" diff --git a/sys/dev/sound/isa/emu8000.c b/sys/dev/sound/isa/emu8000.c deleted file mode 100644 index 2442e2bc08e7..000000000000 --- a/sys/dev/sound/isa/emu8000.c +++ /dev/null @@ -1,1980 +0,0 @@ -/* - * Low level EMU8000 chip driver for FreeBSD. This handles io against - * /dev/midi, the midi {in, out}put event queues and the event/message - * operation to the EMU8000 chip. - * - * (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. - * - * $FreeBSD$ - * - */ - -#include <dev/sound/midi/midi.h> - -#include <isa/isavar.h> - -static devclass_t midi_devclass; - -#ifndef DDB -#undef DDB -#define DDB(x) -#endif /* DDB */ - -/* These are the specs of EMU8000. */ -#define EMU8K_MAXVOICE 32 -#define EMU8K_MAXINFO 256 - -#define EMU8K_IDX_DATA0 0 -#define EMU8K_IDX_DATA1 1 -#define EMU8K_IDX_DATA2 1 -#define EMU8K_IDX_DATA3 2 -#define EMU8K_IDX_PTR 2 - -#define EMU8K_PORT_DATA0 0 -#define EMU8K_PORT_DATA1 0 -#define EMU8K_PORT_DATA2 2 -#define EMU8K_PORT_DATA3 0 -#define EMU8K_PORT_PTR 2 - -#define EMU8K_DRAM_RAM 0x200000 -#define EMU8K_DRAM_MAX 0xffffe0 - -/* And some convinient macros. */ -#define EMU8K_DMA_LEFT 0x00 -#define EMU8K_DMA_RIGHT 0x01 -#define EMU8K_DMA_LR 0x01 -#define EMU8K_DMA_READ 0x00 -#define EMU8K_DMA_WRITE 0x02 -#define EMU8K_DMA_RW 0x02 -#define EMU8K_DMA_MASK 0x03 - -/* The followings are the init array for EMU8000, originally in ADIP. */ - -/* Set 1 */ -static u_short init1_1[32] = -{ - 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330, - 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730, - 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30, - 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30, -}; - -static u_short init1_2[32] = -{ - 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330, - 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730, - 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30, - 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30, -}; - -static u_short init1_3[32] = -{ - 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330, - 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730, - 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30, - 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30, -}; - -static u_short init1_4[32] = -{ - 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330, - 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730, - 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30, - 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30, -}; - -/* Set 2 */ - -static u_short init2_1[32] = -{ - 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330, - 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730, - 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30, - 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30, -}; - -static u_short init2_2[32] = -{ - 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330, - 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730, - 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30, - 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30, -}; - -static u_short init2_3[32] = -{ - 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330, - 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730, - 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30, - 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30, -}; - -static u_short init2_4[32] = -{ - 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330, - 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730, - 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30, - 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30, -}; - -/* Set 3 */ - -static u_short init3_1[32] = -{ - 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, - 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254, - 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234, - 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224, -}; - -static u_short init3_2[32] = -{ - 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254, - 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264, - 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294, - 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3, -}; - -static u_short init3_3[32] = -{ - 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287, - 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7, - 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386, - 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55, -}; - -static u_short init3_4[32] = -{ - 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308, - 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F, - 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319, - 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570, -}; - -/* Set 4 */ - -static u_short init4_1[32] = -{ - 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, - 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254, - 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234, - 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224, -}; - -static u_short init4_2[32] = -{ - 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254, - 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264, - 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294, - 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3, -}; - -static u_short init4_3[32] = -{ - 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287, - 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7, - 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386, - 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55, -}; - -static u_short init4_4[32] = -{ - 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308, - 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F, - 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319, - 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570, -}; - -/* The followings are the register, the channel and the port for the EMU8000 registers. */ -struct _emu_register { - int reg; /* Register */ - int index; /* Index */ - int port; /* Port */ - int chn; /* Channel */ - int size; /* Size, 0 == word, 1 == double word */ -}; - -#define EMU8K_CHN_ANY (-1) - -static struct _emu_register emu_regs[] = -{ - /* Reg, Index, Port, Channel, Size */ - { 0, EMU8K_IDX_DATA0, EMU8K_PORT_DATA0, EMU8K_CHN_ANY, 1}, /* CPF */ - { 1, EMU8K_IDX_DATA0, EMU8K_PORT_DATA0, EMU8K_CHN_ANY, 1}, /* PTRX */ - { 2, EMU8K_IDX_DATA0, EMU8K_PORT_DATA0, EMU8K_CHN_ANY, 1}, /* CVCF */ - { 3, EMU8K_IDX_DATA0, EMU8K_PORT_DATA0, EMU8K_CHN_ANY, 1}, /* VTFT */ - { 6, EMU8K_IDX_DATA0, EMU8K_PORT_DATA0, EMU8K_CHN_ANY, 1}, /* PSST */ - { 7, EMU8K_IDX_DATA0, EMU8K_PORT_DATA0, EMU8K_CHN_ANY, 1}, /* CSL */ - { 0, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 1}, /* CCCA */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 9, 1}, /* HWCF4 */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 10, 1}, /* HWCF5 */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 13, 1}, /* HWCF6 */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 20, 1}, /* SMALR */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 21, 1}, /* SMARR */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 22, 1}, /* SMALW */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 23, 1}, /* SMARW */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 26, 0}, /* SMLD */ - { 1, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, 26, 0}, /* SMRD */ - { 1, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, 27, 0}, /* WC */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 29, 0}, /* HWCF1 */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 30, 0}, /* HWCF2 */ - { 1, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, 31, 0}, /* HWCF3 */ - { 2, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 0}, /* INIT1 */ - { 2, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, EMU8K_CHN_ANY, 0}, /* INIT2 */ - { 3, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 0}, /* INIT3 */ - { 3, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, EMU8K_CHN_ANY, 0}, /* INIT4 */ - { 4, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 0}, /* ENVVOL */ - { 5, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 0}, /* DCYSUSV */ - { 6, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 0}, /* ENVVAL */ - { 7, EMU8K_IDX_DATA1, EMU8K_PORT_DATA1, EMU8K_CHN_ANY, 0}, /* DCYSUS */ - { 4, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, EMU8K_CHN_ANY, 0}, /* ATKHLDV */ - { 5, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, EMU8K_CHN_ANY, 0}, /* LFO1VAL */ - { 6, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, EMU8K_CHN_ANY, 0}, /* ATKHLD */ - { 7, EMU8K_IDX_DATA2, EMU8K_PORT_DATA2, EMU8K_CHN_ANY, 0}, /* LFO2VAL */ - { 0, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, EMU8K_CHN_ANY, 0}, /* IP */ - { 1, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, EMU8K_CHN_ANY, 0}, /* IFATN */ - { 2, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, EMU8K_CHN_ANY, 0}, /* PEFE */ - { 3, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, EMU8K_CHN_ANY, 0}, /* FMMOD */ - { 4, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, EMU8K_CHN_ANY, 0}, /* TREMFRQ */ - { 5, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, EMU8K_CHN_ANY, 0}, /* FM2FRQ2 */ - { 7, EMU8K_IDX_DATA3, EMU8K_PORT_DATA3, 0, 0}, /* PROBE */ -}; - -/* These are the EMU8000 register names. */ -enum { - EMU8K_CPF = 0, - EMU8K_PTRX, - EMU8K_CVCF, - EMU8K_VTFT, - EMU8K_PSST, - EMU8K_CSL, - EMU8K_CCCA, - EMU8K_HWCF4, - EMU8K_HWCF5, - EMU8K_HWCF6, - EMU8K_SMALR, - EMU8K_SMARR, - EMU8K_SMALW, - EMU8K_SMARW, - EMU8K_SMLD, - EMU8K_SMRD, - EMU8K_WC, - EMU8K_HWCF1, - EMU8K_HWCF2, - EMU8K_HWCF3, - EMU8K_INIT1, - EMU8K_INIT2, - EMU8K_INIT3, - EMU8K_INIT4, - EMU8K_ENVVOL, - EMU8K_DCYSUSV, - EMU8K_ENVVAL, - EMU8K_DCYSUS, - EMU8K_ATKHLDV, - EMU8K_LFO1VAL, - EMU8K_ATKHLD, - EMU8K_LFO2VAL, - EMU8K_IP, - EMU8K_IFATN, - EMU8K_PEFE, - EMU8K_FMMOD, - EMU8K_TREMFRQ, - EMU8K_FM2FRQ2, - EMU8K_PROBE, - EMU8K_REGLAST, /* keep this! */ -}; -#define EMU8K_REGNUM (EMU8K_REGLAST) - -/* These are the synthesizer and the midi device information. */ -static struct synth_info emu_synthinfo = { - "EMU8000 Wavetable Synth", - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_AWE32, - 0, - EMU8K_MAXVOICE, - 0, - EMU8K_MAXINFO, - 0, -}; - -static struct midi_info emu_midiinfo = { - "EMU8000 Wavetable Synth", - 0, - 0, - 0, -}; - -#if notyet -/* - * These functions goes into emusynthdev_op_desc. - */ -static mdsy_killnote_t emu_killnote; -static mdsy_setinstr_t emu_setinstr; -static mdsy_startnote_t emu_startnote; -static mdsy_reset_t emu_reset; -static mdsy_hwcontrol_t emu_hwcontrol; -static mdsy_loadpatch_t emu_loadpatch; -static mdsy_panning_t emu_panning; -static mdsy_aftertouch_t emu_aftertouch; -static mdsy_controller_t emu_controller; -static mdsy_patchmgr_t emu_patchmgr; -static mdsy_bender_t emu_bender; -static mdsy_allocvoice_t emu_allocvoice; -static mdsy_setupvoice_t emu_setupvoice; -static mdsy_sendsysex_t emu_sendsysex; -static mdsy_prefixcmd_t emu_prefixcmd; -static mdsy_volumemethod_t emu_volumemethod; - -/* - * This is the synthdev_info for an EMU8000 chip. - */ -static synthdev_info emusynth_op_desc = { - emu_killnote, - emu_setinstr, - emu_startnote, - emu_reset, - emu_hwcontrol, - emu_loadpatch, - emu_panning, - emu_aftertouch, - emu_controller, - emu_patchmgr, - emu_bender, - emu_allocvoice, - emu_setupvoice, - emu_sendsysex, - emu_prefixcmd, - emu_volumemethod, -}; -#endif /* notyet */ - -/* - * These functions goes into emu_op_desc to get called - * from sound.c. - */ - -static int emu_probe(device_t dev); -static int emu_attach(device_t dev); -static int emupnp_attach(device_t dev) __unused; - -static d_open_t emu_open; -static d_close_t emu_close; -static d_ioctl_t emu_ioctl; -static midi_callback_t emu_callback; - -/* These go to mididev_info. */ -static mdsy_readraw_t emu_readraw; -static mdsy_writeraw_t emu_writeraw; - -/* Here is the parameter structure per a device. */ -struct emu_softc { - device_t dev; /* device information */ - mididev_info *devinfo; /* midi device information */ - - struct mtx mtx; /* Mutex to protect a device */ - - struct resource *io[3]; /* Base of io port */ - int io_rid[3]; /* Io resource ID */ - - u_int dramsize; /* DRAM size */ - struct synth_info synthinfo; /* Synthesizer information */ - - int fflags; /* File flags */ -}; - -typedef struct emu_softc *sc_p; - -/* These functions are local. */ -static u_int emu_dramsize(sc_p scp); -static void emu_allocdmachn(sc_p scp, int chn, int mode); -static void emu_dmaaddress(sc_p scp, int mode, u_int addr); -static void emu_waitstream(sc_p scp, int mode); -static void emu_readblkstream(sc_p scp, int mode, u_short *data, size_t len); -static void emu_writeblkstream(sc_p scp, int mode, u_short *data, size_t len); -static void emu_readstream(sc_p scp, int mode, u_short *data); -static void emu_writestream(sc_p scp, int mode, u_short data); -static void emu_releasedmachn(sc_p scp, int chn, int mode); -static void emu_delay(sc_p scp, short n); -static void emu_readcpf(sc_p scp, int chn, u_int *cp, u_int *f) __unused; -static void emu_writecpf(sc_p scp, int chn, u_int cp, u_int f); -static void emu_readptrx(sc_p scp, int chn, u_int *pt, u_int *rs, u_int *auxd) __unused; -static void emu_writeptrx(sc_p scp, int chn, u_int pt, u_int rs, u_int auxd); -static void emu_readcvcf(sc_p scp, int chn, u_int *cv, u_int *cf) __unused; -static void emu_writecvcf(sc_p scp, int chn, u_int cv, u_int cf); -static void emu_readvtft(sc_p scp, int chn, u_int *vt, u_int *ft) __unused; -static void emu_writevtft(sc_p scp, int chn, u_int vt, u_int ft); -static void emu_readpsst(sc_p scp, int chn, u_int *pan, u_int *st) __unused; -static void emu_writepsst(sc_p scp, int chn, u_int pan, u_int st); -static void emu_readcsl(sc_p scp, int chn, u_int *cs, u_int *lp) __unused; -static void emu_writecsl(sc_p scp, int chn, u_int cs, u_int lp); -static void emu_readccca(sc_p scp, int chn, u_int *q, u_int *dma, u_int *wr, u_int *right, u_int *ca) __unused; -static void emu_writeccca(sc_p scp, int chn, u_int q, u_int dma, u_int wr, u_int right, u_int ca); -static void emu_readhwcf4(sc_p scp, u_int *val) __unused; -static void emu_writehwcf4(sc_p scp, u_int val); -static void emu_readhwcf5(sc_p scp, u_int *val) __unused; -static void emu_writehwcf5(sc_p scp, u_int val); -static void emu_readhwcf6(sc_p scp, u_int *val) __unused; -static void emu_writehwcf6(sc_p scp, u_int val); -static void emu_readsmalr(sc_p scp, u_int *mt, u_int *smalr); -static void emu_writesmalr(sc_p scp, u_int mt, u_int smalr); -static void emu_readsmarr(sc_p scp, u_int *mt, u_int *smarr); -static void emu_writesmarr(sc_p scp, u_int mt, u_int smarr); -static void emu_readsmalw(sc_p scp, u_int *full, u_int *smalw); -static void emu_writesmalw(sc_p scp, u_int full, u_int smalw); -static void emu_readsmarw(sc_p scp, u_int *full, u_int *smarw); -static void emu_writesmarw(sc_p scp, u_int full, u_int smarw); -static void emu_readsmld(sc_p scp, u_short *smld); -static void emu_writesmld(sc_p scp, u_short smld); -static void emu_readsmrd(sc_p scp, u_short *smrd); -static void emu_writesmrd(sc_p scp, u_short smrd); -static void emu_readwc(sc_p scp, u_int *wc); -static void emu_writewc(sc_p scp, u_int wc) __unused; -static void emu_readhwcf1(sc_p scp, u_int *val); -static void emu_writehwcf1(sc_p scp, u_int val); -static void emu_readhwcf2(sc_p scp, u_int *val); -static void emu_writehwcf2(sc_p scp, u_int val); -static void emu_readhwcf3(sc_p scp, u_int *val) __unused; -static void emu_writehwcf3(sc_p scp, u_int val); -static void emu_readinit1(sc_p scp, int chn, u_int *val) __unused; -static void emu_writeinit1(sc_p scp, int chn, u_int val); -static void emu_readinit2(sc_p scp, int chn, u_int *val) __unused; -static void emu_writeinit2(sc_p scp, int chn, u_int val); -static void emu_readinit3(sc_p scp, int chn, u_int *val) __unused; -static void emu_writeinit3(sc_p scp, int chn, u_int val); -static void emu_readinit4(sc_p scp, int chn, u_int *val) __unused; -static void emu_writeinit4(sc_p scp, int chn, u_int val); -static void emu_readenvvol(sc_p scp, int chn, u_int *envvol) __unused; -static void emu_writeenvvol(sc_p scp, int chn, u_int envvol); -static void emu_readdcysusv(sc_p scp, int chn, u_int *ph1v, u_int *susv, u_int *off, u_int *dcyv) __unused; -static void emu_writedcysusv(sc_p scp, int chn, u_int ph1v, u_int susv, u_int off, u_int dcyv); -static void emu_readenvval(sc_p scp, int chn, u_int *envval) __unused; -static void emu_writeenvval(sc_p scp, int chn, u_int envval); -static void emu_readdcysus(sc_p scp, int chn, u_int *ph1, u_int *sus, u_int *dcy) __unused; -static void emu_writedcysus(sc_p scp, int chn, u_int ph1, u_int sus, u_int dcy); -static void emu_readatkhldv(sc_p scp, int chn, u_int *atkhldv) __unused; -static void emu_writeatkhldv(sc_p scp, int chn, u_int atkhldv); -static void emu_readlfo1val(sc_p scp, int chn, u_int *lfo1val) __unused; -static void emu_writelfo1val(sc_p scp, int chn, u_int lfo1val); -static void emu_readatkhld(sc_p scp, int chn, u_int *atkhld) __unused; -static void emu_writeatkhld(sc_p scp, int chn, u_int atkhld); -static void emu_readlfo2val(sc_p scp, int chn, u_int *lfo2val) __unused; -static void emu_writelfo2val(sc_p scp, int chn, u_int lfo2val); -static void emu_readip(sc_p scp, int chn, u_int *ip) __unused; -static void emu_writeip(sc_p scp, int chn, u_int ip); -static void emu_readifatn(sc_p scp, int chn, u_int *ifc, u_int *atn) __unused; -static void emu_writeifatn(sc_p scp, int chn, u_int ifc, u_int atn); -static void emu_readpefe(sc_p scp, int chn, u_int *pe, u_int *fe) __unused; -static void emu_writepefe(sc_p scp, int chn, u_int pe, u_int fe); -static void emu_readfmmod(sc_p scp, int chn, u_int *fm, u_int *mod) __unused; -static void emu_writefmmod(sc_p scp, int chn, u_int fm, u_int mod); -static void emu_readtremfrq(sc_p scp, int chn, u_int *trem, u_int *frq) __unused; -static void emu_writetremfrq(sc_p scp, int chn, u_int trem, u_int frq); -static void emu_readfm2frq2(sc_p scp, int chn, u_int *fm2, u_int *frq2) __unused; -static void emu_writefm2frq2(sc_p scp, int chn, u_int fm2, u_int frq2); -static void emu_readprobe(sc_p scp, u_int *val); -static void emu_writeprobe(sc_p scp, u_int val) __unused; -static void emu_command(sc_p scp, int reg, int chn, u_long val); -static u_long emu_status(sc_p scp, int reg, int chn); -static int emu_allocres(sc_p scp, device_t dev); -static void emu_releaseres(sc_p scp, device_t dev); - -/* PnP IDs */ -static struct isa_pnp_id emu_ids[] = { - {0x21008c0e, "CTL0021 WaveTable Synthesizer"}, /* CTL0021 */ - {0x22008c0e, "CTL0022 WaveTable Synthesizer"}, /* CTL0022 */ -}; - -/* - * This is the device descriptor for the midi device. - */ -mididev_info emu_op_desc = { - "EMU8000 Wavetable Synth", - - SNDCARD_AWE32, - - emu_open, - emu_close, - emu_ioctl, - emu_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 -emu_probe(device_t dev) -{ - sc_p scp; - int unit; - u_int probe, hwcf1, hwcf2; - - /* Check isapnp ids */ - if (isa_get_logicalid(dev) != 0) - return (ISA_PNP_PROBE(device_get_parent(dev), dev, emu_ids)); - /* XXX non-pnp emu? */ - - unit = device_get_unit(dev); - scp = device_get_softc(dev); - - device_set_desc(dev, "EMU8000 Wavetable Synth"); - bzero(scp, sizeof(*scp)); - - MIDI_DEBUG(printf("emu%d: probing.\n", unit)); - - if (emu_allocres(scp, dev)) { - emu_releaseres(scp, dev); - return (ENXIO); - } - - emu_readprobe(scp, &probe); - emu_readhwcf1(scp, &hwcf1); - emu_readhwcf2(scp, &hwcf2); - if ((probe & 0x000f) != 0x000c - || (hwcf1 & 0x007e) != 0x0058 - || (hwcf2 & 0x0003) != 0x0003) { - emu_releaseres(scp, dev); - return (ENXIO); - } - - MIDI_DEBUG(printf("emu%d: probed.\n", unit)); - - return (0); -} - -extern synthdev_info midisynth_op_desc; - -static int -emu_attach(device_t dev) -{ - sc_p scp; - mididev_info *devinfo; - int unit, i; - - unit = device_get_unit(dev); - scp = device_get_softc(dev); - - MIDI_DEBUG(printf("emu%d: attaching.\n", unit)); - - if (emu_allocres(scp, dev)) { - emu_releaseres(scp, dev); - return (ENXIO); - } - - /* EMU8000 needs some initialization processes. */ - - /* 1. Write HWCF{1,2}. */ - emu_writehwcf1(scp, 0x0059); - emu_writehwcf2(scp, 0x0020); - - /* Disable the audio. */ - emu_writehwcf3(scp, 0); - - /* 2. Initialize the channels. */ - - /* 2a. Write DCYSUSV. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writedcysusv(scp, i, 0, 0, 1, 0); - - /* 2b. Clear the envelope and sound engine registers. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) { - emu_writeenvvol(scp, i, 0); - emu_writeenvval(scp, i, 0); - emu_writedcysus(scp, i, 0, 0, 0); - emu_writeatkhldv(scp, i, 0); - emu_writelfo1val(scp, i, 0); - emu_writeatkhld(scp, i, 0); - emu_writelfo2val(scp, i, 0); - emu_writeip(scp, i, 0); - emu_writeifatn(scp, i, 0, 0); - emu_writepefe(scp, i, 0, 0); - emu_writefmmod(scp, i, 0, 0); - emu_writetremfrq(scp, i, 0, 0); - emu_writefm2frq2(scp, i, 0, 0); - emu_writeptrx(scp, i, 0, 0, 0); - emu_writevtft(scp, i, 0, 0); - emu_writepsst(scp, i, 0, 0); - emu_writecsl(scp, i, 0, 0); - emu_writeccca(scp, i, 0, 0, 0, 0, 0); - } - - /* 2c. Clear the current registers. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) { - emu_writecpf(scp, i, 0, 0); - emu_writecvcf(scp, i, 0, 0); - } - - /* 3. Initialize the sound memory DMA registers. */ - emu_writesmalr(scp, 0, 0); - emu_writesmarr(scp, 0, 0); - emu_writesmalw(scp, 0, 0); - emu_writesmarw(scp, 0, 0); - - /* 4. Fill the array. */ - - /* 4a. Set 1. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit1(scp, i, init1_1[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit2(scp, i, init1_2[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit3(scp, i, init1_3[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit4(scp, i, init1_4[i]); - - /* 4b. Have a rest. */ - emu_delay(scp, 1024); /* 1024 samples. */ - - /* 4c. Set 2. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit1(scp, i, init2_1[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit2(scp, i, init2_2[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit3(scp, i, init2_3[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit4(scp, i, init2_4[i]); - - /* 4d. Set 3. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit1(scp, i, init3_1[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit2(scp, i, init3_2[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit3(scp, i, init3_3[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit4(scp, i, init3_4[i]); - - /* 4e. Write to HWCF{4,5,6}. */ - emu_writehwcf4(scp, 0); - emu_writehwcf5(scp, 0x00000083); - emu_writehwcf6(scp, 0x00008000); - - /* 4f. Set 4. */ - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit1(scp, i, init4_1[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit2(scp, i, init4_2[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit3(scp, i, init4_3[i]); - for (i = 0 ; i < EMU8K_MAXVOICE ; i++) - emu_writeinit4(scp, i, init4_4[i]); - - /* 5. Determine the size of DRAM. */ - scp->dev = dev; - scp->dramsize = emu_dramsize(scp); - printf("emu%d: DRAM size = %dKB\n", unit, scp->dramsize / 1024); - - /* We have inited the EMU8000. Now work on FM. */ - - /* Write parameters for the left channel. */ - emu_writedcysusv(scp, 30, 0, 0, 1, 0); - emu_writepsst(scp, 30, 0x80, 0xffffe0); /* full left */ - emu_writecsl(scp, 30, 0, 0xfffff8); /* chorus */ - emu_writeptrx(scp, 30, 0, 0, 0); /* reverb */ - emu_writecpf(scp, 30, 0, 0); - emu_writeccca(scp, 30, 0, 0, 0, 0, 0xffffe3); - - /* Then the right channel. */ - emu_writedcysusv(scp, 31, 0, 0, 1, 0); - emu_writepsst(scp, 31, 0x80, 0xfffff0); /* full right */ - emu_writecsl(scp, 31, 0, 0xfffff8); /* chorus */ - emu_writeptrx(scp, 31, 0, 0, 0xff); /* reverb */ - emu_writecpf(scp, 31, 0, 0); - emu_writeccca(scp, 31, 0, 0, 0, 0, 0xfffff3); - - /* Skew volume and cutoff. */ - emu_writevtft(scp, 30, 0x8000, 0xffff); - emu_writevtft(scp, 31, 0x8000, 0xffff); - - /* Ready to sound. */ - emu_writehwcf3(scp, 0x0004); - - /* Fill the softc for this unit. */ - bcopy(&emu_synthinfo, &scp->synthinfo, sizeof(emu_synthinfo)); - mtx_init(&scp->mtx, "emumid", NULL, MTX_DEF); - scp->devinfo = devinfo = create_mididev_info_unit(MDT_SYNTH, &emu_op_desc, &midisynth_op_desc); - - /* Fill the midi info. */ - devinfo->synth.readraw = emu_readraw; - devinfo->synth.writeraw = emu_writeraw; - snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x, 0x%x, 0x%x", - (u_int)rman_get_start(scp->io[0]), (u_int)rman_get_start(scp->io[1]), (u_int)rman_get_start(scp->io[2])); - - midiinit(devinfo, dev); - - MIDI_DEBUG(printf("emu%d: attached.\n", unit)); - - return (0); -} - -static int -emupnp_attach(device_t dev) -{ - return (emu_attach(dev)); -} - -static int -emu_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - return (0); -} - -static int -emu_close(dev_t i_dev, int flags, int mode, struct thread *td) -{ - return (0); -} - -static int -emu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("emu_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(printf("emu_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 != unit) - return (ENXIO); - bcopy(&scp->synthinfo, synthinfo, sizeof(scp->synthinfo)); - synthinfo->device = unit; - return (0); - break; - case SNDCTL_MIDI_INFO: - midiinfo = (struct midi_info *)arg; - if (midiinfo->device != unit) - return (ENXIO); - bcopy(&emu_midiinfo, midiinfo, sizeof(emu_midiinfo)); - strcpy(midiinfo->name, scp->synthinfo.name); - midiinfo->device = unit; - return (0); - break; - case SNDCTL_SYNTH_MEMAVL: - *(int *)arg = 0x7fffffff; - return (0); - break; - default: - return (ENOSYS); - } - /* NOTREACHED */ - return (EINVAL); -} - -static int -emu_callback(void *d, int reason) -{ - mididev_info *devinfo; - - devinfo = (mididev_info *)d; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - return (0); -} - -static int -emu_readraw(mididev_info *md, u_char *buf, int len, int *lenr, int nonblock) -{ - sc_p scp; - int unit; - - if (md == NULL) - return (ENXIO); - if (lenr == NULL) - return (EINVAL); - - unit = md->unit; - scp = md->softc; - if ((md->fflags & FREAD) == 0) { - MIDI_DEBUG(printf("emu_readraw: unit %d is not for reading.\n", unit)); - return (EIO); - } - - /* NOP. */ - *lenr = 0; - - return (0); -} - -static int -emu_writeraw(mididev_info *md, u_char *buf, int len, int *lenw, int nonblock) -{ - sc_p scp; - int unit; - - if (md == NULL) - return (ENXIO); - if (lenw == NULL) - return (EINVAL); - - unit = md->unit; - scp = md->softc; - if ((md->fflags & FWRITE) == 0) { - MIDI_DEBUG(printf("emu_writeraw: unit %d is not for writing.\n", unit)); - return (EIO); - } - - /* NOP. */ - *lenw = 0; - - return (0); -} - -/* - * The functions below here are the synthesizer interfaces. - */ - -/* - * The functions below here are the libraries for the above ones. - */ - -/* Determine the size of DRAM. */ -static u_int -emu_dramsize(sc_p scp) -{ - u_int dramsize; - static u_short magiccode[] = {0x386d, 0xbd2a, 0x73df, 0xf2d8}; - static u_short magiccode2[] = {0x5ef3, 0x2b90, 0xa4c8, 0x6a13}; - u_short buf[sizeof(magiccode) / sizeof(*magiccode)]; - - /* - * Write the magic code to the bottom of DRAM. - * Writing to a wrapped address clobbers the code. - */ - emu_allocdmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE); - emu_dmaaddress(scp, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE, EMU8K_DRAM_RAM); - emu_writeblkstream(scp, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE, magiccode, sizeof(magiccode) / sizeof(*magiccode)); - emu_releasedmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE); - - for (dramsize = 0 ; dramsize + EMU8K_DRAM_RAM < EMU8K_DRAM_MAX ; ) { - - /* Read the magic code. */ - emu_allocdmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_READ); - emu_dmaaddress(scp, EMU8K_DMA_LEFT | EMU8K_DMA_READ, EMU8K_DRAM_RAM); - emu_readblkstream(scp, EMU8K_DMA_LEFT | EMU8K_DMA_READ, buf, sizeof(buf) / sizeof(*buf)); - emu_releasedmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_READ); - - /* Compare the code. */ - if (bcmp(magiccode, buf, sizeof(magiccode))) - break; - - /* Increase the DRAM size. */ - dramsize += 0x8000; - - /* Try writing a different magic code to dramsize. */ - emu_allocdmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE); - emu_dmaaddress(scp, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE, dramsize + EMU8K_DRAM_RAM); - emu_writeblkstream(scp, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE, magiccode2, sizeof(magiccode2) / sizeof(*magiccode2)); - emu_releasedmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_WRITE); - - /* Then read the magic code. */ - emu_allocdmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_READ); - emu_dmaaddress(scp, EMU8K_DMA_LEFT | EMU8K_DMA_READ, dramsize + EMU8K_DRAM_RAM); - emu_readblkstream(scp, EMU8K_DMA_LEFT | EMU8K_DMA_READ, buf, sizeof(buf) / sizeof(*buf)); - emu_releasedmachn(scp, 31, EMU8K_DMA_LEFT | EMU8K_DMA_READ); - - /* Compare the code. */ - if (bcmp(magiccode2, buf, sizeof(magiccode2))) - break; - } - if (dramsize + EMU8K_DRAM_RAM > EMU8K_DRAM_MAX) - dramsize = EMU8K_DRAM_MAX - EMU8K_DRAM_RAM; - - return dramsize * 2; /* dramsize is in words. */ -} - -/* Allocates a channel to a DMA stream. */ -static void -emu_allocdmachn(sc_p scp, int chn, int mode) -{ - /* Turn off the sound, prepare for a DMA stream. */ - emu_writedcysusv(scp, chn, 0, 0, 1, 0); - emu_writevtft(scp, chn, 0, 0); - emu_writecvcf(scp, chn, 0, 0); - emu_writeptrx(scp, chn, 0x4000, 0, 0); - emu_writecpf(scp, chn, 0x4000, 0); - emu_writepsst(scp, chn, 0, 0); - emu_writecsl(scp, chn, 0, 0); - - /* Enter DMA mode. */ - emu_writeccca(scp, chn, 0, 1, - ((mode & EMU8K_DMA_WRITE) > 0) ? 1 : 0, - ((mode & EMU8K_DMA_RIGHT) > 0) ? 1 : 0, - 0); -} - -/* Programs the initial address to a DMA. */ -static void -emu_dmaaddress(sc_p scp, int mode, u_int addr) -{ - /* Wait until the stream comes ready. */ - emu_waitstream(scp, mode); - - switch(mode & EMU8K_DMA_MASK) - { - case EMU8K_DMA_LEFT | EMU8K_DMA_READ: - emu_writesmalr(scp, 0, addr); - emu_readsmld(scp, NULL); /* Read the stale data. */ - break; - case EMU8K_DMA_RIGHT | EMU8K_DMA_READ: - emu_writesmarr(scp, 0, addr); - emu_readsmrd(scp, NULL); /* Read the stale data. */ - break; - case EMU8K_DMA_LEFT | EMU8K_DMA_WRITE: - emu_writesmalw(scp, 0, addr); - break; - case EMU8K_DMA_RIGHT | EMU8K_DMA_WRITE: - emu_writesmarw(scp, 0, addr); - break; - } -} - -/* Waits until a stream gets ready. */ -static void -emu_waitstream(sc_p scp, int mode) -{ - int i; - u_int busy; - - for (i = 0 ; i < 100000 ; i++) { - switch(mode & EMU8K_DMA_MASK) - { - case EMU8K_DMA_LEFT | EMU8K_DMA_READ: - emu_readsmalr(scp, &busy, NULL); - break; - case EMU8K_DMA_RIGHT | EMU8K_DMA_READ: - emu_readsmarr(scp, &busy, NULL); - break; - case EMU8K_DMA_LEFT | EMU8K_DMA_WRITE: - emu_readsmalw(scp, &busy, NULL); - break; - case EMU8K_DMA_RIGHT | EMU8K_DMA_WRITE: - emu_readsmarw(scp, &busy, NULL); - break; - } - if (!busy) - break; - emu_delay(scp, 1); - } - if (busy) - printf("emu%d: stream data still busy, timed out.\n", device_get_unit(scp->dev)); -} - -/* Reads a word block from a stream. */ -static void -emu_readblkstream(sc_p scp, int mode, u_short *data, size_t len) -{ - while((len--) > 0) - emu_readstream(scp, mode, data++); -} - -/* Writes a word block stream to a stream. */ -static void -emu_writeblkstream(sc_p scp, int mode, u_short *data, size_t len) -{ - while((len--) > 0) - emu_writestream(scp, mode, *(data++)); -} - -/* Reads a word from a stream. */ -static void -emu_readstream(sc_p scp, int mode, u_short *data) -{ - if ((mode & EMU8K_DMA_RW) != EMU8K_DMA_READ) - return; - - switch(mode & EMU8K_DMA_MASK) - { - case EMU8K_DMA_LEFT | EMU8K_DMA_READ: - emu_readsmld(scp, data); - break; - case EMU8K_DMA_RIGHT | EMU8K_DMA_READ: - emu_readsmrd(scp, data); - break; - } -} - -/* Writes a word to a stream. */ -static void -emu_writestream(sc_p scp, int mode, u_short data) -{ - if ((mode & EMU8K_DMA_RW) != EMU8K_DMA_WRITE) - return; - - switch(mode & EMU8K_DMA_MASK) - { - case EMU8K_DMA_LEFT | EMU8K_DMA_WRITE: - emu_writesmld(scp, data); - break; - case EMU8K_DMA_RIGHT | EMU8K_DMA_WRITE: - emu_writesmrd(scp, data); - break; - } -} - -/* Releases a channel from a DMA stream. */ -static void -emu_releasedmachn(sc_p scp, int chn, int mode) -{ - /* Wait until the stream comes ready. */ - emu_waitstream(scp, mode); - - /* Leave DMA mode. */ - emu_writeccca(scp, chn, 0, 0, 0, 0, 0); -} - -/* - * Waits cycles. - * Idea-stolen-from: sys/i386/isa/clock.c:DELAY() - */ -static void -emu_delay(sc_p scp, short n) -{ - int wc_prev, wc, wc_left, wc_delta; - - emu_readwc(scp, &wc_prev); - wc_left = n; - - while (wc_left > 0) { - emu_readwc(scp, &wc); - wc_delta = wc - wc_prev; /* The counter increases. */ - wc_prev = wc; - if (wc_delta < 0) - wc_delta += 0xffff; - wc_left -= wc_delta; - } -} - -/* The followings provide abstract access to the registers. */ -#define DECBIT(sts, shift, len) (((sts) >> (shift))) & (0xffffffff >> (32 - len)) -#define GENBIT(val, shift, len) (((val) & (0xffffffff >> (32 - len))) << (shift)) - -/* CPF: Current Pitch and Fractional Address */ -static void -emu_readcpf(sc_p scp, int chn, u_int *cp, u_int *f) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_CPF, chn); - if (cp != NULL) - *cp = DECBIT(sts, 16, 16); - if (f != NULL) - *f = DECBIT(sts, 0, 16); -} - -static void -emu_writecpf(sc_p scp, int chn, u_int cp, u_int f) -{ - emu_command(scp, EMU8K_CPF, chn, - GENBIT(cp, 16, 16) - | GENBIT(f, 0, 16)); -} - -/* PTRX: Pitch Target, Rvb Send and Aux Byte */ -static void -emu_readptrx(sc_p scp, int chn, u_int *pt, u_int *rs, u_int *auxd) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_PTRX, chn); - if (pt != NULL) - *pt = DECBIT(sts, 16, 16); - if (rs != NULL) - *rs = DECBIT(sts, 8, 8); - if (auxd != NULL) - *auxd = DECBIT(sts, 0, 8); -} - -static void -emu_writeptrx(sc_p scp, int chn, u_int pt, u_int rs, u_int auxd) -{ - emu_command(scp, EMU8K_PTRX, chn, - GENBIT(pt, 16, 16) - | GENBIT(rs, 8, 8) - | GENBIT(auxd, 0, 8)); -} - -/* CVCF: Current Volume and Filter Cutoff */ -static void -emu_readcvcf(sc_p scp, int chn, u_int *cv, u_int *cf) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_CVCF, chn); - if (cv != NULL) - *cv = DECBIT(sts, 16, 16); - if (cf != NULL) - *cf = DECBIT(sts, 0, 16); -} - -static void -emu_writecvcf(sc_p scp, int chn, u_int cv, u_int cf) -{ - emu_command(scp, EMU8K_CVCF, chn, - GENBIT(cv, 16, 16) - | GENBIT(cf, 0, 16)); -} - -/* VTFT: Volume and Filter Cutoff Targets */ -static void -emu_readvtft(sc_p scp, int chn, u_int *vt, u_int *ft) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_VTFT, chn); - if (vt != NULL) - *vt = DECBIT(sts, 16, 16); - if (ft != NULL) - *ft = DECBIT(sts, 0, 16); -} - -static void -emu_writevtft(sc_p scp, int chn, u_int vt, u_int ft) -{ - emu_command(scp, EMU8K_VTFT, chn, - GENBIT(vt, 16, 16) - | GENBIT(ft, 0, 16)); -} - -/* PSST: Pan Send and Loop Start Address */ -static void -emu_readpsst(sc_p scp, int chn, u_int *pan, u_int *st) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_PSST, chn); - if (pan != NULL) - *pan = DECBIT(sts, 24, 8); - if (st != NULL) - *st = DECBIT(sts, 0, 24); -} - -static void -emu_writepsst(sc_p scp, int chn, u_int pan, u_int st) -{ - emu_command(scp, EMU8K_PSST, chn, - GENBIT(pan, 24, 8) - | GENBIT(st, 0, 24)); -} - -/* CSL: Chorus Send and Loop End Address */ -static void -emu_readcsl(sc_p scp, int chn, u_int *cs, u_int *lp) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_CSL, chn); - if (cs != NULL) - *cs = DECBIT(sts, 24, 8); - if (lp != NULL) - *lp = DECBIT(sts, 0, 24); -} - -static void -emu_writecsl(sc_p scp, int chn, u_int cs, u_int lp) -{ - emu_command(scp, EMU8K_CSL, chn, - GENBIT(cs, 24, 8) - | GENBIT(lp, 0, 24)); -} - -/* CCCA: Q, Control Bits and Current Address */ -static void -emu_readccca(sc_p scp, int chn, u_int *q, u_int *dma, u_int *wr, u_int *right, u_int *ca) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_CCCA, chn); - if (q != NULL) - *q = DECBIT(sts, 28, 4); - if (dma != NULL) - *dma = DECBIT(sts, 26, 1); - if (wr != NULL) - *wr = DECBIT(sts, 25, 1); - if (right != NULL) - *right = DECBIT(sts, 24, 1); - if (ca != NULL) - *ca = DECBIT(sts, 0, 24); -} - -static void -emu_writeccca(sc_p scp, int chn, u_int q, u_int dma, u_int wr, u_int right, u_int ca) -{ - emu_command(scp, EMU8K_CCCA, chn, - GENBIT(q, 28, 4) - | GENBIT(dma, 26, 1) - | GENBIT(wr, 25, 1) - | GENBIT(right, 24, 1) - | GENBIT(ca, 0, 24)); -} - -/* HWCF4: Configuration Double Word 4 */ -static void -emu_readhwcf4(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_HWCF4, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writehwcf4(sc_p scp, u_int val) -{ - if (val != 0) - printf("emu%d: writing value 0x%x to HWCF4.\n", device_get_unit(scp->dev), val); - emu_command(scp, EMU8K_HWCF4, 0, val); -} - -/* HWCF5: Configuration Double Word 5 */ -static void -emu_readhwcf5(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_HWCF5, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writehwcf5(sc_p scp, u_int val) -{ - if (val != 0x00000083) - printf("emu%d: writing value 0x%x to HWCF5.\n", device_get_unit(scp->dev), val); - emu_command(scp, EMU8K_HWCF5, 0, val); -} - -/* HWCF6: Configuration Double Word 6 */ -static void -emu_readhwcf6(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_HWCF6, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writehwcf6(sc_p scp, u_int val) -{ - if (val != 0x00008000) - printf("emu%d: writing value 0x%x to HWCF6.\n", device_get_unit(scp->dev), val); - emu_command(scp, EMU8K_HWCF6, 0, val); -} - -/* SMALR: Sound Memory Address for Left SM Reads */ -static void -emu_readsmalr(sc_p scp, u_int *mt, u_int *smalr) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_SMALR, 0); - if (mt != NULL) - *mt = DECBIT(sts, 31, 1); - if (smalr != NULL) - *smalr = DECBIT(sts, 0, 24); -} - -static void -emu_writesmalr(sc_p scp, u_int mt, u_int smalr) -{ - emu_command(scp, EMU8K_SMALR, 0, - GENBIT(mt, 31, 1) - | GENBIT(smalr, 0, 24)); -} - -/* SMARR: Sound Memory Address for Right SM Reads */ -static void -emu_readsmarr(sc_p scp, u_int *mt, u_int *smarr) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_SMARR, 0); - if (mt != NULL) - *mt = DECBIT(sts, 31, 1); - if (smarr != NULL) - *smarr = DECBIT(sts, 0, 24); -} - -static void -emu_writesmarr(sc_p scp, u_int mt, u_int smarr) -{ - emu_command(scp, EMU8K_SMARR, 0, - GENBIT(mt, 31, 1) - | GENBIT(smarr, 0, 24)); -} - -/* SMALW: Sound Memory Address for Left SM Writes */ -static void -emu_readsmalw(sc_p scp, u_int *full, u_int *smalw) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_SMALW, 0); - if (full != NULL) - *full = DECBIT(sts, 31, 1); - if (smalw != NULL) - *smalw = DECBIT(sts, 0, 24); -} - -static void -emu_writesmalw(sc_p scp, u_int full, u_int smalw) -{ - emu_command(scp, EMU8K_SMALW, 0, - GENBIT(full, 31, 1) - | GENBIT(smalw, 0, 24)); -} - -/* SMARW: Sound Memory Address for Right SM Writes */ -static void -emu_readsmarw(sc_p scp, u_int *full, u_int *smarw) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_SMARW, 0); - if (full != NULL) - *full = DECBIT(sts, 31, 1); - if (smarw != NULL) - *smarw = DECBIT(sts, 0, 24); -} - -static void -emu_writesmarw(sc_p scp, u_int full, u_int smarw) -{ - emu_command(scp, EMU8K_SMARW, 0, - GENBIT(full, 31, 1) - | GENBIT(smarw, 0, 24)); -} - -/* SMLD: Sound Memory Left Data */ -static void -emu_readsmld(sc_p scp, u_short *smld) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_SMLD, 0); - if (smld != NULL) - *smld = sts; -} - -static void -emu_writesmld(sc_p scp, u_short smld) -{ - emu_command(scp, EMU8K_SMLD, 0, smld); -} - -/* SMRD: Sound Memory Right Data */ -static void -emu_readsmrd(sc_p scp, u_short *smrd) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_SMRD, 0); - if (smrd != NULL) - *smrd = sts; -} - -static void -emu_writesmrd(sc_p scp, u_short smrd) -{ - emu_command(scp, EMU8K_SMRD, 0, smrd); -} - -/* WC: Sample COunter */ -static void -emu_readwc(sc_p scp, u_int *wc) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_WC, 0); - if (wc != NULL) - *wc = sts; -} - -static void -emu_writewc(sc_p scp, u_int wc) -{ - emu_command(scp, EMU8K_WC, 0, wc); -} - -/* HWCF1: Configuration Double Word 1 */ -static void -emu_readhwcf1(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_HWCF1, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writehwcf1(sc_p scp, u_int val) -{ - if (val != 0x0059) - printf("emu%d: writing value 0x%x to HWCF1.\n", device_get_unit(scp->dev), val); - emu_command(scp, EMU8K_HWCF1, 0, val); -} - -/* HWCF2: Configuration Double Word 2 */ -static void -emu_readhwcf2(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_HWCF2, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writehwcf2(sc_p scp, u_int val) -{ - if (val != 0x0020) - printf("emu%d: writing value 0x%x to HWCF2.\n", device_get_unit(scp->dev), val); - emu_command(scp, EMU8K_HWCF2, 0, val); -} - -/* HWCF3: Configuration Double Word 3 */ -static void -emu_readhwcf3(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_HWCF3, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writehwcf3(sc_p scp, u_int val) -{ - if (val != 0x0004 && val != 0) - printf("emu%d: writing value 0x%x to HWCF3.\n", device_get_unit(scp->dev), val); - emu_command(scp, EMU8K_HWCF3, 0, val); -} - -/* INIT1: Initialization Array 1 */ -static void -emu_readinit1(sc_p scp, int chn, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_INIT1, chn); - if (val != NULL) - *val = sts; -} - -static void -emu_writeinit1(sc_p scp, int chn, u_int val) -{ - emu_command(scp, EMU8K_INIT1, chn, val); -} - -/* INIT2: Initialization Array 2 */ -static void -emu_readinit2(sc_p scp, int chn, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_INIT2, chn); - if (val != NULL) - *val = sts; -} - -static void -emu_writeinit2(sc_p scp, int chn, u_int val) -{ - emu_command(scp, EMU8K_INIT2, chn, val); -} - -/* INIT3: Initialization Array 3 */ -static void -emu_readinit3(sc_p scp, int chn, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_INIT3, chn); - if (val != NULL) - *val = sts; -} - -static void -emu_writeinit3(sc_p scp, int chn, u_int val) -{ - emu_command(scp, EMU8K_INIT3, chn, val); -} - -/* INIT4: Initialization Array 4 */ -static void -emu_readinit4(sc_p scp, int chn, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_INIT4, chn); - if (val != NULL) - *val = sts; -} - -static void -emu_writeinit4(sc_p scp, int chn, u_int val) -{ - emu_command(scp, EMU8K_INIT4, chn, val); -} - -/* ENVVOL: Volume Envelope Decay */ -static void -emu_readenvvol(sc_p scp, int chn, u_int *envvol) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_ENVVOL, chn); - if (envvol != NULL) - *envvol = sts; -} - -static void -emu_writeenvvol(sc_p scp, int chn, u_int envvol) -{ - emu_command(scp, EMU8K_ENVVOL, chn, envvol); -} - -/* DCYSUSV: Volume Envelope Sustain and Decay */ -static void -emu_readdcysusv(sc_p scp, int chn, u_int *ph1v, u_int *susv, u_int *off, u_int *dcyv) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_DCYSUSV, chn); - if (ph1v != NULL) - *ph1v = DECBIT(sts, 15, 1); - if (susv != NULL) - *susv = DECBIT(sts, 8, 7); - if (off != NULL) - *off = DECBIT(sts, 7, 1); - if (dcyv != NULL) - *dcyv = DECBIT(sts, 0, 7); -} - -static void -emu_writedcysusv(sc_p scp, int chn, u_int ph1v, u_int susv, u_int off, u_int dcyv) -{ - emu_command(scp, EMU8K_DCYSUSV, chn, - GENBIT(ph1v, 15, 1) - | GENBIT(susv, 8, 7) - | GENBIT(off, 7, 1) - | GENBIT(dcyv, 0, 7)); -} - -/* ENVVAL: Modulation Envelope Decay */ -static void -emu_readenvval(sc_p scp, int chn, u_int *envval) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_ENVVAL, chn); - if (envval != NULL) - *envval = sts; -} - -static void -emu_writeenvval(sc_p scp, int chn, u_int envval) -{ - emu_command(scp, EMU8K_ENVVAL, chn, envval); -} - -/* DCYSUS: Modulation Envelope Sustain and Decay */ -static void -emu_readdcysus(sc_p scp, int chn, u_int *ph1, u_int *sus, u_int *dcy) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_DCYSUS, chn); - if (ph1 != NULL) - *ph1 = DECBIT(sts, 15, 1); - if (sus != NULL) - *sus = DECBIT(sts, 8, 7); - if (dcy != NULL) - *dcy = DECBIT(sts, 0, 7); -} - -static void -emu_writedcysus(sc_p scp, int chn, u_int ph1, u_int sus, u_int dcy) -{ - emu_command(scp, EMU8K_DCYSUS, chn, - GENBIT(ph1, 15, 1) - | GENBIT(sus, 8, 7) - | GENBIT(dcy, 0, 7)); -} - -/* ATKHLDV: Volume Envelope Hold and Attack */ -static void -emu_readatkhldv(sc_p scp, int chn, u_int *atkhldv) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_ATKHLDV, chn); - if (atkhldv != NULL) - *atkhldv = sts; -} - -static void -emu_writeatkhldv(sc_p scp, int chn, u_int atkhldv) -{ - emu_command(scp, EMU8K_ATKHLDV, chn, atkhldv); -} - -/* LFO1VAL: LFO #1 Delay */ -static void -emu_readlfo1val(sc_p scp, int chn, u_int *lfo1val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_LFO1VAL, chn); - if (lfo1val != NULL) - *lfo1val = sts; -} - -static void -emu_writelfo1val(sc_p scp, int chn, u_int lfo1val) -{ - emu_command(scp, EMU8K_LFO1VAL, chn, lfo1val); -} - -/* ATKHLD: Modulation Envelope Hold and Attack */ -static void -emu_readatkhld(sc_p scp, int chn, u_int *atkhld) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_ATKHLD, chn); - if (atkhld != NULL) - *atkhld = sts; -} - -static void -emu_writeatkhld(sc_p scp, int chn, u_int atkhld) -{ - emu_command(scp, EMU8K_ATKHLD, chn, atkhld); -} - -/* LFO2VAL: LFO #2 Delay */ -static void -emu_readlfo2val(sc_p scp, int chn, u_int *lfo2val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_LFO2VAL, chn); - if (lfo2val != NULL) - *lfo2val = sts; -} - -static void -emu_writelfo2val(sc_p scp, int chn, u_int lfo2val) -{ - emu_command(scp, EMU8K_LFO2VAL, chn, lfo2val); -} - -/* IP: Initial Pitch */ -static void -emu_readip(sc_p scp, int chn, u_int *ip) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_IP, chn); - if (ip != NULL) - *ip = sts; -} - -static void -emu_writeip(sc_p scp, int chn, u_int ip) -{ - emu_command(scp, EMU8K_IP, chn, ip); -} - -/* IFATN: Initial Filter Cutoff and Attenuation */ -static void -emu_readifatn(sc_p scp, int chn, u_int *ifc, u_int *atn) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_IFATN, chn); - if (ifc != NULL) - *ifc = DECBIT(sts, 8, 8); - if (atn != NULL) - *atn = DECBIT(sts, 0, 8); -} - -static void -emu_writeifatn(sc_p scp, int chn, u_int ifc, u_int atn) -{ - emu_command(scp, EMU8K_IFATN, chn, - GENBIT(ifc, 8, 8) - | GENBIT(atn, 0, 8)); -} - -/* PEFE: Pitch and Filter Envelope Heights */ -static void -emu_readpefe(sc_p scp, int chn, u_int *pe, u_int *fe) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_PEFE, chn); - if (pe != NULL) - *pe = DECBIT(sts, 8, 8); - if (fe != NULL) - *fe = DECBIT(sts, 0, 8); -} - -static void -emu_writepefe(sc_p scp, int chn, u_int pe, u_int fe) -{ - emu_command(scp, EMU8K_PEFE, chn, - GENBIT(pe, 8, 8) - | GENBIT(fe, 0, 8)); -} - -/* FMMOD: Vibrato and Filter Modulation from LFO #1 */ -static void -emu_readfmmod(sc_p scp, int chn, u_int *fm, u_int *mod) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_FMMOD, chn); - if (fm != NULL) - *fm = DECBIT(sts, 8, 8); - if (mod != NULL) - *mod = DECBIT(sts, 0, 8); -} - -static void -emu_writefmmod(sc_p scp, int chn, u_int fm, u_int mod) -{ - emu_command(scp, EMU8K_FMMOD, chn, - GENBIT(fm, 8, 8) - | GENBIT(mod, 0, 8)); -} - -/* TREMFRQ: LFO #1 Tremolo Amount and Frequency */ -static void -emu_readtremfrq(sc_p scp, int chn, u_int *trem, u_int *frq) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_TREMFRQ, chn); - if (trem != NULL) - *trem = DECBIT(sts, 8, 8); - if (frq != NULL) - *frq = DECBIT(sts, 0, 8); -} - -static void -emu_writetremfrq(sc_p scp, int chn, u_int trem, u_int frq) -{ - emu_command(scp, EMU8K_TREMFRQ, chn, - GENBIT(trem, 8, 8) - | GENBIT(frq, 0, 8)); -} - -/* FM2FRQ2: LFO #2 Vibrato Amount and Frequency */ -static void -emu_readfm2frq2(sc_p scp, int chn, u_int *fm2, u_int *frq2) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_FM2FRQ2, chn); - if (fm2 != NULL) - *fm2 = DECBIT(sts, 8, 8); - if (frq2 != NULL) - *frq2 = DECBIT(sts, 0, 8); -} - -static void -emu_writefm2frq2(sc_p scp, int chn, u_int fm2, u_int frq2) -{ - emu_command(scp, EMU8K_FM2FRQ2, chn, - GENBIT(fm2, 8, 8) - | GENBIT(frq2, 0, 8)); -} - -/* PROBE: Probe Register */ -static void -emu_readprobe(sc_p scp, u_int *val) -{ - u_long sts; - - sts = emu_status(scp, EMU8K_PROBE, 0); - if (val != NULL) - *val = sts; -} - -static void -emu_writeprobe(sc_p scp, u_int val) -{ - emu_command(scp, EMU8K_PROBE, 0, val); -} - -/* Writes to a register. */ -static void -emu_command(sc_p scp, int reg, int chn, u_long val) -{ - if (chn < 0 || chn >= EMU8K_MAXVOICE || reg < 0 || reg >= EMU8K_REGNUM) - return; - - /* Override the channel if necessary. */ - if (emu_regs[reg].chn != EMU8K_CHN_ANY) - chn = emu_regs[reg].chn; - - /* Select the register first. */ - bus_space_write_2(rman_get_bustag(scp->io[EMU8K_IDX_PTR]), rman_get_bushandle(scp->io[EMU8K_IDX_PTR]), EMU8K_PORT_PTR, (chn & 0x1f) | ((emu_regs[reg].reg & 0x07) << 5)); - - /* Then we write the data. */ - bus_space_write_2(rman_get_bustag(scp->io[emu_regs[reg].index]), rman_get_bushandle(scp->io[emu_regs[reg].index]), emu_regs[reg].port, val & 0xffff); - if (emu_regs[reg].size) - /* double word */ - bus_space_write_2(rman_get_bustag(scp->io[emu_regs[reg].index]), rman_get_bushandle(scp->io[emu_regs[reg].index]), emu_regs[reg].port + 2, (val >> 16) & 0xffff); -} - -/* Reads from a register. */ -static u_long -emu_status(sc_p scp, int reg, int chn) -{ - u_long status; - - if (chn < 0 || chn >= EMU8K_MAXVOICE || reg < 0 || reg >= EMU8K_REGNUM) - return (0xffffffff); - - /* Override the channel if necessary. */ - if (emu_regs[reg].chn != EMU8K_CHN_ANY) - chn = emu_regs[reg].chn; - - /* Select the register first. */ - bus_space_write_2(rman_get_bustag(scp->io[EMU8K_IDX_PTR]), rman_get_bushandle(scp->io[EMU8K_IDX_PTR]), EMU8K_PORT_PTR, (chn & 0x1f) | ((emu_regs[reg].reg & 0x07) << 5)); - - /* Then we read the data. */ - status = bus_space_read_2(rman_get_bustag(scp->io[emu_regs[reg].index]), rman_get_bushandle(scp->io[emu_regs[reg].index]), emu_regs[reg].port) & 0xffff; - if (emu_regs[reg].size) - /* double word */ - status |= (bus_space_read_2(rman_get_bustag(scp->io[emu_regs[reg].index]), rman_get_bushandle(scp->io[emu_regs[reg].index]), emu_regs[reg].port + 2) & 0xffff) << 16; - - return (status); -} - -/* Allocates resources. */ -static int -emu_allocres(sc_p scp, device_t dev) -{ - int i; - - /* - * Attempt to allocate the EMU8000's three I/O port ranges. - */ - for (i = 0; i < 3; i++) - { - if (scp->io[i] == NULL) - { - scp->io_rid[i] = i; - scp->io[i] = bus_alloc_resource(dev, SYS_RES_IOPORT, - &(scp->io_rid[i]), - 0, ~0, 4, RF_ACTIVE); - } - } - - /* - * Fail if any of the I/O ranges failed (I.e. weren't identified and - * configured by PNP, which can happen if the ID of the card isn't - * known by the PNP quirk-handling logic) - */ - if (scp->io[0] == NULL || scp->io[1] == NULL || scp->io[2] == NULL) - { - printf("emu%d: Resource alloc failed, pnp_quirks " - "may need { 0x%08x, 0x%08x }\n", - device_get_unit(dev), - isa_get_vendorid(dev), - isa_get_logicalid(dev)); - - return 1; - } - - return 0; -} - -/* Releases resources. */ -static void -emu_releaseres(sc_p scp, device_t dev) -{ - if (scp->io[0] != NULL) { - bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid[0], scp->io[0]); - scp->io[0] = NULL; - } - if (scp->io[1] != NULL) { - bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid[1], scp->io[1]); - scp->io[1] = NULL; - } - if (scp->io[2] != NULL) { - bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid[2], scp->io[2]); - scp->io[2] = NULL; - } -} - -static device_method_t emu_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe , emu_probe ), - DEVMETHOD(device_attach, emu_attach), - - { 0, 0 }, -}; - -static driver_t emu_driver = { - "midi", - emu_methods, - sizeof(struct emu_softc), -}; - -DRIVER_MODULE(emu, isa, emu_driver, midi_devclass, 0, 0); diff --git a/sys/dev/sound/isa/gusmidi.c b/sys/dev/sound/isa/gusmidi.c deleted file mode 100644 index 16a2d18c86e3..000000000000 --- a/sys/dev/sound/isa/gusmidi.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * 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 mtx mtx; /* Mutex to protect the device. */ - - 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 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, - gusmidi_ioctl, - - 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; - - scp = device_get_softc(dev); - - /* Fill the softc. */ - scp->dev = dev; - mtx_init(&scp->mtx, "gusmid", NULL, MTX_DEF); - scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &gusmidi_op_desc, &midisynth_op_desc); - - /* Fill the midi info. */ - 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)); - - midiinit(devinfo, dev); - - bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, gusmidi_intr, scp, - &scp->ih); - - return (0); -} - -static int -gusmidi_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - - unit = MIDIUNIT(i_dev); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(printf("gusmidi_open: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - - mtx_lock(&scp->mtx); - - gusmidi_writeport(scp, PORT_CTL, MIDICTL_MASTER_RESET); - DELAY(100); - - gusmidi_writeport(scp, PORT_CTL, scp->ctl); - - mtx_unlock(&scp->mtx); - - return (0); -} - -static int -gusmidi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("gusmidi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(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 != 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 != 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; - u_char c; - mididev_info *devinfo; - int stat, did_something, leni; - - scp = (sc_p)arg; - devinfo = scp->devinfo; - - /* XXX No framing/overrun checks... */ - mtx_lock(&devinfo->flagqueue_mtx); - mtx_lock(&scp->mtx); - - do { - stat = gusmidi_readport(scp, PORT_ST); - did_something = 0; - if (stat & MIDIST_RXFULL) { - c = gusmidi_readport(scp, PORT_RX); - mtx_unlock(&scp->mtx); - if ((devinfo->flags & MIDI_F_PASSTHRU) && - (!(devinfo->flags & MIDI_F_BUSY) || - !(devinfo->fflags & FWRITE))) { - midibuf_input_intr(&devinfo->midi_dbuf_passthru, - &c, sizeof c, &leni); - 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, &leni); - } - did_something = 1; - } else - mtx_unlock(&scp->mtx); - if (stat & MIDIST_TXDONE) { - if (devinfo->flags & MIDI_F_WRITING) { - gusmidi_xmit(scp); - did_something = 1; - mtx_lock(&scp->mtx); - } else if (scp->ctl & MIDICTL_TX_IRQ_EN) { - /* This shouldn't happen. */ - mtx_lock(&scp->mtx); - scp->ctl &= ~MIDICTL_TX_IRQ_EN; - gusmidi_writeport(scp, PORT_CTL, scp->ctl); - } - } else - mtx_lock(&scp->mtx); - } while (did_something != 0); - - mtx_unlock(&scp->mtx); - mtx_unlock(&devinfo->flagqueue_mtx); - - /* Invoke the upper layer. */ - midi_intr(devinfo); -} - -static int -gusmidi_callback(void *di, int reason) -{ - int unit; - sc_p scp; - mididev_info *d; - - d = (mididev_info *)di; - - mtx_assert(&d->flagqueue_mtx, MA_OWNED); - - if (d == NULL) { - MIDI_DEBUG(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; - mtx_lock(&scp->mtx); - scp->ctl |= MIDICTL_RX_IRQ_EN; - gusmidi_writeport(scp, PORT_CTL, scp->ctl); - mtx_unlock(&scp->mtx); - } - 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: - mtx_lock(&scp->mtx); - 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; - } - gusmidi_writeport(scp, PORT_CTL, scp->ctl); - mtx_unlock(&scp->mtx); - break; - } - - return (0); -} - -/* - * The functions below here are the libraries for the above ones. - */ - -/* - * Starts to play the data in the output queue. - */ -static void -gusmidi_startplay(sc_p scp) -{ - mididev_info *devinfo; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* Can we play now? */ - if (devinfo->midi_dbuf_out.rl == 0) - return; - - devinfo->flags |= MIDI_F_WRITING; - mtx_lock(&scp->mtx); - scp->ctl |= MIDICTL_TX_IRQ_EN; - mtx_unlock(&scp->mtx); -} - -static void -gusmidi_xmit(sc_p scp) -{ - register mididev_info *devinfo; - register midi_dbuf *dbuf; - u_char c; - int leno; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* 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) { - /* Do we have the data to transmit? */ - if (dbuf->rl == 0) { - /* Stop playing. */ - devinfo->flags &= ~MIDI_F_WRITING; - mtx_lock(&scp->mtx); - scp->ctl &= ~MIDICTL_TX_IRQ_EN; - gusmidi_writeport(scp, PORT_CTL, scp->ctl); - mtx_unlock(&scp->mtx); - break; - } else { - mtx_lock(&scp->mtx); - if (gusmidi_readport(scp, PORT_ST) & MIDIST_TXDONE) { - /* Send the data. */ - midibuf_output_intr(dbuf, &c, sizeof(c), &leno); - gusmidi_writeport(scp, PORT_TX, c); - /* We are playing now. */ - } else { - mtx_unlock(&scp->mtx); - break; - } - mtx_unlock(&scp->mtx); - } - } -} - -/* 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_any(dev, SYS_RES_IRQ, - &scp->irq_rid, 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); diff --git a/sys/dev/sound/isa/mpu.c b/sys/dev/sound/isa/mpu.c deleted file mode 100644 index 3f259a76ecc2..000000000000 --- a/sys/dev/sound/isa/mpu.c +++ /dev/null @@ -1,805 +0,0 @@ -/* - * 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 <dev/sound/midi/midi.h> -#include <dev/sound/chip.h> -#include <machine/cpufunc.h> - -#include <isa/isavar.h> -#include <dev/ic/ns16550.h> - -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 mtx mtx; /* Mutex to protect the device. */ - - 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 */ - - 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); -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, u_int8_t *value); -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, - mpu_ioctl, - - 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); - - MIDI_DEBUG(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() - */ - - critical_enter(); - - /* - * 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) { - critical_exit(); - 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) { - critical_exit(); - 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) { - critical_exit(); - printf("mpu%d: not acked.\n", unit); - mpu_releaseres(scp, dev); - return (ENXIO); - } - - critical_exit(); - - 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; - - MIDI_DEBUG(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; - - scp = device_get_softc(dev); - - MIDI_DEBUG(printf("mpu: attaching.\n")); - - mtx_init(&scp->mtx, "mpumid", NULL, MTX_DEF); - - /* Allocate the resources, switch to uart mode. */ - if (mpu_allocres(scp, dev) || mpu_uartmode(scp)) { - mpu_releaseres(scp, dev); - mtx_destroy(&scp->mtx); - return (ENXIO); - } - - /* mpu_probe() has put the interface to uart mode. */ - - /* Fill the softc. */ - scp->dev = dev; - scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &mpu_op_desc, &midisynth_op_desc); - - /* Fill the midi info. */ - 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)); - - midiinit(devinfo, dev); - - /* Now we can handle the interrupts. */ - if (scp->irq != NULL) - bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, mpu_intr, scp, - &scp->ih); - - MIDI_DEBUG(printf("mpu: attached.\n")); - - 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 thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("mpu_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(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 != 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 != 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; - int leni; - - scp = (sc_p)arg; - devinfo = scp->devinfo; - - mtx_lock(&devinfo->flagqueue_mtx); - mtx_lock(&scp->mtx); - - /* Read the received data. */ - while ((mpu_status(scp) & MPU_INPUTBUSY) == 0) { - /* Receive the data. */ - mpu_readdata(scp, &c); - mtx_unlock(&scp->mtx); - /* 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), &leni); - 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), &leni); - } - mtx_lock(&scp->mtx); - } - mtx_unlock(&scp->mtx); - mtx_unlock(&devinfo->flagqueue_mtx); - - /* Invoke the upper layer. */ - midi_intr(devinfo); -} - -static int -mpu_callback(void *di, int reason) -{ - int unit; - sc_p scp; - mididev_info *d; - - d = (mididev_info *)di; - - mtx_assert(&d->flagqueue_mtx, MA_OWNED); - - if (d == NULL) { - MIDI_DEBUG(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. - */ -static void -mpu_startplay(sc_p scp) -{ - mididev_info *devinfo; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* Can we play now? */ - if (devinfo->midi_dbuf_out.rl == 0) - return; - - devinfo->flags |= MIDI_F_WRITING; - mpu_xmit(scp); -} - -static void -mpu_xmit(sc_p scp) -{ - register mididev_info *devinfo; - register midi_dbuf *dbuf; - u_char c; - int leno; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* 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) { - if (dbuf->rl == 0) - break; - else { - mtx_lock(&scp->mtx); - /* XXX Wait until we can write the data. */ - if ((mpu_status(scp) & MPU_OUTPUTBUSY) == 0) { - /* Send the data. */ - midibuf_output_intr(dbuf, &c, sizeof(c), &leno); - mpu_writedata(scp, c); - /* We are playing now. */ - devinfo->flags |= MIDI_F_WRITING; - } - mtx_unlock(&scp->mtx); - } - } - /* Stop playing. */ - devinfo->flags &= ~MIDI_F_WRITING; -} - - -/* - * Reset mpu. - * The caller must lock scp->mtx before calling this function if needed. - */ -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. - * The caller must lock scp->mtx before calling this function if needed. - */ -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. - * The caller must lock scp->mtx before calling this function if needed. - */ -static int -mpu_waitack(sc_p scp) -{ - int i; - u_int8_t resp; - - resp = 0; - for (i = 0 ; i < MPU_TRYDATA ; i++) { - if (mpu_readdata(scp, &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_int8_t *value) -{ - u_int status; - - if (value == NULL) - return (EINVAL); - - /* Is the interface ready to write? */ - status = mpu_status(scp); - if ((status & MPU_INPUTBUSY) != 0) - /* The interface is busy. */ - return (EAGAIN); - - *value = (u_int8_t)(mpu_readport(scp, MPU_DATAPORT) & 0xff); - - return (0); -} - -/* 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_any(dev, SYS_RES_IRQ, - &scp->irq_rid, 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); diff --git a/sys/dev/sound/isa/opl.c b/sys/dev/sound/isa/opl.c deleted file mode 100644 index 21eb4530cc9d..000000000000 --- a/sys/dev/sound/isa/opl.c +++ /dev/null @@ -1,1885 +0,0 @@ -/* - * A low level driver for Yamaha YM3812 and OPL-3 -chips - * - * 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. - * - */ - -/* - * Major improvements to the FM handling 30AUG92 by Rob Hooft, - */ -/* - * hooft@chem.ruu.nl - */ -/* - * - * Ported to the new Audio Driver by Luigi Rizzo: - * (C) 1999 Seigo Tanimura - * - * This is the OPL2/3/4 chip 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 operation to the OPL chip. - * - * $FreeBSD$ - * - */ - -#include <dev/sound/midi/midi.h> -#include <dev/sound/chip.h> - -#include <isa/isavar.h> - -static devclass_t midi_devclass; - -#ifndef DDB -#undef DDB -#define DDB(x) -#endif /* DDB */ - -/* - * The OPL-3 mode is switched on by writing 0x01, to the offset 5 - * of the right side. - * - * Another special register at the right side is at offset 4. It contains - * a bit mask defining which voices are used as 4 OP voices. - * - * The percussive mode is implemented in the left side only. - * - * With the above exeptions the both sides can be operated independently. - * - * A 4 OP voice can be created by setting the corresponding - * bit at offset 4 of the right side. - * - * For example setting the rightmost bit (0x01) changes the - * first voice on the right side to the 4 OP mode. The fourth - * voice is made inaccessible. - * - * If a voice is set to the 2 OP mode, it works like 2 OP modes - * of the original YM3812 (AdLib). In addition the voice can - * be connected the left, right or both stereo channels. It can - * even be left unconnected. This works with 4 OP voices also. - * - * The stereo connection bits are located in the FEEDBACK_CONNECTION - * register of the voice (0xC0-0xC8). In 4 OP voices these bits are - * in the second half of the voice. - */ - -/* - * Register numbers for the global registers - */ - -#define TEST_REGISTER 0x01 -#define ENABLE_WAVE_SELECT 0x20 - -#define TIMER1_REGISTER 0x02 -#define TIMER2_REGISTER 0x03 -#define TIMER_CONTROL_REGISTER 0x04 /* Left side */ -#define IRQ_RESET 0x80 -#define TIMER1_MASK 0x40 -#define TIMER2_MASK 0x20 -#define TIMER1_START 0x01 -#define TIMER2_START 0x02 - -#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */ -#define RIGHT_4OP_0 0x01 -#define RIGHT_4OP_1 0x02 -#define RIGHT_4OP_2 0x04 -#define LEFT_4OP_0 0x08 -#define LEFT_4OP_1 0x10 -#define LEFT_4OP_2 0x20 - -#define OPL3_MODE_REGISTER 0x05 /* Right side */ -#define OPL3_ENABLE 0x01 -#define OPL4_ENABLE 0x02 - -#define KBD_SPLIT_REGISTER 0x08 /* Left side */ -#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ -#define KEYBOARD_SPLIT 0x40 - -#define PERCUSSION_REGISTER 0xbd /* Left side only */ -#define TREMOLO_DEPTH 0x80 -#define VIBRATO_DEPTH 0x40 -#define PERCUSSION_ENABLE 0x20 -#define BASSDRUM_ON 0x10 -#define SNAREDRUM_ON 0x08 -#define TOMTOM_ON 0x04 -#define CYMBAL_ON 0x02 -#define HIHAT_ON 0x01 - -/* - * Offsets to the register banks for operators. To get the - * register number just add the operator offset to the bank offset - * - * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) - */ -#define AM_VIB 0x20 -#define TREMOLO_ON 0x80 -#define VIBRATO_ON 0x40 -#define SUSTAIN_ON 0x20 -#define KSR 0x10 /* Key scaling rate */ -#define MULTIPLE_MASK 0x0f /* Frequency multiplier */ - -/* - * KSL/Total level (0x40 to 0x55) - */ -#define KSL_LEVEL 0x40 -#define KSL_MASK 0xc0 /* Envelope scaling bits */ -#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ - -/* - * Attack / Decay rate (0x60 to 0x75) - */ -#define ATTACK_DECAY 0x60 -#define ATTACK_MASK 0xf0 -#define DECAY_MASK 0x0f - -/* - * Sustain level / Release rate (0x80 to 0x95) - */ -#define SUSTAIN_RELEASE 0x80 -#define SUSTAIN_MASK 0xf0 -#define RELEASE_MASK 0x0f - -/* - * Wave select (0xE0 to 0xF5) - */ -#define WAVE_SELECT 0xe0 - -/* - * Offsets to the register banks for voices. Just add to the - * voice number to get the register number. - * - * F-Number low bits (0xA0 to 0xA8). - */ -#define FNUM_LOW 0xa0 - -/* - * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) - */ -#define KEYON_BLOCK 0xb0 -#define KEYON_BIT 0x20 -#define BLOCKNUM_MASK 0x1c -#define FNUM_HIGH_MASK 0x03 - -/* - * Feedback / Connection (0xc0 to 0xc8) - * - * These registers have two new bits when the OPL-3 mode - * is selected. These bits controls connecting the voice - * to the stereo channels. For 4 OP voices this bit is - * defined in the second half of the voice (add 3 to the - * register offset). - * - * For 4 OP voices the connection bit is used in the - * both halfs (gives 4 ways to connect the operators). - */ -#define FEEDBACK_CONNECTION 0xc0 -#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ -#define CONNECTION_BIT 0x01 -/* - * In the 4 OP mode there is four possible configurations how the - * operators can be connected together (in 2 OP modes there is just - * AM or FM). The 4 OP connection mode is defined by the rightmost - * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halfs. - * - * First half Second half Mode - * - * +---+ - * v | - * 0 0 >+-1-+--2--3--4--> - * - * - * - * +---+ - * | | - * 0 1 >+-1-+--2-+ - * |-> - * >--3----4-+ - * - * +---+ - * | | - * 1 0 >+-1-+-----+ - * |-> - * >--2--3--4-+ - * - * +---+ - * | | - * 1 1 >+-1-+--+ - * | - * >--2--3-+-> - * | - * >--4----+ - */ -#define STEREO_BITS 0x30 /* OPL-3 only */ -#define VOICE_TO_LEFT 0x10 -#define VOICE_TO_RIGHT 0x20 - -/* - * Definition table for the physical voices - */ - -struct physical_voice_info { - unsigned char voice_num; - unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ - int ch; /* channel (left=USE_LEFT, right=USE_RIGHT) */ - unsigned char op[4]; /* Operator offsets */ -}; - -/* - * There is 18 possible 2 OP voices - * (9 in the left and 9 in the right). - * The first OP is the modulator and 2nd is the carrier. - * - * The first three voices in the both sides may be connected - * with another voice to a 4 OP voice. For example voice 0 - * can be connected with voice 3. The operators of voice 3 are - * used as operators 3 and 4 of the new 4 OP voice. - * In this case the 2 OP voice number 0 is the 'first half' and - * voice 3 is the second. - */ - -#define USE_LEFT 0 -#define USE_RIGHT 1 - -static struct physical_voice_info pv_map[18] = -{ -/* No Mode Side OP1 OP2 OP3 OP4 */ -/* --------------------------------------------------- */ - { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */ - { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */ - { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */ - - { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}}, - { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}}, - { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}} -}; - -/* These are the tuning parameters. */ -static unsigned short semitone_tuning[24] = -{ -/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, -/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, -/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755 -}; - -static unsigned short cent_tuning[100] = -{ -/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, -/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, -/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, -/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, -/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, -/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, -/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, -/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, -/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, -/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, -/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, -/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, -/* 96 */ 10570, 10576, 10582, 10589 -}; - -/* - * The next table looks magical, but it certainly is not. Its values have - * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception - * for i=0. This log-table converts a linear volume-scaling (0..127) to a - * logarithmic scaling as present in the FM-synthesizer chips. so : Volume - * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative - * volume -8 it was implemented as a table because it is only 128 bytes and - * it saves a lot of log() calculations. (RH) - */ -static char opl_volumetable[128] = -{ - -64, -48, -40, -35, -32, -29, -27, -26, - -24, -23, -21, -20, -19, -18, -18, -17, - -16, -15, -15, -14, -13, -13, -12, -12, - -11, -11, -10, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -6, -6, -6, - -5, -5, -5, -5, -4, -4, -4, -4, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -1, -1, -1, -1, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 4, - 4, 4, 4, 4, 4, 4, 4, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 8, 8, 8, 8, 8}; - -#define MAX_VOICE 18 -#define OFFS_4OP 11 -#define SBFM_MAXINSTR 256 - -/* These are the OPL Models. */ -#define MODEL_NONE 0 -#define MODEL_OPL2 2 -#define MODEL_OPL3 3 -#define MODEL_OPL4 4 - -/* These are the OPL Voice modes. */ -#define VOICE_NONE 0 -#define VOICE_2OP 2 -#define VOICE_4OP 4 - -/* PnP IDs */ -static struct isa_pnp_id opl_ids[] = { - {0x01200001, "@H@2001 FM Synthesizer"}, /* @H@2001 */ - {0x01100001, "@H@1001 FM Synthesizer"}, /* @H@1001 */ -#if notdef - /* TODO: write bridge drivers for these devices. */ - {0x0000630e, "CSC0000 FM Synthesizer"}, /* CSC0000 */ - {0x68187316, "ESS1868 FM Synthesizer"}, /* ESS1868 */ - {0x79187316, "ESS1879 FM Synthesizer"}, /* ESS1879 */ - {0x2100a865, "YMH0021 FM Synthesizer"}, /* YMH0021 */ - {0x80719304, "ADS7180 FM Synthesizer"}, /* ADS7180 */ - {0x0300561e, "GRV0003 FM Synthesizer"}, /* GRV0003 */ -#endif /* notdef */ -}; - -/* These are the default io bases. */ -static int opl_defaultiobase[] = { - 0x388, - 0x380, -}; - -/* These are the per-voice information. */ -struct voice_info { - u_char keyon_byte; - long bender; - long bender_range; - u_long orig_freq; - u_long current_freq; - int volume; - int mode; -}; - -/* These are the synthesizer and the midi device information. */ -static struct synth_info opl_synthinfo = { - "OPL FM Synthesizer", - 0, - SYNTH_TYPE_FM, - FM_TYPE_ADLIB, - 0, - 9, - 0, - SBFM_MAXINSTR, - 0, -}; - -static struct midi_info opl_midiinfo = { - "OPL FM Synthesizer", - 0, - 0, - 0, -}; - -/* - * These functions goes into oplsynthdev_op_desc. - */ -static mdsy_killnote_t opl_killnote; -static mdsy_setinstr_t opl_setinstr; -static mdsy_startnote_t opl_startnote; -static mdsy_reset_t opl_reset; -static mdsy_hwcontrol_t opl_hwcontrol; -static mdsy_loadpatch_t opl_loadpatch; -static mdsy_panning_t opl_panning; -static mdsy_aftertouch_t opl_aftertouch; -static mdsy_controller_t opl_controller; -static mdsy_patchmgr_t opl_patchmgr; -static mdsy_bender_t opl_bender; -static mdsy_allocvoice_t opl_allocvoice; -static mdsy_setupvoice_t opl_setupvoice; -static mdsy_sendsysex_t opl_sendsysex; -static mdsy_prefixcmd_t opl_prefixcmd; -static mdsy_volumemethod_t opl_volumemethod; - -/* - * This is the synthdev_info for an OPL3 chip. - */ -static synthdev_info oplsynth_op_desc = { - opl_killnote, - opl_setinstr, - opl_startnote, - opl_reset, - opl_hwcontrol, - opl_loadpatch, - opl_panning, - opl_aftertouch, - opl_controller, - opl_patchmgr, - opl_bender, - opl_allocvoice, - opl_setupvoice, - opl_sendsysex, - opl_prefixcmd, - opl_volumemethod, -}; - -/* Here is the parameter structure per a device. */ -struct opl_softc { - device_t dev; /* device information */ - mididev_info *devinfo; /* midi device information */ - - struct mtx mtx; /* Mutex to protect the device. */ - - struct resource *io; /* Base of io port */ - int io_rid; /* Io resource ID */ - - int model; /* OPL model */ - struct synth_info synthinfo; /* Synthesizer information */ - - struct sbi_instrument i_map[SBFM_MAXINSTR]; /* Instrument map */ - struct sbi_instrument *act_i[SBFM_MAXINSTR]; /* Active instruments */ - struct physical_voice_info pv_map[MAX_VOICE]; /* Physical voice map */ - int cmask; /* Connection mask */ - int lv_map[MAX_VOICE]; /* Level map */ - struct voice_info voc[MAX_VOICE]; /* Voice information */ -}; - -typedef struct opl_softc *sc_p; - -/* - * These functions goes into opl_op_desc to get called - * from sound.c. - */ - -static int opl_probe(device_t dev); -static int opl_probe1(sc_p scp); -static int opl_attach(device_t dev); -static int oplsbc_probe(device_t dev); -static int oplsbc_attach(device_t dev); - -static d_open_t opl_open; -static d_close_t opl_close; -static d_ioctl_t opl_ioctl; -static midi_callback_t opl_callback; - -/* These go to snddev_info. */ -static mdsy_readraw_t opl_readraw; -static mdsy_writeraw_t opl_writeraw; - -/* These functions are local. */ -static void opl_command(sc_p scp, int ch, int addr, u_int val); -static int opl_status(sc_p scp); -static void opl_enter4opmode(sc_p scp); -static void opl_storeinstr(sc_p scp, int instr_no, struct sbi_instrument *instr); -static void opl_calcvol(u_char *regbyte, int volume, int main_vol); -static void opl_setvoicevolume(sc_p scp, int voice, int volume, int main_vol); -static void opl_freqtofnum(int freq, int *block, int *fnum); -static int opl_bendpitch(sc_p scp, int voice, int val); -static int opl_notetofreq(int note_num); -static u_long opl_computefinetune(u_long base_freq, int bend, int range); -static int opl_allocres(sc_p scp, device_t dev); -static void opl_releaseres(sc_p scp, device_t dev); - -/* - * This is the device descriptor for the midi device. - */ -static mididev_info opl_op_desc = { - "OPL FM Synthesizer", - - SNDCARD_OPL, - - opl_open, - opl_close, - opl_ioctl, - - opl_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 -opl_probe(device_t dev) -{ - sc_p scp; - int unit, i; - - /* Check isapnp ids */ - if (isa_get_logicalid(dev) != 0) - return (ISA_PNP_PROBE(device_get_parent(dev), dev, opl_ids)); - - scp = device_get_softc(dev); - unit = device_get_unit(dev); - - device_set_desc(dev, opl_op_desc.name); - bzero(scp, sizeof(*scp)); - - MIDI_DEBUG(printf("opl%d: probing.\n", unit)); - - scp->io_rid = 0; - scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 4, RF_ACTIVE); - if (opl_allocres(scp, dev)) { - /* We try the defaults in opl_defaultiobase. */ - MIDI_DEBUG(printf("opl%d: port is omitted, trying the defaults.\n", unit)); - for (i = 0 ; i < sizeof(opl_defaultiobase) / sizeof(*opl_defaultiobase) ; i++) { - scp->io_rid = 0; - scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, opl_defaultiobase[i], opl_defaultiobase[i] + 1, 4, RF_ACTIVE); - if (scp->io != NULL) { - if (opl_probe1(scp)) - opl_releaseres(scp, dev); - else - break; - } - } - if (scp->io == NULL) - return (ENXIO); - } else if(opl_probe1(scp)) { - opl_releaseres(scp, dev); - return (ENXIO); - } - - /* We now have some kind of OPL. */ - - MIDI_DEBUG(printf("opl%d: probed.\n", unit)); - - return (0); -} - -/* We do probe in this function. */ -static int -opl_probe1(sc_p scp) -{ - u_char stat1, stat2; - - /* Reset the timers and the interrupt. */ - opl_command(scp, USE_LEFT, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - opl_command(scp, USE_LEFT, TIMER_CONTROL_REGISTER, IRQ_RESET); - - /* Read the status. */ - stat1 = opl_status(scp); - if ((stat1 & 0xe0) != 0) - return (1); - - /* Try firing the timer1. */ - opl_command(scp, USE_LEFT, TIMER1_REGISTER, 0xff); /* Set the timer value. */ - opl_command(scp, USE_LEFT, TIMER_CONTROL_REGISTER, TIMER1_START | TIMER2_MASK); /* Start the timer. */ - DELAY(150); /* Wait for the timer. */ - - /* Read the status. */ - stat2 = opl_status(scp); - - /* Reset the timers and the interrupt. */ - opl_command(scp, USE_LEFT, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - opl_command(scp, USE_LEFT, TIMER_CONTROL_REGISTER, IRQ_RESET); - - if ((stat2 & 0xe0) != 0xc0) - return (1); - - return (0); -} - -static int -oplsbc_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_SYNTH) - return (ENXIO); - - s = "SB OPL FM Synthesizer"; - - scp = device_get_softc(dev); - bzero(scp, sizeof(*scp)); - scp->io_rid = 2; - device_set_desc(dev, s); - return (0); -} - -static int -opl_attach(device_t dev) -{ - sc_p scp; - mididev_info *devinfo; - int i, opl4_io, opl4_id; - struct resource *opl4; - u_char signature, tmp; - - scp = device_get_softc(dev); - - MIDI_DEBUG(printf("opl: attaching.\n")); - - /* Fill the softc for this unit. */ - scp->dev = dev; - - /* Allocate other resources. */ - if (opl_allocres(scp, dev)) { - opl_releaseres(scp, dev); - return (ENXIO); - } - - /* Detect the OPL type. */ - signature = opl_status(scp); - if (signature == 0x06) - scp->model = MODEL_OPL2; - else { - /* OPL3 or later, might be OPL4. */ - - /* Enable OPL3 and OPL4. */ - opl_command(scp, USE_RIGHT, OPL3_MODE_REGISTER, 0); - opl_command(scp, USE_RIGHT, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); - - tmp = opl_status(scp); - if (tmp != 0x02) - scp->model = MODEL_OPL3; -#if notdef - else { -#endif /* notdef */ - /* Alloc OPL4 ID register. */ - opl4_id = 2; - opl4_io = rman_get_start(scp->io) - 8; - opl4 = bus_alloc_resource(dev, SYS_RES_IOPORT, &opl4_id, opl4_io, opl4_io + 1, 2, RF_ACTIVE); - if (opl4 != NULL) { - /* Select OPL4 ID register. */ - bus_space_write_1(rman_get_bustag(opl4), rman_get_bushandle(opl4), 0, 0x02); - DELAY(10); - tmp = bus_space_read_1(rman_get_bustag(opl4), rman_get_bushandle(opl4), 1); - DELAY(10); - - if (tmp != 0x20) - scp->model = MODEL_OPL3; - else { - scp->model = MODEL_OPL4; - - /* Select back OPL4 FM mixer control. */ - bus_space_write_1(rman_get_bustag(opl4), rman_get_bushandle(opl4), 0, 0xf8); - DELAY(10); - bus_space_write_1(rman_get_bustag(opl4), rman_get_bushandle(opl4), 1, 0x1b); - DELAY(10); - } - bus_release_resource(dev, SYS_RES_IOPORT, opl4_id, opl4); - } -#if notdef - } -#endif /* notdef */ - opl_command(scp, USE_RIGHT, OPL3_MODE_REGISTER, 0); - } - - /* Kill any previous notes. */ - for (i = 0 ; i < 9 ; i++) - opl_command(scp, USE_RIGHT, KEYON_BLOCK + i, 0); - - /* Select melodic mode. */ - opl_command(scp, USE_LEFT, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl_command(scp, USE_LEFT, PERCUSSION_REGISTER, 0); - - for (i = 0 ; i < SBFM_MAXINSTR ; i++) - scp->i_map[i].channel = -1; - - /* Fill the softc. */ - bcopy(&opl_synthinfo, &scp->synthinfo, sizeof(opl_synthinfo)); - snprintf(scp->synthinfo.name, 64, "Yamaha OPL%d FM", scp->model); - mtx_init(&scp->mtx, "oplmid", NULL, MTX_DEF); - bcopy(pv_map, scp->pv_map, sizeof(pv_map)); - if (scp->model < MODEL_OPL3) { /* OPL2. */ - scp->synthinfo.nr_voices = 9; - scp->synthinfo.nr_drums = 0; - for (i = 0 ; i < MAX_VOICE ; i++) - scp->pv_map[i].ch = USE_LEFT; - } else { /* OPL3 or later. */ - scp->synthinfo.capabilities |= SYNTH_CAP_OPL3; - scp->synthinfo.nr_voices = 18; - scp->synthinfo.nr_drums = 0; -#if notdef - for (i = 0 ; i < MAX_VOICE ; i++) { - if (scp->pv_map[i].ch == USE_LEFT) - scp->pv_map[i].ch = USE_LEFT; - else - scp->pv_map[i].ch = USE_RIGHT; - } -#endif /* notdef */ - opl_command(scp, USE_RIGHT, OPL3_MODE_REGISTER, OPL3_ENABLE); - opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, 0); - } - - scp->devinfo = devinfo = create_mididev_info_unit(MDT_SYNTH, &opl_op_desc, &oplsynth_op_desc); - - /* Fill the midi info. */ - devinfo->synth.readraw = opl_readraw; - devinfo->synth.writeraw = opl_writeraw; - devinfo->synth.alloc.max_voice = scp->synthinfo.nr_voices; - strcpy(devinfo->name, scp->synthinfo.name); - snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x", (u_int)rman_get_start(scp->io)); - - midiinit(devinfo, dev); - - MIDI_DEBUG(printf("opl: attached.\n")); - MIDI_DEBUG(printf("opl: the chip is OPL%d.\n", scp->model)); - - return (0); -} - -static int -oplsbc_attach(device_t dev) -{ - return (opl_attach(dev)); -} - -static int -opl_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit, i; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("opl%d: opening.\n", unit)); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(printf("opl_open: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - - mtx_lock(&devinfo->synth.vc_mtx); - if (scp->model < MODEL_OPL3) - devinfo->synth.alloc.max_voice = 9; - else - devinfo->synth.alloc.max_voice = 18; - devinfo->synth.alloc.timestamp = 0; - for (i = 0 ; i < MAX_VOICE ; i++) { - devinfo->synth.alloc.map[i] = 0; - devinfo->synth.alloc.alloc_times[i] = 0; - } - mtx_unlock(&devinfo->synth.vc_mtx); - scp->cmask = 0; /* We are in 2 OP mode initially. */ - if (scp->model >= MODEL_OPL3) { - mtx_lock(&scp->mtx); - opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask); - mtx_unlock(&scp->mtx); - } - - MIDI_DEBUG(printf("opl%d: opened.\n", unit)); - - return (0); -} - -static int -opl_close(dev_t i_dev, int flags, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("opl%d: closing.\n", unit)); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(printf("opl_close: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - - mtx_lock(&devinfo->synth.vc_mtx); - if (scp->model < MODEL_OPL3) - devinfo->synth.alloc.max_voice = 9; - else - devinfo->synth.alloc.max_voice = 18; - mtx_unlock(&devinfo->synth.vc_mtx); - - /* Stop the OPL. */ - opl_reset(scp->devinfo); - - MIDI_DEBUG(printf("opl%d: closed.\n", unit)); - - return (0); -} - -static int -opl_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - struct sbi_instrument *ins; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("opl_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(printf("opl_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 != unit) - return (ENXIO); - bcopy(&scp->synthinfo, synthinfo, sizeof(scp->synthinfo)); - synthinfo->device = unit; - synthinfo->nr_voices = devinfo->synth.alloc.max_voice; - if (synthinfo->nr_voices == 12) - synthinfo->nr_voices = 6; - return (0); - break; - case SNDCTL_MIDI_INFO: - midiinfo = (struct midi_info *)arg; - if (midiinfo->device != unit) - return (ENXIO); - bcopy(&opl_midiinfo, midiinfo, sizeof(opl_midiinfo)); - strcpy(midiinfo->name, scp->synthinfo.name); - midiinfo->device = unit; - return (0); - break; - case SNDCTL_FM_LOAD_INSTR: - ins = (struct sbi_instrument *)arg; - if (ins->channel < 0 || ins->channel >= SBFM_MAXINSTR) { - printf("opl_ioctl: Instrument number %d is not valid.\n", ins->channel); - return (EINVAL); - } -#if notyet - pmgr_inform(scp, PM_E_PATCH_LOADED, inc->channel, 0, 0, 0); -#endif /* notyet */ - opl_storeinstr(scp, ins->channel, ins); - return (0); - break; - case SNDCTL_SYNTH_MEMAVL: - *(int *)arg = 0x7fffffff; - return (0); - break; - case SNDCTL_FM_4OP_ENABLE: - if (scp->model >= MODEL_OPL3) - opl_enter4opmode(scp); - return (0); - break; - default: - return (ENOSYS); - } - /* NOTREACHED */ - return (EINVAL); -} - -static int -opl_callback(void *d, int reason) -{ - int unit; - sc_p scp; - mididev_info *devinfo; - - devinfo = (mididev_info *)d; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - if (devinfo == NULL) { - MIDI_DEBUG(printf("opl_callback: device not configured.\n")); - return (ENXIO); - } - - unit = devinfo->unit; - scp = devinfo->softc; - - MIDI_DEBUG(printf("opl%d: callback, reason 0x%x.\n", unit, reason)); - - switch (reason & MIDI_CB_REASON_MASK) { - case MIDI_CB_START: - if ((reason & MIDI_CB_RD) != 0 && (devinfo->flags & MIDI_F_READING) == 0) - /* Begin recording. */ - devinfo->flags |= MIDI_F_READING; - if ((reason & MIDI_CB_WR) != 0 && (devinfo->flags & MIDI_F_WRITING) == 0) - /* Start playing. */ - devinfo->flags |= MIDI_F_WRITING; - break; - case MIDI_CB_STOP: - case MIDI_CB_ABORT: - if ((reason & MIDI_CB_RD) != 0 && (devinfo->flags & MIDI_F_READING) != 0) - /* Stop recording. */ - devinfo->flags &= ~MIDI_F_READING; - if ((reason & MIDI_CB_WR) != 0 && (devinfo->flags & MIDI_F_WRITING) != 0) - /* Stop Playing. */ - devinfo->flags &= ~MIDI_F_WRITING; - break; - } - - return (0); -} - -static int -opl_readraw(mididev_info *md, u_char *buf, int len, int *lenr, int nonblock) -{ - sc_p scp; - int unit; - - if (md == NULL) - return (ENXIO); - if (lenr == NULL) - return (EINVAL); - - unit = md->unit; - scp = md->softc; - if ((md->fflags & FREAD) == 0) { - MIDI_DEBUG(printf("opl_readraw: unit %d is not for reading.\n", unit)); - return (EIO); - } - - /* NOP. */ - *lenr = 0; - - return (0); -} - -static int -opl_writeraw(mididev_info *md, u_char *buf, int len, int *lenw, int nonblock) -{ - sc_p scp; - int unit; - - if (md == NULL) - return (ENXIO); - if (lenw == NULL) - return (EINVAL); - - unit = md->unit; - scp = md->softc; - if ((md->fflags & FWRITE) == 0) { - MIDI_DEBUG(printf("opl_writeraw: unit %d is not for writing.\n", unit)); - return (EIO); - } - - /* NOP. */ - *lenw = 0; - - return (0); -} - -/* The functions below here are the synthesizer interfaces. */ - -static int -opl_killnote(mididev_info *md, int voice, int note, int vel) -{ - int unit; - sc_p scp; - struct physical_voice_info *map; - - scp = md->softc; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: killing a note, voice %d, note %d, vel %d.\n", unit, voice, note, vel)); - - if (voice < 0 || voice >= md->synth.alloc.max_voice) - return (0); - - mtx_lock(&md->synth.vc_mtx); - - md->synth.alloc.map[voice] = 0; - mtx_lock(&scp->mtx); - map = &scp->pv_map[scp->lv_map[voice]]; - - if (map->voice_mode != VOICE_NONE) { - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte & ~0x20); - - scp->voc[voice].keyon_byte = 0; - scp->voc[voice].bender = 0; - scp->voc[voice].volume = 64; - scp->voc[voice].bender_range = 200; - scp->voc[voice].orig_freq = 0; - scp->voc[voice].current_freq = 0; - scp->voc[voice].mode = 0; - } - - mtx_unlock(&scp->mtx); - mtx_unlock(&md->synth.vc_mtx); - - return (0); -} - -static int -opl_setinstr(mididev_info *md, int voice, int instr_no) -{ - int unit; - sc_p scp; - - scp = md->softc; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: setting an instrument, voice %d, instr_no %d.\n", unit, voice, instr_no)); - - - if (voice < 0 || voice >= md->synth.alloc.max_voice || instr_no < 0 || instr_no >= SBFM_MAXINSTR) - return (0); - - mtx_lock(&scp->mtx); - scp->act_i[voice] = &scp->i_map[instr_no]; - mtx_unlock(&scp->mtx); - - return (0); -} - -static int -opl_startnote(mididev_info *md, int voice, int note, int volume) -{ - u_char fpc; - int unit, block, fnum, freq, voice_mode, voice_shift; - struct sbi_instrument *instr; - struct physical_voice_info *map; - sc_p scp; - - scp = md->softc; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: starting a note, voice %d, note %d, volume %d.\n", unit, voice, note, volume)); - - if (voice < 0 || voice >= md->synth.alloc.max_voice) - return (0); - - mtx_lock(&scp->mtx); - map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == VOICE_NONE) { - mtx_unlock(&scp->mtx); - return (0); - } - - if (note == 255) { - /* Change the volume. */ - opl_setvoicevolume(scp, voice, volume, scp->voc[voice].volume); - mtx_unlock(&scp->mtx); - return (0); - } - - /* Kill the previous note. */ - opl_command(scp, map->ch, KSL_LEVEL + map->op[1], 0xff); /* Carrier volume */ - opl_command(scp, map->ch, KSL_LEVEL + map->op[0], 0xff); /* Modulator volume */ - if (map->voice_mode == VOICE_4OP) { - opl_command(scp, map->ch, KSL_LEVEL + map->op[3], 0xff); /* Carrier volume */ - opl_command(scp, map->ch, KSL_LEVEL + map->op[2], 0xff); /* Modulator volume */ - } - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, 0); /* Note off. */ - - instr = scp->act_i[voice]; - if (instr == NULL) - instr = &scp->i_map[0]; - if (instr->channel < 0) { - mtx_unlock(&scp->mtx); - printf("opl_startnote: the instrument for voice %d is undefined.\n", voice); - return (0); - } - if (map->voice_mode == VOICE_2OP && instr->key == OPL3_PATCH) { - mtx_unlock(&scp->mtx); - printf("opl_startnote: the voice mode %d mismatches the key 0x%x.\n", map->voice_mode, instr->key); - return (0); - } - - voice_mode = map->voice_mode; - if (voice_mode == VOICE_4OP) { - if (map->ch == USE_LEFT) - voice_shift = 0; - else - voice_shift = 3; - voice_shift += map->voice_num; - if (instr->key != OPL3_PATCH) { - voice_mode = VOICE_2OP; - scp->cmask &= ~(1 << voice_shift); - } else - scp->cmask |= 1 << voice_shift; - - opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask); - } - - /* Set the sound characteristics, attack, decay, sustain, release, wave select, feedback, connection. */ - opl_command(scp, map->ch, AM_VIB + map->op[0], instr->operators[0]); /* Sound characteristics. */ - opl_command(scp, map->ch, AM_VIB + map->op[1], instr->operators[1]); - opl_command(scp, map->ch, ATTACK_DECAY + map->op[0], instr->operators[4]); /* Attack and decay. */ - opl_command(scp, map->ch, ATTACK_DECAY + map->op[1], instr->operators[5]); - opl_command(scp, map->ch, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); /* Sustain and release. */ - opl_command(scp, map->ch, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); - opl_command(scp, map->ch, WAVE_SELECT + map->op[0], instr->operators[8]); /* Wave select. */ - opl_command(scp, map->ch, WAVE_SELECT + map->op[1], instr->operators[9]); - fpc = instr->operators[10]; - if ((fpc & 0x30) == 0) - fpc |= 0x30; /* So that at least one channel is enabled. */ - opl_command(scp, map->ch, FEEDBACK_CONNECTION + map->voice_num, fpc); /* Feedback and connection. */ - - if (voice_mode == VOICE_4OP) { - /* Do not forget the operators 3 and 4. */ - opl_command(scp, map->ch, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); /* Sound characteristics. */ - opl_command(scp, map->ch, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); - opl_command(scp, map->ch, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); /* Attack and decay. */ - opl_command(scp, map->ch, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); - opl_command(scp, map->ch, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); /* Sustain and release. */ - opl_command(scp, map->ch, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); - opl_command(scp, map->ch, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); /* Wave select. */ - opl_command(scp, map->ch, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); - fpc = instr->operators[OFFS_4OP + 10]; - if ((fpc & 0x30) == 0) - fpc |= 0x30; /* So that at least one channel is enabled. */ - opl_command(scp, map->ch, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); /* Feedback and connection. */ - } - scp->voc[voice].mode = voice_mode; - - opl_setvoicevolume(scp, voice, volume, scp->voc[voice].volume); - - /* Calcurate the frequency. */ - scp->voc[voice].orig_freq = opl_notetofreq(note) / 1000; - /* Tune for the pitch bend. */ - freq = scp->voc[voice].current_freq = opl_computefinetune(scp->voc[voice].orig_freq, scp->voc[voice].bender, scp->voc[voice].bender_range); - opl_freqtofnum(freq, &block, &fnum); - - /* Now we can play the note. */ - opl_command(scp, map->ch, FNUM_LOW + map->voice_num, fnum & 0xff); - scp->voc[voice].keyon_byte = 0x20 | ((block & 0x07) << 2) | ((fnum >> 8) & 0x03); - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte); - if (voice_mode == VOICE_4OP) - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num + 3, scp->voc[voice].keyon_byte); - - mtx_unlock(&scp->mtx); - - return (0); -} - -static int -opl_reset(mididev_info *md) -{ - int unit, i; - sc_p scp; - struct physical_voice_info *map; - - scp = md->softc; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: resetting.\n", unit)); - - mtx_lock(&md->synth.vc_mtx); - mtx_lock(&scp->mtx); - - for (i = 0 ; i < MAX_VOICE ; i++) - scp->lv_map[i] = i; - - for (i = 0 ; i < md->synth.alloc.max_voice ; i++) { - opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[0], 0xff); - opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[1], 0xff); - if (scp->pv_map[scp->lv_map[i]].voice_mode == VOICE_4OP) { - opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[2], 0xff); - opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[3], 0xff); - } - /* - * opl_killnote(md, i, 0, 64) inline-expanded to avoid - * unlocking and relocking mutex unnecessarily. - */ - md->synth.alloc.map[i] = 0; - map = &scp->pv_map[scp->lv_map[i]]; - - if (map->voice_mode != VOICE_NONE) { - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[i].keyon_byte & ~0x20); - - scp->voc[i].keyon_byte = 0; - scp->voc[i].bender = 0; - scp->voc[i].volume = 64; - scp->voc[i].bender_range = 200; - scp->voc[i].orig_freq = 0; - scp->voc[i].current_freq = 0; - scp->voc[i].mode = 0; - } - } - - if (scp->model >= MODEL_OPL3) { - md->synth.alloc.max_voice = 18; - for (i = 0 ; i < MAX_VOICE ; i++) - scp->pv_map[i].voice_mode = VOICE_2OP; - } - - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&scp->mtx); - - return (0); -} - -static int -opl_hwcontrol(mididev_info *md, u_char *event) -{ - /* NOP. */ - return (0); -} - -static int -opl_loadpatch(mididev_info *md, int format, struct uio *buf, int offs, int count, int pmgr_flag) -{ - int unit; - struct sbi_instrument ins; - sc_p scp; - - scp = md->softc; - unit = md->unit; - - if (count < sizeof(ins)) { - printf("opl_loadpatch: The patch record is too short.\n"); - return (EINVAL); - } - if (uiomove(&((char *)&ins)[offs], sizeof(ins) - offs, buf) != 0) - printf("opl_loadpatch: User memory mangled?\n"); - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { - printf("opl_loadpatch: Instrument number %d is not valid.\n", ins.channel); - return (EINVAL); - } - ins.key = format; - - opl_storeinstr(scp, ins.channel, &ins); - return (0); -} - -static int -opl_panning(mididev_info *md, int chn, int pan) -{ - /* NOP. */ - return (0); -} - -#define SET_VIBRATO(cell) do { \ - int tmp; \ - tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ - if (press > 110) \ - tmp |= 0x40; /* Vibrato on */ \ - opl_command(scp, map->ch, AM_VIB + map->op[cell-1], tmp);} while(0); - -static int -opl_aftertouch(mididev_info *md, int voice, int press) -{ - int unit, connection; - struct sbi_instrument *instr; - struct physical_voice_info *map; - sc_p scp; - - scp = md->softc; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: setting the aftertouch, voice %d, press %d.\n", unit, voice, press)); - - if (voice < 0 || voice >= md->synth.alloc.max_voice) - return (0); - - mtx_lock(&scp->mtx); - - map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == VOICE_NONE) { - mtx_unlock(&scp->mtx); - return (0); - } - - /* Adjust the vibrato. */ - instr = scp->act_i[voice]; - if (instr == NULL) - instr = &scp->i_map[0]; - - if (scp->voc[voice].mode == VOICE_4OP) { - connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - switch (connection) { - case 0: - SET_VIBRATO(4); - break; - case 1: - SET_VIBRATO(2); - SET_VIBRATO(4); - break; - case 2: - SET_VIBRATO(1); - SET_VIBRATO(4); - break; - case 3: - SET_VIBRATO(1); - SET_VIBRATO(3); - SET_VIBRATO(4); - break; - } - } else { - SET_VIBRATO(1); - if ((instr->operators[10] & 0x01)) - SET_VIBRATO(2); - } - - mtx_unlock(&scp->mtx); - - return (0); -} - -static int -opl_bendpitch(sc_p scp, int voice, int value) -{ - int unit, block, fnum, freq; - struct physical_voice_info *map; - mididev_info *md; - - md = scp->devinfo; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: setting the pitch bend, voice %d, value %d.\n", unit, voice, value)); - - mtx_lock(&scp->mtx); - - map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == 0) { - mtx_unlock(&scp->mtx); - return (0); - } - scp->voc[voice].bender = value; - if (value == 0 || (scp->voc[voice].keyon_byte & 0x20) == 0) { - mtx_unlock(&scp->mtx); - return (0); - } - - freq = opl_computefinetune(scp->voc[voice].orig_freq, scp->voc[voice].bender, scp->voc[voice].bender_range); - scp->voc[voice].current_freq = freq; - - opl_freqtofnum(freq, &block, &fnum); - - opl_command(scp, map->ch, FNUM_LOW + map->voice_num, fnum & 0xff); - scp->voc[voice].keyon_byte = 0x20 | ((block & 0x07) << 2) | ((fnum >> 8) & 0x03); - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte); - if (map->voice_mode == VOICE_4OP) - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num + 3, scp->voc[voice].keyon_byte); - - mtx_unlock(&scp->mtx); - - return (0); -} - -static int -opl_controller(mididev_info *md, int voice, int ctrlnum, int val) -{ - int unit; - sc_p scp; - - scp = md->softc; - unit = md->unit; - - MIDI_DEBUG(printf("opl%d: setting the controller, voice %d, ctrlnum %d, val %d.\n", unit, voice, ctrlnum, val)); - - if (voice < 0 || voice >= md->synth.alloc.max_voice) - return (0); - - switch (ctrlnum) { - case CTRL_PITCH_BENDER: - opl_bendpitch(scp, voice, val); - break; - case CTRL_PITCH_BENDER_RANGE: - mtx_lock(&scp->mtx); - scp->voc[voice].bender_range = val; - mtx_unlock(&scp->mtx); - break; - case CTRL_MAIN_VOLUME: - mtx_lock(&scp->mtx); - scp->voc[voice].volume = val / 128; - mtx_unlock(&scp->mtx); - break; - } - - return (0); -} - -static int -opl_patchmgr(mididev_info *md, struct patmgr_info *rec) -{ - return (EINVAL); -} - -static int -opl_bender(mididev_info *md, int voice, int val) -{ - sc_p scp; - - scp = md->softc; - - if (voice < 0 || voice >= md->synth.alloc.max_voice) - return (0); - - return opl_bendpitch(scp, voice, val - 8192); -} - -static int -opl_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *alloc) -{ - int i, p, best, first, avail, best_time, is4op, instr_no; - struct sbi_instrument *instr; - sc_p scp; - - scp = md->softc; - - MIDI_DEBUG(printf("opl%d: allocating a voice, chn %d, note %d.\n", md->unit, chn, note)); - - best_time = 0x7fffffff; - - mtx_lock(&md->synth.vc_mtx); - - if (chn < 0 || chn >= 15) - instr_no = 0; - else - instr_no = md->synth.chn_info[chn].pgm_num; - - mtx_lock(&scp->mtx); - - instr = &scp->i_map[instr_no]; - if (instr->channel < 0 || md->synth.alloc.max_voice != 12) - is4op = 0; - else if (md->synth.alloc.max_voice == 12) { - if (instr->key == OPL3_PATCH) - is4op = 1; - else - is4op = 0; - } else - is4op = 0; - - if (is4op) { - first = p = 0; - avail = 6; - } else { - if (md->synth.alloc.max_voice == 12) - first = p = 6; - else - first = p = 0; - avail = md->synth.alloc.max_voice; - } - - /* Look up a free voice. */ - best = first; - - for (i = 0 ; i < avail ; i++) { - if (alloc->map[p] == 0) - return (p); - } - if (alloc->alloc_times[p] < best_time) { - best_time = alloc->alloc_times[p]; - best = p; - } - p = (p + 1) % avail; - - if (best < 0) - best = 0; - else if (best > md->synth.alloc.max_voice) - best -= md->synth.alloc.max_voice; - - mtx_unlock(&scp->mtx); - mtx_unlock(&md->synth.vc_mtx); - - return best; -} - -static int -opl_setupvoice(mididev_info *md, int voice, int chn) -{ - struct channel_info *info; - sc_p scp; - - scp = md->softc; - - MIDI_DEBUG(printf("opl%d: setting up a voice, voice %d, chn %d.\n", md->unit, voice, chn)); - - mtx_lock(&md->synth.vc_mtx); - - info = &md->synth.chn_info[chn]; - - opl_setinstr(md, voice, info->pgm_num); - mtx_lock(&scp->mtx); - scp->voc[voice].bender = info->bender_value; - scp->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; - mtx_unlock(&scp->mtx); - - mtx_lock(&md->synth.vc_mtx); - - return (0); -} - -static int -opl_sendsysex(mididev_info *md, u_char *sysex, int len) -{ - /* NOP. */ - return (0); -} - -static int -opl_prefixcmd(mididev_info *md, int status) -{ - /* NOP. */ - return (0); -} - -static int -opl_volumemethod(mididev_info *md, int mode) -{ - /* NOP. */ - return (0); -} - -/* - * The functions below here are the libraries for the above ones. - */ - -/* Writes a command to the OPL chip. */ -static void -opl_command(sc_p scp, int ch, int addr, u_int val) -{ - int model; - - MIDI_DEBUG(printf("opl%d: sending a command, addr 0x%x, val 0x%x.\n", scp->devinfo->unit, addr, val)); - - model = scp->model; - - /* Write the addr first. */ - bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), ch * 2, (u_char)(addr & 0xff)); - if (model < MODEL_OPL3) - DELAY(10); - else { - bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), ch * 2); - bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), ch * 2); - } - - /* Next write the value. */ - bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), ch * 2 + 1, (u_char)(val & 0xff)); - if (model < MODEL_OPL3) - DELAY(30); - else { - bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), ch * 2); - bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), ch * 2); - } -} - -/* Reads the status of the OPL chip. */ -static int -opl_status(sc_p scp) -{ - MIDI_DEBUG(printf("opl%d: reading the status.\n", scp->devinfo->unit)); - - return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), 0); -} - -static void -opl_enter4opmode(sc_p scp) -{ - int i; - mididev_info *devinfo; - static int v4op[MAX_VOICE] = { - 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, - }; - - devinfo = scp->devinfo; - - MIDI_DEBUG(printf("opl%d: entering 4 OP mode.\n", devinfo->unit)); - - /* Connect all possible 4 OP voice operators. */ - mtx_lock(&devinfo->synth.vc_mtx); - mtx_lock(&scp->mtx); - scp->cmask = 0x3f; - opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask); - - for (i = 0 ; i < 3 ; i++) - scp->pv_map[i].voice_mode = VOICE_4OP; - for (i = 3 ; i < 6 ; i++) - scp->pv_map[i].voice_mode = VOICE_NONE; - for (i = 9 ; i < 12 ; i++) - scp->pv_map[i].voice_mode = VOICE_4OP; - for (i = 12 ; i < 15 ; i++) - scp->pv_map[i].voice_mode = VOICE_NONE; - - for (i = 0 ; i < 12 ; i++) - scp->lv_map[i] = v4op[i]; - mtx_unlock(&scp->mtx); - devinfo->synth.alloc.max_voice = 12; - mtx_unlock(&devinfo->synth.vc_mtx); -} - -static void -opl_storeinstr(sc_p scp, int instr_no, struct sbi_instrument *instr) -{ - if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || scp->model < MODEL_OPL3)) - printf("opl_storeinstr: The patch format field 0x%x is not valid.\n", instr->key); - - bcopy(instr, &scp->i_map[instr_no], sizeof(*instr)); -} - -static void -opl_calcvol(u_char *regbyte, int volume, int main_vol) -{ - int level; - - level = (~*regbyte & 0x3f); - - if (main_vol > 127) - main_vol = 127; - - volume = (volume * main_vol) / 127; - - if (level > 0) - level += opl_volumetable[volume]; - - RANGE(level, 0, 0x3f); - - *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); -} - -static void -opl_setvoicevolume(sc_p scp, int voice, int volume, int main_vol) -{ - u_char vol1, vol2, vol3, vol4; - int connection; - struct sbi_instrument *instr; - struct physical_voice_info *map; - mididev_info *devinfo; - - devinfo = scp->devinfo; - - if (voice < 0 || voice >= devinfo->synth.alloc.max_voice) - return; - - map = &scp->pv_map[scp->lv_map[voice]]; - instr = scp->act_i[voice]; - if (instr == NULL) - instr = &scp->i_map[0]; - - if (instr->channel < 0) - return; - if (scp->voc[voice].mode == VOICE_NONE) - return; - if (scp->voc[voice].mode == VOICE_2OP) { /* 2 OP mode. */ - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - if ((instr->operators[10] & 0x01)) - opl_calcvol(&vol1, volume, main_vol); - opl_calcvol(&vol2, volume, main_vol); - opl_command(scp, map->ch, KSL_LEVEL + map->op[0], vol1); - opl_command(scp, map->ch, KSL_LEVEL + map->op[1], vol2); - } else { /* 4 OP mode. */ - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - vol3 = instr->operators[OFFS_4OP + 2]; - vol4 = instr->operators[OFFS_4OP + 3]; - connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - switch(connection) { - case 0: - opl_calcvol(&vol4, volume, main_vol); - break; - case 1: - opl_calcvol(&vol2, volume, main_vol); - opl_calcvol(&vol4, volume, main_vol); - break; - case 2: - opl_calcvol(&vol1, volume, main_vol); - opl_calcvol(&vol4, volume, main_vol); - break; - case 3: - opl_calcvol(&vol1, volume, main_vol); - opl_calcvol(&vol3, volume, main_vol); - opl_calcvol(&vol4, volume, main_vol); - break; - } - opl_command(scp, map->ch, KSL_LEVEL + map->op[0], vol1); - opl_command(scp, map->ch, KSL_LEVEL + map->op[1], vol2); - opl_command(scp, map->ch, KSL_LEVEL + map->op[2], vol3); - opl_command(scp, map->ch, KSL_LEVEL + map->op[3], vol4); - } -} - -static void -opl_freqtofnum(int freq, int *block, int *fnum) -{ - int f, octave; - - f = freq; - octave = 5; - - if (f == 0) - octave = 0; - else if (f < 261) { - while (f < 261) { - octave--; - f <<= 1; - } - } else if (f > 493) { - while (f > 493) { - octave++; - f >>= 1; - } - } - if (octave > 7) - octave = 7; - - *fnum = freq * (1 << (20 - octave)) / 49716; - *block = octave; -} - -static int notes[] = -{ - 261632, - 277189, - 293671, - 311132, - 329632, - 349232, - 369998, - 391998, - 415306, - 440000, - 466162, - 493880 -}; - -#define BASE_OCTAVE 5 - -static int -opl_notetofreq(int note_num) -{ - int note, octave, note_freq; - - octave = note_num / 12; - note = note_num % 12; - - note_freq = notes[note]; - - if (octave < BASE_OCTAVE) - note_freq >>= (BASE_OCTAVE - octave); - else if (octave > BASE_OCTAVE) - note_freq <<= (octave - BASE_OCTAVE); - - return (note_freq); -} - -static u_long -opl_computefinetune(u_long base_freq, int bend, int range) -{ - u_long amount; - int negative, semitones, cents, multiplier; - - if (bend == 0 || range == 0 || base_freq == 0) - return (base_freq); - - multiplier = 1; - - if (range > 8192) - range = 8192; - - bend = bend * range / 8192; - if (bend == 0) - return (base_freq); - - if (bend < 0) { - negative = 1; - bend = -bend; - } - else - negative = 0; - if (bend > range) - bend = range; - - while (bend > 2399) { - multiplier *= 4; - bend -= 2400; - } - - semitones = bend / 100; - cents = bend % 100; - - amount = (u_long)(semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000; - - if (negative) - return (base_freq * 10000) / amount; - else - return (base_freq * amount) / 10000; -} - -/* Allocates resources other than IO ports. */ -static int -opl_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, 4, RF_ACTIVE); - if (scp->io == NULL) - return (1); - } - - return (0); -} - -/* Releases resources. */ -static void -opl_releaseres(sc_p scp, device_t dev) -{ - if (scp->io != NULL) { - bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io); - scp->io = NULL; - } -} - -static device_method_t opl_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe , opl_probe ), - DEVMETHOD(device_attach, opl_attach), - - { 0, 0 }, -}; - -static driver_t opl_driver = { - "midi", - opl_methods, - sizeof(struct opl_softc), -}; - -DRIVER_MODULE(opl, isa, opl_driver, midi_devclass, 0, 0); - -static device_method_t oplsbc_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe , oplsbc_probe ), - DEVMETHOD(device_attach, oplsbc_attach), - - { 0, 0 }, -}; - -static driver_t oplsbc_driver = { - "midi", - oplsbc_methods, - sizeof(struct opl_softc), -}; - -DRIVER_MODULE(oplsbc, sbc, oplsbc_driver, midi_devclass, 0, 0); diff --git a/sys/dev/sound/isa/uartsio.c b/sys/dev/sound/isa/uartsio.c deleted file mode 100644 index 384e1837cda1..000000000000 --- a/sys/dev/sound/isa/uartsio.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * 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 <dev/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 mtx mtx; /* Mutex to protect the device. */ - - 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, - uartsio_ioctl, - - 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); - - MIDI_DEBUG(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? */ - - MIDI_DEBUG(printf("uartsio%d: probed.\n", unit)); - - return (0); -} - -static int -uartsio_attach(device_t dev) -{ - sc_p scp; - mididev_info *devinfo; - - scp = device_get_softc(dev); - - MIDI_DEBUG(printf("uartsio: attaching.\n")); - - /* 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; - MIDI_DEBUG(printf("uartsio: uart is 16550A, tx size is %d bytes.\n", scp->tx_size)); - } else { - scp->has_fifo = 0; - scp->tx_size = 1; - MIDI_DEBUG(printf("uartsio: uart is not 16550A.\n")); - } - - /* 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); - - /* Fill the softc. */ - scp->dev = dev; - mtx_init(&scp->mtx, "siomid", NULL, MTX_DEF); - scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &uartsio_op_desc, &midisynth_op_desc); - - /* Fill the midi info. */ - snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d", - (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq)); - - midiinit(devinfo, dev); - - /* Now we can handle the interrupts. */ - bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, uartsio_intr, scp, &scp->ih); - - MIDI_DEBUG(printf("uartsio: attached.\n")); - - return (0); -} - -static int -uartsio_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("uartsio_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(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 != 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 != 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; - - mtx_lock(&devinfo->flagqueue_mtx); - uartsio_xmit(scp); - mtx_unlock(&devinfo->flagqueue_mtx); - - /* Invoke the upper layer. */ - midi_intr(devinfo); -} - -static int -uartsio_callback(void *di, int reason) -{ - int unit; - sc_p scp; - mididev_info *d; - - d = (mididev_info *)di; - - mtx_assert(&d->flagqueue_mtx, MA_OWNED); - - if (d == NULL) { - MIDI_DEBUG(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) - 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. - */ -static void -uartsio_startplay(sc_p scp) -{ - mididev_info *devinfo; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* 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, leni, leno; - u_char c[TX_FIFO_SIZE]; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - mtx_lock(&scp->mtx); - for (;;) { - /* 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); - mtx_unlock(&scp->mtx); - /* 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]), &leni); - 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]), &leni); - mtx_lock(&scp->mtx); - } - } - mtx_unlock(&scp->mtx); - - /* 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) { - /* Do we have the data to transmit? */ - if (dbuf->rl == 0) { - /* Stop playing. */ - devinfo->flags &= ~MIDI_F_WRITING; - } else { - mtx_lock(&scp->mtx); - /* Read LSR and MSR. */ - lsr = uartsio_readport(scp, com_lsr); - msr = uartsio_readport(scp, com_msr); - /* Is the device ready?. */ - if ((lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) { - /* send the data. */ - txsize = scp->tx_size; - if (dbuf->rl < txsize) - txsize = dbuf->rl; - midibuf_output_intr(dbuf, c, txsize, &leno); - 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; - } - mtx_unlock(&scp->mtx); - } - } - mtx_lock(&scp->mtx); - if (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) == IIR_NOPEND) - break; - } - mtx_unlock(&scp->mtx); - - 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) -{ - 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_any(dev, SYS_RES_IRQ, - &scp->irq_rid, 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); diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c deleted file mode 100644 index a9d018496bd7..000000000000 --- a/sys/dev/sound/midi/midi.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * 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 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 <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 = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = midiopen, - .d_close = midiclose, - .d_read = midiread, - .d_write = midiwrite, - .d_ioctl = midiioctl, - .d_poll = midipoll, - .d_name = "midi", - .d_maj = CDEV_MAJOR, -}; - -/* - * descriptors for active devices. also used as the public softc - * of a device. - */ -static TAILQ_HEAD(,_mididev_info) midi_info; -static int nmidi, nsynth; -/* Mutex to protect midi_info, nmidi and nsynth. */ -static struct mtx midiinfo_mtx; -static int midiinfo_mtx_init; - -/* These make the buffer for /dev/midistat */ -static int midistatbusy; -static char midistatbuf[4096]; -static int midistatptr; - -SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver"); - -int midi_debug; -SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, ""); - -midi_cmdtab cmdtab_midiioctl[] = { - {SNDCTL_MIDI_PRETIME, "SNDCTL_MIDI_PRETIME"}, - {SNDCTL_MIDI_MPUMODE, "SNDCTL_MIDI_MPUMODE"}, - {SNDCTL_MIDI_MPUCMD, "SNDCTL_MIDI_MPUCMD"}, - {SNDCTL_SYNTH_INFO, "SNDCTL_SYNTH_INFO"}, - {SNDCTL_MIDI_INFO, "SNDCTL_MIDI_INFO"}, - {SNDCTL_SYNTH_MEMAVL, "SNDCTL_SYNTH_MEMAVL"}, - {SNDCTL_FM_LOAD_INSTR, "SNDCTL_FM_LOAD_INSTR"}, - {SNDCTL_FM_4OP_ENABLE, "SNDCTL_FM_4OP_ENABLE"}, - {MIOSPASSTHRU, "MIOSPASSTHRU"}, - {MIOGPASSTHRU, "MIOGPASSTHRU"}, - {AIONWRITE, "AIONWRITE"}, - {AIOGSIZE, "AIOGSIZE"}, - {AIOSSIZE, "AIOSSIZE"}, - {AIOGFMT, "AIOGFMT"}, - {AIOSFMT, "AIOSFMT"}, - {AIOGMIX, "AIOGMIX"}, - {AIOSMIX, "AIOSMIX"}, - {AIOSTOP, "AIOSTOP"}, - {AIOSYNC, "AIOSYNC"}, - {AIOGCAP, "AIOGCAP"}, - {-1, NULL}, -}; - -/* - * This is the generic init routine. - * Must be called after device-specific init. - */ -int -midiinit(mididev_info *d, device_t dev) -{ - int unit; - - /* - * initialize standard parameters for the device. This can be - * overridden by device-specific configurations but better do - * here the generic things. - */ - - MIDI_DEBUG(printf("midiinit: unit %d.\n", d->unit)); - - unit = d->unit; - d->softc = device_get_softc(dev); - d->dev = dev; - d->magic = MAGIC(d->unit); /* debugging... */ - d->flags = 0; - d->fflags = 0; - d->midi_dbuf_in.unit_size = 1; - d->midi_dbuf_out.unit_size = 1; - d->midi_dbuf_passthru.unit_size = 1; - - mtx_unlock(&d->flagqueue_mtx); - - 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"); - } - make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN), - UID_ROOT, GID_WHEEL, 0666, "midi%d", unit); - - 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; - - if (MIDIDEV(i_dev) != MIDI_DEV_MIDIN) - return NULL; - u = MIDIUNIT(i_dev); - if (unit) - *unit = u; - - return get_mididev_info_unit(u); -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct. - */ -mididev_info * -get_mididev_info_unit(int unit) -{ - mididev_info *md; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - mtx_lock(&midiinfo_mtx); - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->unit == unit) - break; - } - mtx_unlock(&midiinfo_mtx); - - return md; -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct with MDT_MIDI. - */ -mididev_info * -get_mididev_midi_unit(int unit) -{ - mididev_info *md; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - mtx_lock(&midiinfo_mtx); - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->midiunit == unit) - break; - } - mtx_unlock(&midiinfo_mtx); - - return md; -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct with MDT_SYNTH. - */ -mididev_info * -get_mididev_synth_unit(int unit) -{ - mididev_info *md; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - mtx_lock(&midiinfo_mtx); - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->synthunit == unit) - break; - } - mtx_unlock(&midiinfo_mtx); - - return md; -} - -/* Create a new midi device info structure. */ -/* TODO: lock md, then exit. */ -mididev_info * -create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf) -{ - int unit; - mididev_info *md, *mdnew; - - /* XXX */ - if (!midiinfo_mtx_init) { - midiinfo_mtx_init = 1; - mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF); - TAILQ_INIT(&midi_info); - } - - /* As malloc(9) might block, allocate mididev_info now. */ - mdnew = malloc(sizeof(mididev_info), M_DEVBUF, M_WAITOK | M_ZERO); - if (mdnew == NULL) - return NULL; - bcopy(mdinf, mdnew, sizeof(mididev_info)); - bcopy(syninf, &mdnew->synth, sizeof(synthdev_info)); - midibuf_init(&mdnew->midi_dbuf_in); - midibuf_init(&mdnew->midi_dbuf_out); - midibuf_init(&mdnew->midi_dbuf_passthru); - mtx_init(&mdnew->flagqueue_mtx, "midflq", NULL, MTX_DEF); - mtx_init(&mdnew->synth.vc_mtx, "synsvc", NULL, MTX_DEF); - mtx_init(&mdnew->synth.status_mtx, "synsst", NULL, MTX_DEF); - - mtx_lock(&midiinfo_mtx); - - switch (type) { - case MDT_MIDI: - mdnew->midiunit = nmidi; - mdnew->synthunit = nmidi; - nmidi++; - break; - case MDT_SYNTH: - mdnew->midiunit = -1; - mdnew->synthunit = nsynth; - nsynth++; - break; - default: - mtx_unlock(&midiinfo_mtx); - midibuf_destroy(&mdnew->midi_dbuf_in); - midibuf_destroy(&mdnew->midi_dbuf_out); - midibuf_destroy(&mdnew->midi_dbuf_passthru); - mtx_destroy(&mdnew->flagqueue_mtx); - mtx_destroy(&mdnew->synth.vc_mtx); - mtx_destroy(&mdnew->synth.status_mtx); - free(mdnew, M_DEVBUF); - panic("unsupported device type"); - return NULL; - } - mdnew->mdtype = type; - - for (unit = 0 ; ; unit++) { - TAILQ_FOREACH(md, &midi_info, md_link) { - if (md->unit == unit) - break; - } - if (md == NULL) - break; - } - - mdnew->unit = unit; - mtx_lock(&mdnew->flagqueue_mtx); - TAILQ_INSERT_TAIL(&midi_info, mdnew, md_link); - - mtx_unlock(&midiinfo_mtx); - - return mdnew; -} - -/* Return the number of configured devices. */ -int -mididev_info_number(void) -{ - return nmidi + nsynth; -} - -/* Return the number of configured midi devices. */ -int -mididev_midi_number(void) -{ - return nmidi; -} - -/* Return the number of configured synth devices. */ -int -mididev_synth_number(void) -{ - return nsynth; -} - -/* - * 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 thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_open(i_dev, flags, mode, td); - break; - case MIDI_DEV_STATUS: - ret = midistat_open(i_dev, flags, mode, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiclose(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_close(i_dev, flags, mode, td); - break; - case MIDI_DEV_STATUS: - ret = midistat_close(i_dev, flags, mode, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiread(dev_t i_dev, struct uio * buf, int flag) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_read(i_dev, buf, flag); - break; - case MIDI_DEV_STATUS: - ret = midistat_read(i_dev, buf, flag); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiwrite(dev_t i_dev, struct uio * buf, int flag) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_write(i_dev, buf, flag); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_ioctl(i_dev, cmd, arg, mode, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -static int -midipoll(dev_t i_dev, int events, struct thread *td) -{ - int ret; - - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_MIDIN: - ret = midi_poll(i_dev, events, td); - break; - default: - ret = ENXIO; - break; - } - - return (ret); -} - -/* - * Followings are the generic methods in midi drivers. - */ - -int -midi_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int dev, unit, ret; - mididev_info *d; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_open: unit %d, flags 0x%x.\n", unit, flags)); - - if (d == NULL) - return (ENXIO); - - /* Mark this device busy. */ - mtx_lock(&d->flagqueue_mtx); - device_busy(d->dev); - if ((d->flags & MIDI_F_BUSY) != 0) { - mtx_unlock(&d->flagqueue_mtx); - printf("midi_open: unit %d is busy.\n", unit); - return (EBUSY); - } - d->fflags = flags; - d->flags |= MIDI_F_BUSY; - d->flags &= ~(MIDI_F_READING | MIDI_F_WRITING); - if ((d->fflags & O_NONBLOCK) != 0) - d->flags |= MIDI_F_NBIO; - - /* Init the queue. */ - if ((flags & FREAD) != 0) - midibuf_clear(&d->midi_dbuf_in); - if ((flags & FWRITE) != 0) { - midibuf_clear(&d->midi_dbuf_out); - midibuf_clear(&d->midi_dbuf_passthru); - } - - mtx_unlock(&d->flagqueue_mtx); - - if (d->open == NULL) - ret = 0; - else - ret = d->open(i_dev, flags, mode, td); - - mtx_lock(&d->flagqueue_mtx); - - /* Begin recording if nonblocking. */ - if ((d->flags & (MIDI_F_READING | MIDI_F_NBIO)) == MIDI_F_NBIO && (d->fflags & FREAD) != 0) - d->callback(d, MIDI_CB_START | MIDI_CB_RD); - - mtx_unlock(&d->flagqueue_mtx); - - MIDI_DEBUG(printf("midi_open: opened.\n")); - - return (ret); -} - -int -midi_close(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int dev, unit, ret; - mididev_info *d; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_close: unit %d.\n", unit)); - - if (d == NULL) - return (ENXIO); - - mtx_lock(&d->flagqueue_mtx); - - /* Stop recording and playing. */ - if ((d->flags & MIDI_F_READING) != 0) - d->callback(d, MIDI_CB_ABORT | MIDI_CB_RD); - if ((d->flags & MIDI_F_WRITING) != 0) - d->callback(d, MIDI_CB_ABORT | MIDI_CB_WR); - - /* Clear the queues. */ - if ((d->fflags & FREAD) != 0) - midibuf_clear(&d->midi_dbuf_in); - if ((d->fflags & FWRITE) != 0) { - midibuf_clear(&d->midi_dbuf_out); - midibuf_clear(&d->midi_dbuf_passthru); - } - - /* Stop playing and unmark this device busy. */ - d->flags &= ~MIDI_F_BUSY; - d->fflags = 0; - - device_unbusy(d->dev); - - mtx_unlock(&d->flagqueue_mtx); - - if (d->close == NULL) - ret = 0; - else - ret = d->close(i_dev, flags, mode, td); - - MIDI_DEBUG(printf("midi_close: closed.\n")); - - return (ret); -} - -int -midi_read(dev_t i_dev, struct uio * buf, int flag) -{ - int dev, unit, len, lenr, ret; - mididev_info *d ; - u_char *uiobuf; - - dev = minor(i_dev); - - d = get_mididev_info(i_dev, &unit); - MIDI_DEBUG(printf("midi_read: unit %d, resid %d.\n", unit, buf->uio_resid)); - - if (d == NULL) - return (ENXIO); - - ret = 0; - - len = buf->uio_resid; - lenr = 0; - - uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - if (uiobuf == NULL) - return (ENOMEM); - - mtx_lock(&d->flagqueue_mtx); - - /* 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 { - if ((d->flags & MIDI_F_NBIO) != 0 && len > d->midi_dbuf_in.rl) - len = d->midi_dbuf_in.rl; - ret = midibuf_seqread(&d->midi_dbuf_in, uiobuf, len, &lenr, - d->callback, d, MIDI_CB_START | MIDI_CB_RD, - &d->flagqueue_mtx); - } - - mtx_unlock(&d->flagqueue_mtx); - - if (lenr > 0) - ret = uiomove(uiobuf, lenr, buf); - - free(uiobuf, M_DEVBUF); - - MIDI_DEBUG(printf("midi_read: ret %d, resid %d.\n", ret, buf->uio_resid)); - - return (ret); -} - -int -midi_write(dev_t i_dev, struct uio * buf, int flag) -{ - int dev, unit, len, len2, lenw, ret; - mididev_info *d; - u_char *uiobuf; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_write: unit %d.\n", unit)); - - if (d == NULL) - return (ENXIO); - - ret = 0; - - len = buf->uio_resid; - lenw = 0; - - uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - if (uiobuf == NULL) - return (ENOMEM); - - ret = uiomove(uiobuf, len, buf); - if (ret != 0) { - free(uiobuf, M_DEVBUF); - return (ret); - } - - mtx_lock(&d->flagqueue_mtx); - - /* Have we got the data to write? */ - if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) { - /* Begin playing. */ - d->callback(d, MIDI_CB_START | MIDI_CB_WR); - ret = EAGAIN; - } else { - len2 = len; - if ((d->flags & MIDI_F_NBIO) != 0 && len2 > d->midi_dbuf_out.fl) - len2 = d->midi_dbuf_out.fl; - ret = midibuf_seqwrite(&d->midi_dbuf_out, uiobuf, len2, &lenw, - d->callback, d, MIDI_CB_START | MIDI_CB_WR, - &d->flagqueue_mtx); - } - - mtx_unlock(&d->flagqueue_mtx); - - free(uiobuf, M_DEVBUF); - buf->uio_resid = len - lenw; - - 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 thread *td) -{ - int ret = ENOSYS, dev, unit; - mididev_info *d; - struct snd_size *sndsize; - snd_sync_parm *sp; - - 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, td); - if (ret != ENOSYS) - return ret; - - /* - * pass control to the default ioctl handler. Set ret to 0 now. - */ - ret = 0; - - MIDI_DEBUG(printf("midi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - /* - * all routines are called with int. blocked. Make sure that - * ints are re-enabled when calling slow or blocking functions! - */ - switch(cmd) { - - /* - * we start with the new ioctl interface. - */ - case AIONWRITE: /* how many bytes can write ? */ - mtx_lock(&d->flagqueue_mtx); - *(int *)arg = d->midi_dbuf_out.fl; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: fl %d.\n", *(int *)arg)); - break; - - case AIOSSIZE: /* set the current blocksize */ - sndsize = (struct snd_size *)arg; - MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size)); - mtx_lock(&d->flagqueue_mtx); - if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) { - d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size; - d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size; - sndsize->play_size = d->midi_dbuf_out.blocksize; - sndsize->rec_size = d->midi_dbuf_in.blocksize; - d->flags &= ~MIDI_F_HAS_SIZE; - mtx_unlock(&d->flagqueue_mtx); - } - 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; - sndsize->play_size = d->midi_dbuf_out.blocksize; - sndsize->rec_size = d->midi_dbuf_in.blocksize; - d->flags |= MIDI_F_HAS_SIZE; - mtx_unlock(&d->flagqueue_mtx); - } - - ret = 0; - break; - - case AIOGSIZE: /* get the current blocksize */ - sndsize = (struct snd_size *)arg; - mtx_lock(&d->flagqueue_mtx); - sndsize->play_size = d->midi_dbuf_out.blocksize; - sndsize->rec_size = d->midi_dbuf_in.blocksize; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size)); - - ret = 0; - break; - - case AIOSTOP: - mtx_lock(&d->flagqueue_mtx); - 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 { - MIDI_DEBUG(printf("midi_ioctl: bad channel 0x%x.\n", *(int *)arg)); - *(int *)arg = 0 ; - } - mtx_unlock(&d->flagqueue_mtx); - break ; - - case AIOSYNC: - sp = (snd_sync_parm *)arg; - MIDI_DEBUG(printf("midi_ioctl: unimplemented, chan 0x%03lx pos %lu.\n", - sp->chan, - sp->pos)); - break; - /* - * here follow the standard ioctls (filio.h etc.) - */ - case FIONREAD: /* get # bytes to read */ - mtx_lock(&d->flagqueue_mtx); - *(int *)arg = d->midi_dbuf_in.rl; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: rl %d.\n", *(int *)arg)); - break; - - case FIOASYNC: /*set/clear async i/o */ - MIDI_DEBUG(printf("FIOASYNC\n")); - break; - - case FIONBIO: /* set/clear non-blocking i/o */ - mtx_lock(&d->flagqueue_mtx); - if (*(int *)arg == 0) - d->flags &= ~MIDI_F_NBIO ; - else - d->flags |= MIDI_F_NBIO ; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: arg %d.\n", *(int *)arg)); - break ; - - case MIOSPASSTHRU: /* set/clear passthru */ - mtx_lock(&d->flagqueue_mtx); - if (*(int *)arg == 0) - d->flags &= ~MIDI_F_PASSTHRU ; - else - d->flags |= MIDI_F_PASSTHRU ; - - /* Init the queue. */ - midibuf_clear(&d->midi_dbuf_passthru); - - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg)); - - /* FALLTHROUGH */ - case MIOGPASSTHRU: /* get passthru */ - mtx_lock(&d->flagqueue_mtx); - if ((d->flags & MIDI_F_PASSTHRU) != 0) - *(int *)arg = 1; - else - *(int *)arg = 0; - mtx_unlock(&d->flagqueue_mtx); - MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg)); - break; - - default: - MIDI_DEBUG(printf("midi_ioctl: default ioctl midi%d subdev %d fn 0x%08lx fail\n", - unit, dev & 0xf, cmd)); - ret = EINVAL; - break ; - } - return ret ; -} - -int -midi_poll(dev_t i_dev, int events, struct thread *td) -{ - int unit, dev, ret, lim; - mididev_info *d; - - dev = minor(i_dev); - d = get_mididev_info(i_dev, &unit); - - MIDI_DEBUG(printf("midi_poll: unit %d.\n", unit)); - - if (d == NULL) - return (ENXIO); - - ret = 0; - - mtx_lock(&d->flagqueue_mtx); - - /* 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(td, &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(td, &d->midi_dbuf_in.sel); - else - /* We can write now. */ - ret |= events & (POLLIN | POLLRDNORM); - } - - mtx_unlock(&d->flagqueue_mtx); - - return (ret); -} - -void -midi_intr(mididev_info *d) -{ - if (d->intr != NULL) - d->intr(d->intrarg, d); -} - -/* Flush the output queue. */ -#define MIDI_SYNC_TIMEOUT 1 -int -midi_sync(mididev_info *d) -{ - int i, rl; - - mtx_assert(&d->flagqueue_mtx, MA_OWNED); - - MIDI_DEBUG(printf("midi_sync: unit %d.\n", d->unit)); - - while (d->midi_dbuf_out.rl > 0) { - if ((d->flags & MIDI_F_WRITING) == 0) - d->callback(d, MIDI_CB_START | MIDI_CB_WR); - rl = d->midi_dbuf_out.rl; - i = cv_timedwait_sig(&d->midi_dbuf_out.cv_out, - &d->flagqueue_mtx, - (d->midi_dbuf_out.bufsize * 10 * hz / 38400) - + MIDI_SYNC_TIMEOUT * hz); - if (i == EINTR || i == ERESTART) { - if (i == EINTR) - d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); - return (i); - } - if (i == EWOULDBLOCK && rl == d->midi_dbuf_out.rl) { - /* A queue seems to be stuck up. Give up and clear the queue. */ - d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); - midibuf_clear(&d->midi_dbuf_out); - return (0); - } - } - - return 0; -} - -/* - * These handle the status message of the midi drivers. - */ - -int -midistat_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - 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 thread *td) -{ - 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 < mididev_info_number() ; i++) { - md = get_mididev_info_unit(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 len; - - len = min(uio->uio_resid, strlen(&buf[*ptr])); - if (len > 0) { - uiomove(&buf[*ptr], len, uio); - *ptr += len; - } - - return (0); -} - -char -*midi_cmdname(int cmd, midi_cmdtab *tab) -{ - while (tab->name != NULL) { - if (cmd == tab->cmd) - return (tab->name); - tab++; - } - - return ("unknown"); -} diff --git a/sys/dev/sound/midi/midi.h b/sys/dev/sound/midi/midi.h deleted file mode 100644 index 634d457f5c53..000000000000 --- a/sys/dev/sound/midi/midi.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * 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/lock.h> -#include <sys/sockio.h> -#include <sys/fcntl.h> -#include <sys/tty.h> -#include <sys/proc.h> -#include <sys/sysctl.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/resource.h> -#include <machine/bus_memio.h> -#include <machine/bus_pio.h> -#include <machine/bus.h> -#include <machine/clock.h> /* for DELAY */ -#include <sys/limits.h> -#include <sys/soundcard.h> -#include <sys/rman.h> -#include <sys/mman.h> -#include <sys/poll.h> -#include <sys/mutex.h> -#include <sys/condvar.h> - -#include <dev/sound/midi/miditypes.h> -#include <dev/sound/midi/midibuf.h> -#include <dev/sound/midi/midisynth.h> - -#define MIDI_CDEV_MAJOR 30 - -/*#define MIDI_OUTOFGIANT*/ - -/* - * The order of mutex lock (from the first to the last) - * - * 1. sequencer flags, queues, timer and device list - * 2. midi synth voice and channel - * 3. midi synth status - * 4. generic midi flags and queues - * 5. midi device - */ - -/* - * 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_ioctl_t *ioctl; - 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 */ - int midiunit; /* unit number for midi devices */ - int synthunit; /* unit number for synth devices */ - int mdtype; /* MDT_MIDI or MDT_SYNTH */ - 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. - */ - - struct mtx flagqueue_mtx; /* Mutex to protect flags and queues */ - - /* Queues */ - 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. - */ - - /* Flags */ - 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 nterrupts; /* 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]; - - /* The tailq entry of the next midi device. */ - TAILQ_ENTRY(_mididev_info) md_link; - - /* The tailq entry of the next midi device opened by a sequencer. */ - TAILQ_ENTRY(_mididev_info) md_linkseq; -} ; - -/* - * then ioctls and other stuff - */ - -#define NMIDI_MAX 16 /* 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) (udev2dev(makeudev((m), MIDIMKMINOR((u), (d))))) - -/* - * see if the device is configured - */ -#define MIDICONFED(x) ((x)->ioctl != NULL) - -/* - * finally, all default parameters - */ -#define MIDI_BUFFSIZE (1024) /* XXX */ - -#ifdef _KERNEL - -/* 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); - mididev_info *get_mididev_info_unit(int unit); - mididev_info *get_mididev_midi_unit(int unit); - mididev_info *get_mididev_synth_unit(int unit); - mididev_info *create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf); - int mididev_info_number(void); - int mididev_midi_number(void); - int mididev_synth_number(void); -#define MDT_MIDI (0) -#define MDT_SYNTH (1) - -/* 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 *); - -/* Sync output */ -int midi_sync(mididev_info *); - -struct _midi_cmdtab { - int cmd; - char * name; -}; -typedef struct _midi_cmdtab midi_cmdtab; - -char *midi_cmdname(int cmd, midi_cmdtab *tab); - -SYSCTL_DECL(_hw_midi); - -extern int midi_debug; -#define MIDI_DEBUG(x) \ - do { \ - if (midi_debug) { \ - (x); \ - } \ - } while(0) - -extern midi_cmdtab cmdtab_midiioctl[]; - -#endif /* _KERNEL */ - -/* - * Minor numbers for the midi driver. - */ - -#define MIDI_DEV_MIDIN 2 /* Raw midi access */ -#define MIDI_DEV_STATUS 15 /* /dev/midistat */ - -#endif /* _MIDI_H_ */ diff --git a/sys/dev/sound/midi/midibuf.c b/sys/dev/sound/midi/midibuf.c deleted file mode 100644 index f4444059ac8f..000000000000 --- a/sys/dev/sound/midi/midibuf.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * 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 <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 dequeuerawdata(midi_dbuf *dbuf, char *data, int len); -static void copyrawdata(midi_dbuf *dbuf, int offset, char *data, int len); -static void deleterawdata(midi_dbuf *dbuf, 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) { - dbuf->buf = malloc(MIDI_BUFFSIZE, M_DEVBUF, M_WAITOK | M_ZERO); - cv_init(&dbuf->cv_in, "midi queue in"); - cv_init(&dbuf->cv_out, "midi queue out"); - } - - return (midibuf_clear(dbuf)); -} - -int -midibuf_destroy(midi_dbuf *dbuf) -{ - if (dbuf->buf != NULL) { - free(dbuf->buf, M_DEVBUF); - cv_destroy(&dbuf->cv_in); - cv_destroy(&dbuf->cv_out); - } - - return (0); -} - -int -midibuf_clear(midi_dbuf *dbuf) -{ - 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 *lenw, midi_callback_t *cb, void *d, int reason, struct mtx *m) -{ - int i, lwrt; - - if (m != NULL) - mtx_assert(m, MA_OWNED); - - if (lenw == NULL) - return (EINVAL); - *lenw = 0; - - /* Is this a real queue? */ - if (dbuf == (midi_dbuf *)NULL) - return (EINVAL); - - /* 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); - - *lenw += lwrt; - len -= lwrt; - data += lwrt; - } - - if (cb != NULL) - (*cb)(d, reason); - - /* Have we got still more data to write? */ - if (len > 0) { - /* Sleep until we have enough space. */ - i = cv_wait_sig(&dbuf->cv_out, m); - if (i == EINTR || i == ERESTART) - return (i); - } - } - - return (0); -} - -int -midibuf_output_intr(midi_dbuf *dbuf, u_char *data, int len, int *leno) -{ - if (leno == NULL) - return (EINVAL); - *leno = 0; - - /* Is this a real queue? */ - if (dbuf == (midi_dbuf *)NULL) - return (EINVAL); - - /* Have we got any data in the queue? */ - *leno = DATA_AVAIL(dbuf); - if (*leno == 0) - return (EAGAIN); - - /* Dequeue the data. */ - if (*leno > len) - *leno = len; - dequeuerawdata(dbuf, data, *leno); - - return (0); -} - -int -midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len, int *leni) -{ - if (leni == NULL) - return (EINVAL); - *leni = 0; - - /* Is this a real queue? */ - if (dbuf == (midi_dbuf *)NULL) - return (EINVAL); - - /* 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); - *leni = len; - - return (0); -} - -/* The sequencer calls this function to dequeue data. */ -int -midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len, int *lenr, midi_callback_t *cb, void *d, int reason, struct mtx *m) -{ - int i, lrd; - - if (m != NULL) - mtx_assert(m, MA_OWNED); - - if (lenr == NULL) - return (EINVAL); - *lenr = 0; - - /* Is this a real queue? */ - if (dbuf == (midi_dbuf *)NULL) - return (EINVAL); - - /* Write down every single byte. */ - while (len > 0) { - if (cb != NULL) - (*cb)(d, reason); - - /* Have we got data to read? */ - if ((lrd = DATA_AVAIL(dbuf)) == 0) { - /* Sleep until we have data ready to read. */ - i = cv_wait_sig(&dbuf->cv_in, m); - if (i == EINTR || i == ERESTART) - return (i); - /* 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); - - *lenr += lrd; - len -= lrd; - data += lrd; - } - } - - return (0); -} - -/* The sequencer calls this function to copy data without dequeueing. */ -int -midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len, int *lenc, midi_callback_t *cb, void *d, int reason, struct mtx *m) -{ - int i, lrd; - - if (m != NULL) - mtx_assert(m, MA_OWNED); - - if (lenc == NULL) - return (EINVAL); - *lenc = 0; - - /* Is this a real queue? */ - if (dbuf == (midi_dbuf *)NULL) - return (EINVAL); - - /* Write down every single byte. */ - while (len > 0) { - if (cb != NULL) - (*cb)(d, reason); - - /* Have we got data to read? */ - if ((lrd = DATA_AVAIL(dbuf)) == 0) { - /* Sleep until we have data ready to read. */ - i = cv_wait_sig(&dbuf->cv_in, m); - if (i == EINTR || i == ERESTART) - return (i); - /* 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, *lenc, data, lrd); - - *lenc += lrd; - len -= lrd; - data += lrd; - } - } - - return (0); -} - -/* - * The sequencer calls this function to delete the data - * that the sequencer has already read. - */ -int -midibuf_seqdelete(midi_dbuf *dbuf, int len, int *lenr, midi_callback_t *cb, void *d, int reason, struct mtx *m) -{ - int i, lrd; - - if (m != NULL) - mtx_assert(m, MA_OWNED); - - if (lenr == NULL) - return (EINVAL); - *lenr = 0; - - /* Is this a real queue? */ - if (dbuf == (midi_dbuf *)NULL) - return (EINVAL); - - /* Write down every single byte. */ - while (len > 0) { - if (cb != NULL) - (*cb)(d, reason); - - /* Have we got data to read? */ - if ((lrd = DATA_AVAIL(dbuf)) == 0) { - /* Sleep until we have data ready to read. */ - i = cv_wait_sig(&dbuf->cv_in, m); - if (i == EINTR || i == ERESTART) - return (i); - /* 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. Delete the data. */ - deleterawdata(dbuf, lrd); - - *lenr += lrd; - len -= lrd; - } - } - - return (0); -} - -/* - * 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. */ - bcopy(data, dbuf->buf + dbuf->fp, dbuf->bufsize - dbuf->fp); - bcopy(data + dbuf->bufsize - dbuf->fp, dbuf->buf, len - (dbuf->bufsize - dbuf->fp)); - } else - /* The new data do not wrap, once is enough. */ - bcopy(data, dbuf->buf + dbuf->fp, 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. */ - cv_broadcast(&dbuf->cv_in); - if (SEL_WAITING(&dbuf->sel) && dbuf->rl >= dbuf->blocksize) - selwakeuppri(&dbuf->sel, PRIBIO); -} - -static void -dequeuerawdata(midi_dbuf *dbuf, char *data, int len) -{ - /* Copy the data. */ - copyrawdata(dbuf, 0, data, len); - - /* Delete the data. */ - deleterawdata(dbuf, len); -} - -static void -copyrawdata(midi_dbuf *dbuf, int offset, char *data, int len) -{ - int rp; - - rp = (dbuf->rp + offset) % dbuf->bufsize; - - /* dbuf->rp might wrap around dbuf->bufsize. */ - if (dbuf->bufsize - rp < len) { - /* The data to be read wraps, copy them twice. */ - bcopy(dbuf->buf + rp, data, dbuf->bufsize - rp); - bcopy(dbuf->buf, data + dbuf->bufsize - rp, len - (dbuf->bufsize - rp)); - } else - /* The new data do not wrap, once is enough. */ - bcopy(dbuf->buf + rp, data, len); -} - -static void -deleterawdata(midi_dbuf *dbuf, int 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. */ - cv_broadcast(&dbuf->cv_out); - if (SEL_WAITING(&dbuf->sel) && dbuf->fl >= dbuf->blocksize) - selwakeuppri(&dbuf->sel, PRIBIO); -} diff --git a/sys/dev/sound/midi/midibuf.h b/sys/dev/sound/midi/midibuf.h deleted file mode 100644 index a25c1cc24bdf..000000000000 --- a/sys/dev/sound/midi/midibuf.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 */ - struct cv cv_in, cv_out; /* condvars */ - 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_destroy(midi_dbuf *dbuf); -int midibuf_clear(midi_dbuf *dbuf); -int midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len, int *lenw, midi_callback_t *cb, void *d, int reason, struct mtx *m); -int midibuf_output_intr(midi_dbuf *dbuf, u_char *data, int len, int *leno); -int midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len, int *leni); -int midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len, int *lenr, midi_callback_t *cb, void *d, int reason, struct mtx *m); -int midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len, int *lenc, midi_callback_t *cb, void *d, int reason, struct mtx *m); -int midibuf_seqdelete(midi_dbuf *dbuf, int len, int *lend, midi_callback_t *cb, void *d, int reason, struct mtx *m); diff --git a/sys/dev/sound/midi/midisynth.c b/sys/dev/sound/midi/midisynth.c deleted file mode 100644 index d3708332e58b..000000000000 --- a/sys/dev/sound/midi/midisynth.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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 <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 sequencer.c. - */ - -static int -synth_killnote(mididev_info *md, int chn, int note, int vel) -{ - int unit, lenw; - 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); - - 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); - - return (md->synth.writeraw(md, c, 3, &lenw, 1)); -} - -static int -synth_setinstr(mididev_info *md, int chn, int instr) -{ - int unit, lenw; - 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; - - return (md->synth.writeraw(md, c, 3, &lenw, 1)); -} - -static int -synth_startnote(mididev_info *md, int chn, int note, int vel) -{ - int unit, lenw; - 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); - - 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); - - return (md->synth.writeraw(md, c, 3, &lenw, 1)); -} - -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, lenw; - 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, &lenw, 0); - return (0); - } - first_byte = 0; - } - - if (!eox_seen) { - c[0] = 0xf7; - md->synth.writeraw(md, c, 1, &lenw, 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, lenw; - 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); - - c[0] = 0xd0 | (chn & 0x0f); /* Channel Pressure. */ - c[1] = (u_char)press; - if (synth_prefixcmd(md, c[0])) - return (0); - - return (md->synth.writeraw(md, c, 2, &lenw, 1)); -} - -static int -synth_controller(mididev_info *md, int chn, int ctrlnum, int val) -{ - int unit, lenw; - 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); - - c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ - c[1] = (u_char)ctrlnum; - if (synth_prefixcmd(md, c[0])) - return (0); - - return (md->synth.writeraw(md, c, 3, &lenw, 1)); -} - -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, lenw; - 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); - - 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); - - return (md->synth.writeraw(md, c, 3, &lenw, 1)); -} - -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, lenw; - synthdev_info *sd; - u_char c[len]; - - unit = md->unit; - sd = &md->synth; - - mtx_lock(&sd->status_mtx); - for (i = 0 ; i < len ; i++) { - switch (sysex[i]) { - case 0xf0: - /* Sysex begins. */ - if (synth_prefixcmd(md, 0xf0)) { - mtx_unlock(&sd->status_mtx); - return (0); - } - sd->sysex_state = 1; - break; - case 0xf7: - /* Sysex ends. */ - if (!sd->sysex_state) { - mtx_unlock(&sd->status_mtx); - return (0); - } - sd->sysex_state = 0; - break; - default: - if (!sd->sysex_state) { - mtx_unlock(&sd->status_mtx); - 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; - } - mtx_unlock(&sd->status_mtx); - - return (md->synth.writeraw(md, c, i, &lenw, 1)); -} - -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 *lenr, int nonblock) -{ - int unit, ret; - - if (md == NULL) - return (ENXIO); - if (lenr == NULL) - return (EINVAL); - - *lenr = 0; - unit = md->unit; - - if ((md->fflags & FREAD) == 0) { - MIDI_DEBUG(printf("synth_readraw: unit %d is not for reading.\n", unit)); - return (EIO); - } - - mtx_lock(&md->flagqueue_mtx); - - /* Begin recording. */ - if ((md->flags & MIDI_F_READING) == 0) - 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) { - mtx_unlock(&md->flagqueue_mtx); - return (EAGAIN); - } - } - - ret = midibuf_seqread(&md->midi_dbuf_in, buf, len, lenr, - md->callback, md, MIDI_CB_START | MIDI_CB_RD, - &md->flagqueue_mtx); - - mtx_unlock(&md->flagqueue_mtx); - - return (ret); -} - -static int -synth_writeraw(mididev_info *md, u_char *buf, int len, int *lenw, int nonblock) -{ - int unit, ret; - - if (md == NULL) - return (ENXIO); - if (lenw == NULL) - return (EINVAL); - - *lenw = 0; - unit = md->unit; - - if ((md->fflags & FWRITE) == 0) { - MIDI_DEBUG(printf("synth_writeraw: unit %d is not for writing.\n", unit)); - return (EIO); - } - - /* For nonblocking, have we got enough space to write? */ - mtx_lock(&md->flagqueue_mtx); - if (nonblock && md->midi_dbuf_out.fl < len) { - /* Begin playing. */ - md->callback(md, MIDI_CB_START | MIDI_CB_WR); - mtx_unlock(&md->flagqueue_mtx); - return (EAGAIN); - } - - ret = midibuf_seqwrite(&md->midi_dbuf_out, buf, len, lenw, - md->callback, md, MIDI_CB_START | MIDI_CB_WR, - &md->flagqueue_mtx); - - if (ret == 0) - /* Begin playing. */ - md->callback(md, MIDI_CB_START | MIDI_CB_WR); - - mtx_unlock(&md->flagqueue_mtx); - - return (ret); -} - -/* - * The functions below here are the libraries for the above ones. - */ - -static int -synth_leavesysex(mididev_info *md) -{ - int unit, lenw; - synthdev_info *sd; - u_char c; - - unit = md->unit; - sd = &md->synth; - - mtx_lock(&sd->status_mtx); - if (!sd->sysex_state) { - mtx_unlock(&sd->status_mtx); - return (0); - } - - sd->sysex_state = 0; - mtx_unlock(&sd->status_mtx); - c = 0xf7; - - return (md->synth.writeraw(md, &c, sizeof(c), &lenw, 1)); -} diff --git a/sys/dev/sound/midi/midisynth.h b/sys/dev/sound/midi/midisynth.h deleted file mode 100644 index 356be897cb66..000000000000 --- a/sys/dev/sound/midi/midisynth.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 *lenr, int nonblock); -typedef int (mdsy_writeraw_t)(mididev_info *md, u_char *buf, int len, int *lenw, int nonblock); - -/* - * The order of mutex lock (from the first to the last) - * - * 1. sequencer flags, queues, timer and devlice list - * 2. midi synth voice and channel - * 3. midi synth status - * 4. generic midi flags and queues - * 5. midi device - */ - -/* 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; - - /* Voice and channel */ - struct mtx vc_mtx; /* Mutex to protect voice and channel. */ - struct voice_alloc_info alloc; /* Voice allocation. */ - struct channel_info chn_info[16]; /* Channel information. */ - - /* Status */ - struct mtx status_mtx; /* Mutex to protect status. */ - int sysex_state; /* State of sysex transmission. */ -}; -typedef struct _synthdev_info synthdev_info; diff --git a/sys/dev/sound/midi/miditypes.h b/sys/dev/sound/midi/miditypes.h deleted file mode 100644 index 065734252d03..000000000000 --- a/sys/dev/sound/midi/miditypes.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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)(void *d, int reason); -typedef void (midi_intr_t)(void *p, mididev_info *md); diff --git a/sys/dev/sound/midi/sequencer.c b/sys/dev/sound/midi/sequencer.c deleted file mode 100644 index bea493616d40..000000000000 --- a/sys/dev/sound/midi/sequencer.c +++ /dev/null @@ -1,2603 +0,0 @@ -/* - * The sequencer personality manager. - * - * 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 newmidi sequencer driver. This driver handles io against - * /dev/sequencer, midi input and output event queues and event transmittion - * to and from a midi device or synthesizer. - */ - -#include <dev/sound/midi/midi.h> -#include <dev/sound/midi/sequencer.h> - -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - synthesizer and MIDI output) */ -#define SND_DEV_MIDIN 2 /* Raw midi access */ -#define SND_DEV_MUSIC 8 /* /dev/music, level 2 interface */ - -#define MIDIDEV_MODE 0x2000 - -/* Length of a sequencer event. */ -#define EV_SZ 8 -#define IEV_SZ 8 - -/* Lookup modes */ -#define LOOKUP_EXIST (0) -#define LOOKUP_OPEN (1) -#define LOOKUP_CLOSE (2) - -/* - * These functions goes into seq_op_desc to get called - * from sound.c. - */ - -static midi_intr_t seq_intr; -static midi_callback_t seq_callback; - -/* These are the entries to the sequencer driver. */ -static d_open_t seq_open; -static d_close_t seq_close; -static d_ioctl_t seq_ioctl; -static d_read_t seq_read; -static d_write_t seq_write; -static d_poll_t seq_poll; - -/* - * This is the device descriptor for the midi sequencer. - */ -seqdev_info seq_op_desc = { - "midi sequencer", - - 0, - - seq_open, - seq_close, - seq_read, - seq_write, - seq_ioctl, - seq_poll, - - seq_callback, - - SEQ_BUFFSIZE, /* Queue Length */ - - 0, /* XXX This is not an *audio* device! */ -}; - - -/* Here is the parameter structure per a device. */ -struct seq_softc { - seqdev_info *devinfo; /* sequencer device information */ - - /* Flags (protected by flag_mtx of mididev_info) */ - int fflags; /* Access mode */ - int queueout_pending; /* Pending for the output queue */ - int seq_mode; /* Sequencer mode */ - - /* Timer counters */ - u_long seq_time; /* The beggining time of this sequence */ - u_long prev_event_time; /* The time of the previous event output */ - u_long prev_input_time; /* The time of the previous event input */ - u_long prev_wakeup_time; /* The time of the previous wakeup */ - struct callout timeout_ch; /* Timer callout handler */ - long timer_current; /* Current timer value */ - int timer_running; /* State of timer */ - int pending_timer; /* Timer change operation */ - int pre_event_timeout; /* Time to wait event input */ - - /* Devices */ - TAILQ_HEAD(,_mididev_info) midi_open; /* Midi devices opened by this sequencer. */ - timerdev_info *timer; /* A timer device for /dev/music */ - - /* - * XXX not sure to which category these belong. - * (and some might be no-op) - */ - int output_threshould; /* Sequence output threshould */ - snd_sync_parm sync_parm; /* AIOSYNC parameter set */ - struct thread *sync_thread; /* AIOSYNCing thread */ -}; - -typedef struct seq_softc *sc_p; - -static d_open_t seqopen; -static d_close_t seqclose; -static d_ioctl_t seqioctl; -static d_read_t seqread; -static d_write_t seqwrite; -static d_poll_t seqpoll; - -#define CDEV_MAJOR SEQ_CDEV_MAJOR -static struct cdevsw seq_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = seqopen, - .d_close = seqclose, - .d_read = seqread, - .d_write = seqwrite, - .d_ioctl = seqioctl, - .d_poll = seqpoll, - .d_name = "midi", /* XXX */ - .d_maj = CDEV_MAJOR, -}; - - -static TAILQ_HEAD(,_seqdev_info) seq_info; -/* Mutex to protect seq_info and nseq. */ -static struct mtx seqinfo_mtx; -/* total number of sequencers */ -static u_long nseq; -static dev_t seq_alias = NODEV; -static dev_t music_alias = NODEV; - -SYSCTL_NODE(_hw_midi, OID_AUTO, seq, CTLFLAG_RD, 0, "Midi sequencer"); - -int seq_debug; -SYSCTL_INT(_hw_midi_seq, OID_AUTO, debug, CTLFLAG_RW, &seq_debug, 0, ""); - -static midi_cmdtab cmdtab_seqevent[] = { - {SEQ_NOTEOFF, "SEQ_NOTEOFF"}, - {SEQ_NOTEON, "SEQ_NOTEON"}, - {SEQ_WAIT, "SEQ_WAIT"}, - {SEQ_PGMCHANGE, "SEQ_PGMCHANGE"}, - {SEQ_SYNCTIMER, "SEQ_SYNCTIMER"}, - {SEQ_MIDIPUTC, "SEQ_MIDIPUTC"}, - {SEQ_DRUMON, "SEQ_DRUMON"}, - {SEQ_DRUMOFF, "SEQ_DRUMOFF"}, - {SEQ_ECHO, "SEQ_ECHO"}, - {SEQ_AFTERTOUCH, "SEQ_AFTERTOUCH"}, - {SEQ_CONTROLLER, "SEQ_CONTROLLER"}, - {SEQ_BALANCE, "SEQ_BALANCE"}, - {SEQ_VOLMODE, "SEQ_VOLMODE"}, - {SEQ_FULLSIZE, "SEQ_FULLSIZE"}, - {SEQ_PRIVATE, "SEQ_PRIVATE"}, - {SEQ_EXTENDED, "SEQ_EXTENDED"}, - {EV_SEQ_LOCAL, "EV_SEQ_LOCAL"}, - {EV_TIMING, "EV_TIMING"}, - {EV_CHN_COMMON, "EV_CHN_COMMON"}, - {EV_CHN_VOICE, "EV_CHN_VOICE"}, - {EV_SYSEX, "EV_SYSEX"}, - {-1, NULL}, -}; - -midi_cmdtab cmdtab_seqioctl[] = { - {SNDCTL_SEQ_RESET, "SNDCTL_SEQ_RESET"}, - {SNDCTL_SEQ_SYNC, "SNDCTL_SEQ_SYNC"}, - {SNDCTL_SYNTH_INFO, "SNDCTL_SYNTH_INFO"}, - {SNDCTL_SEQ_CTRLRATE, "SNDCTL_SEQ_CTRLRATE"}, - {SNDCTL_SEQ_GETOUTCOUNT, "SNDCTL_SEQ_GETOUTCOUNT"}, - {SNDCTL_SEQ_GETINCOUNT, "SNDCTL_SEQ_GETINCOUNT"}, - {SNDCTL_SEQ_PERCMODE, "SNDCTL_SEQ_PERCMODE"}, - {SNDCTL_FM_LOAD_INSTR, "SNDCTL_FM_LOAD_INSTR"}, - {SNDCTL_SEQ_TESTMIDI, "SNDCTL_SEQ_TESTMIDI"}, - {SNDCTL_SEQ_RESETSAMPLES, "SNDCTL_SEQ_RESETSAMPLES"}, - {SNDCTL_SEQ_NRSYNTHS, "SNDCTL_SEQ_NRSYNTHS"}, - {SNDCTL_SEQ_NRMIDIS, "SNDCTL_SEQ_NRMIDIS"}, - {SNDCTL_MIDI_INFO, "SNDCTL_MIDI_INFO"}, - {SNDCTL_SEQ_THRESHOLD, "SNDCTL_SEQ_THRESHOLD"}, - {SNDCTL_SYNTH_MEMAVL, "SNDCTL_SYNTH_MEMAVL"}, - {SNDCTL_FM_4OP_ENABLE, "SNDCTL_FM_4OP_ENABLE"}, - {SNDCTL_PMGR_ACCESS, "SNDCTL_PMGR_ACCESS"}, - {SNDCTL_SEQ_PANIC, "SNDCTL_SEQ_PANIC"}, - {SNDCTL_SEQ_OUTOFBAND, "SNDCTL_SEQ_OUTOFBAND"}, - {SNDCTL_TMR_TIMEBASE, "SNDCTL_TMR_TIMEBASE"}, - {SNDCTL_TMR_START, "SNDCTL_TMR_START"}, - {SNDCTL_TMR_STOP, "SNDCTL_TMR_STOP"}, - {SNDCTL_TMR_CONTINUE, "SNDCTL_TMR_CONTINUE"}, - {SNDCTL_TMR_TEMPO, "SNDCTL_TMR_TEMPO"}, - {SNDCTL_TMR_SOURCE, "SNDCTL_TMR_SOURCE"}, - {SNDCTL_TMR_METRONOME, "SNDCTL_TMR_METRONOME"}, - {SNDCTL_TMR_SELECT, "SNDCTL_TMR_SELECT"}, - {SNDCTL_MIDI_PRETIME, "SNDCTL_MIDI_PRETIME"}, - {AIONWRITE, "AIONWRITE"}, - {AIOGSIZE, "AIOGSIZE"}, - {AIOSSIZE, "AIOSSIZE"}, - {AIOGFMT, "AIOGFMT"}, - {AIOSFMT, "AIOSFMT"}, - {AIOGMIX, "AIOGMIX"}, - {AIOSMIX, "AIOSMIX"}, - {AIOSTOP, "AIOSTOP"}, - {AIOSYNC, "AIOSYNC"}, - {AIOGCAP, "AIOGCAP"}, - {-1, NULL}, -}; - -midi_cmdtab cmdtab_timer[] = { - {TMR_WAIT_REL, "TMR_WAIT_REL"}, - {TMR_WAIT_ABS, "TMR_WAIT_ABS"}, - {TMR_STOP, "TMR_STOP"}, - {TMR_START, "TMR_START"}, - {TMR_CONTINUE, "TMR_CONTINUE"}, - {TMR_TEMPO, "TMR_TEMPO"}, - {TMR_ECHO, "TMR_ECHO"}, - {TMR_CLOCK, "TMR_CLOCK"}, - {TMR_SPP, "TMR_SPP"}, - {TMR_TIMESIG, "TMR_TIMESIG"}, - {-1, NULL}, -}; - -static midi_cmdtab cmdtab_seqcv[] = { - {MIDI_NOTEOFF, "MIDI_NOTEOFF"}, - {MIDI_NOTEON, "MIDI_NOTEON"}, - {MIDI_KEY_PRESSURE, "MIDI_KEY_PRESSURE"}, - {-1, NULL}, -}; - -static midi_cmdtab cmdtab_seqccmn[] = { - {MIDI_CTL_CHANGE, "MIDI_CTL_CHANGE"}, - {MIDI_PGM_CHANGE, "MIDI_PGM_CHANGE"}, - {MIDI_CHN_PRESSURE, "MIDI_CHN_PRESSURE"}, - {MIDI_PITCH_BEND, "MIDI_PITCH_BEND"}, - {MIDI_SYSTEM_PREFIX, "MIDI_SYSTEM_PREFIX"}, - {-1, NULL}, -}; - - -/* The followings are the local function. */ -static int seq_init(void); -static int seq_initunit(int unit); -static int seq_queue(sc_p scp, u_char *note); -static void seq_startplay(sc_p scp); -static int seq_playevent(sc_p scp, u_char *event); -static u_long seq_gettime(void); -static int seq_requesttimer(sc_p scp, int delay); -static void seq_stoptimer(sc_p scp); -static void seq_midiinput(sc_p scp, mididev_info *md); -static int seq_extended(sc_p scp, u_char *event); -static int seq_chnvoice(sc_p scp, u_char *event); -static int seq_findvoice(mididev_info *md, int chn, int note) __unused; -static int seq_allocvoice(sc_p scp, mididev_info *md, int chn, int note) __unused; -static int seq_chncommon(sc_p scp, u_char *event); -static int seq_timing(sc_p scp, u_char *event); -static int seq_local(sc_p scp, u_char *event); -static int seq_sysex(sc_p scp, u_char *event); -static int seq_reset(sc_p scp); -static int seq_openmidi(sc_p scp, mididev_info *md, int flags, int mode, struct thread *p); -static int seq_closemidi(sc_p scp, mididev_info *md, int flags, int mode, struct thread *p); -static void seq_panic(sc_p scp); -static int seq_sync(sc_p scp); - -static seqdev_info *get_seqdev_info(dev_t i_dev, int *unit); -static seqdev_info *get_seqdev_info_unit(int unit); -static seqdev_info *create_seqdev_info_unit(int unit, seqdev_info *seq); -static int lookup_mididev(sc_p scp, int unit, int mode, mididev_info **mdp); -static int lookup_mididev_midi(sc_p scp, int unit, int mode, mididev_info **mdp); -static void seq_clone(void *arg, char *name, int namelen, dev_t *dev); - -/* - * 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 -seq_init(void) -{ - SEQ_DEBUG(printf("seq: initing.\n")); - - mtx_init(&seqinfo_mtx, "seqinf", NULL, MTX_DEF); - TAILQ_INIT(&seq_info); - - seq_initunit(0); - EVENTHANDLER_REGISTER(dev_clone, seq_clone, 0, 1000); - - SEQ_DEBUG(printf("seq: inited.\n")); - - return (0); -} - -static int -seq_initunit(int unit) -{ - sc_p scp; - seqdev_info *devinfo; - dev_t seqdev, musicdev; - - /* Allocate the softc. */ - scp = malloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO); - if (scp == (sc_p)NULL) { - printf("seq_initunit: unit %d, softc allocation failed.\n", unit); - return (1); - } - - /* Fill the softc and the seq_info for this unit. */ - scp->seq_time = seq_gettime(); - scp->prev_event_time = 0; - scp->prev_input_time = 0; - scp->prev_wakeup_time = scp->seq_time; -#if defined(MIDI_OUTOFGIANT) - callout_init(&scp->timeout_ch, 1); -#else - callout_init(&scp->timeout_ch, 0); -#endif /* MIDI_OUTOFGIANT */ - scp->timer_current = 0; - scp->timer_running = 0; - scp->queueout_pending = 0; - TAILQ_INIT(&scp->midi_open); - scp->pending_timer = -1; - - scp->devinfo = devinfo = create_seqdev_info_unit(unit, &seq_op_desc); - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = EV_SZ; - devinfo->softc = scp; - devinfo->flags = 0; - mtx_unlock(&devinfo->flagqueue_mtx); - - seqdev = make_dev(&seq_cdevsw, MIDIMKMINOR(unit, SND_DEV_SEQ), - UID_ROOT, GID_WHEEL, 0666, "sequencer%d", unit); - musicdev = make_dev(&seq_cdevsw, MIDIMKMINOR(unit, SND_DEV_MUSIC), - UID_ROOT, GID_WHEEL, 0666, "music%d", unit); - - mtx_lock(&seqinfo_mtx); - if (seq_alias != NODEV) { - destroy_dev(seq_alias); - seq_alias = NODEV; - } - seq_alias = make_dev_alias(seqdev, "sequencer"); - if (music_alias != NODEV) { - destroy_dev(music_alias); - music_alias = NODEV; - } - music_alias = make_dev_alias(musicdev, "music"); - mtx_unlock(&seqinfo_mtx); - - if (timerdev_install() != 0) - printf("seq_initunit: timerdev_install failed.\n"); - - return (0); -} - -int -seq_open(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int unit; - sc_p scp; - seqdev_info *sd; - - unit = MIDIUNIT(i_dev); - - SEQ_DEBUG(printf("seq_open: unit %d, flags 0x%x.\n", unit, flags)); - - if (unit >= NSEQ_MAX) { - SEQ_DEBUG(printf("seq_open: unit %d does not exist.\n", unit)); - return (ENXIO); - } - - sd = get_seqdev_info(i_dev, &unit); - if (sd == NULL) { - SEQ_DEBUG(printf("seq_open: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = sd->softc; - - /* Mark this device busy. */ - mtx_lock(&sd->flagqueue_mtx); - if ((sd->flags & SEQ_F_BUSY) != 0) { - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_open: unit %d is busy.\n", unit)); - return (EBUSY); - } - scp->fflags = flags; - sd->flags |= SEQ_F_BUSY; - sd->flags &= ~(SEQ_F_READING | SEQ_F_WRITING); - if ((scp->fflags & O_NONBLOCK) != 0) - sd->flags |= SEQ_F_NBIO; - scp->seq_mode = MIDIDEV(i_dev); - - /* Init the queue. */ - midibuf_clear(&sd->midi_dbuf_in); - midibuf_clear(&sd->midi_dbuf_out); - - /* Init timestamp. */ - scp->seq_time = seq_gettime(); - scp->prev_event_time = 0; - scp->prev_input_time = 0; - scp->prev_wakeup_time = scp->seq_time; - - if (scp->pending_timer != -1) { - scp->timer = get_timerdev_info_unit(scp->pending_timer); - scp->pending_timer = -1; - } - if (scp->timer == NULL) - scp->timer = get_timerdev_info(); - if (scp->timer != NULL) { - scp->timer->seq = scp; - mtx_unlock(&scp->timer->mtx); - } else if (scp->seq_mode == SND_DEV_MUSIC) { - mtx_unlock(&sd->flagqueue_mtx); - printf("seq_open: no timer available.\n"); - sd->flags &= ~SEQ_F_BUSY; - return (ENXIO); - } - - if (scp->seq_mode == SND_DEV_MUSIC) - scp->timer->open(scp->timer, flags, mode, td); - - /* Begin recording if nonblocking. */ - if ((sd->flags & (SEQ_F_READING | SEQ_F_NBIO)) == SEQ_F_NBIO && (scp->fflags & FREAD) != 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_RD); - - mtx_unlock(&sd->flagqueue_mtx); - - SEQ_DEBUG(printf("seq_open: opened, mode %d.\n", scp->seq_mode == SND_DEV_MUSIC ? 2 : 1)); - - return (0); -} - -int -seq_close(dev_t i_dev, int flags, int mode, struct thread *td) -{ - int unit; - sc_p scp; - seqdev_info *sd; - mididev_info *md; - timerdev_info *tmd; - - unit = MIDIUNIT(i_dev); - - SEQ_DEBUG(printf("seq_close: unit %d.\n", unit)); - - if (unit >= NSEQ_MAX) { - SEQ_DEBUG(printf("seq_close: unit %d does not exist.\n", unit)); - return (ENXIO); - } - - sd = get_seqdev_info(i_dev, &unit); - if (sd == NULL) { - SEQ_DEBUG(printf("seq_close: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = sd->softc; - - mtx_lock(&sd->flagqueue_mtx); - - if (!(sd->flags & MIDI_F_NBIO)) - seq_sync(scp); - - /* Stop the timer. */ - seq_stoptimer(scp); - - /* Reset the sequencer. */ - seq_reset(scp); - seq_sync(scp); - - /* Clean up the midi device. */ - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) - lookup_mididev(scp, md->unit, LOOKUP_CLOSE, NULL); - - /* Stop playing and unmark this device busy. */ - sd->flags &= ~(SEQ_F_BUSY | SEQ_F_READING | SEQ_F_WRITING | SEQ_F_INSYNC); - - if (scp->seq_mode == SND_DEV_MUSIC) - scp->timer->close(scp->timer, flags, mode, td); - - if (scp->timer != NULL) { - tmd = scp->timer; - mtx_lock(&tmd->mtx); - scp->timer = NULL; - tmd->seq = NULL; - mtx_unlock(&tmd->mtx); - } - - mtx_unlock(&sd->flagqueue_mtx); - - SEQ_DEBUG(printf("seq_close: closed.\n")); - - return (0); -} - -int -seq_read(dev_t i_dev, struct uio *buf, int flag) -{ - int unit, ret, len, lenr; - sc_p scp; - seqdev_info *sd; - u_char *uiobuf; - - unit = MIDIUNIT(i_dev); - - SEQ_DEBUG(printf("seq_read: unit %d, resid %d.\n", unit, buf->uio_resid)); - - if (unit >= NSEQ_MAX) { - SEQ_DEBUG(printf("seq_read: unit %d does not exist.\n", unit)); - return (ENXIO); - } - - sd = get_seqdev_info(i_dev, &unit); - if (sd == NULL) { - SEQ_DEBUG(printf("seq_read: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = sd->softc; - if ((scp->fflags & FREAD) == 0) { - SEQ_DEBUG(printf("seq_read: unit %d is not for reading.\n", unit)); - return (EIO); - } - - len = buf->uio_resid; - lenr = 0; - - uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - if (uiobuf == NULL) - return (ENOMEM); - - mtx_lock(&sd->flagqueue_mtx); - - /* Begin recording. */ - if ((sd->flags & SEQ_F_READING) == 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_RD); - - /* Have we got the data to read? */ - if ((sd->flags & SEQ_F_NBIO) != 0 && sd->midi_dbuf_in.rl == 0) - ret = EAGAIN; - else { - if ((sd->flags & SEQ_F_NBIO) != 0 && len > sd->midi_dbuf_in.rl) - len = sd->midi_dbuf_in.rl; - ret = midibuf_seqread(&sd->midi_dbuf_in, uiobuf, len, &lenr, - sd->callback, sd, SEQ_CB_START | SEQ_CB_RD, - &sd->flagqueue_mtx); - } - - mtx_unlock(&sd->flagqueue_mtx); - - if (ret == 0 && lenr > 0) - ret = uiomove(uiobuf, lenr, buf); - - free(uiobuf, M_DEVBUF); - - SEQ_DEBUG(printf("seq_read: ret %d, resid %d.\n", ret, buf->uio_resid)); - - return (ret); -} - -int -seq_write(dev_t i_dev, struct uio *buf, int flag) -{ - u_char event[EV_SZ], ev_code; - int unit, count, countorg, midiunit, ev_size, p, ret; - sc_p scp; - seqdev_info *sd; - mididev_info *md; - - unit = MIDIUNIT(i_dev); - - SEQ_DEBUG(printf("seq_write: unit %d, resid %d.\n", unit, buf->uio_resid)); - - if (unit >= NSEQ_MAX) { - SEQ_DEBUG(printf("seq_write: unit %d does not exist.\n", unit)); - return (ENXIO); - } - - sd = get_seqdev_info(i_dev, &unit); - if (sd == NULL) { - SEQ_DEBUG(printf("seq_write: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = sd->softc; - if ((scp->fflags & FWRITE) == 0) { - SEQ_DEBUG(printf("seq_write: unit %d is not for writing.\n", unit)); - return (EIO); - } - - p = 0; - countorg = buf->uio_resid; - count = countorg; - - /* Pick up an event. */ - while (count >= 4) { - if (uiomove((caddr_t)event, 4, buf)) - printf("seq_write: user memory mangled?\n"); - ev_code = event[0]; - SEQ_DEBUG(printf("seq_write: unit %d, event %s.\n", unit, midi_cmdname(ev_code, cmdtab_seqevent))); - - /* Have a look at the event code. */ - if (ev_code == SEQ_FULLSIZE) { - - /* A long event, these are the patches/samples for a synthesizer. */ - midiunit = *(u_short *)&event[2]; - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - return (ret); - - SEQ_DEBUG(printf("seq_write: loading a patch to the unit %d.\n", midiunit)); - - ret = md->synth.loadpatch(md, *(short *)&event[0], buf, p + 4, count, 0); - return (ret); - } - - if (ev_code >= 128) { - - /* Some sort of an extended event. The size is eight bytes. */ - if (scp->seq_mode == SND_DEV_MUSIC && ev_code == SEQ_EXTENDED) { - printf("seq_write: invalid level two event %x.\n", ev_code); - return (EINVAL); - } - ev_size = 8; - - if (count < ev_size) { - /* No more data. Start playing now. */ - mtx_lock(&sd->flagqueue_mtx); - if ((sd->flags & SEQ_F_WRITING) == 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - mtx_unlock(&sd->flagqueue_mtx); - buf->uio_resid += 4; - - return (0); - } - if (uiomove((caddr_t)&event[4], 4, buf)) - printf("seq_write: user memory mangled?\n"); - } else { - - /* Not an extended event. The size is four bytes. */ - if (scp->seq_mode == SND_DEV_MUSIC) { - printf("seq_write: four byte event in level two mode.\n"); - return (EINVAL); - } - ev_size = 4; - } - if (ev_code == SEQ_MIDIPUTC) { - /* An event passed to the midi device itself. */ - midiunit = event[2]; - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev_midi(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - return (ret); - } - - SEQ_DEBUG(printf("seq_write: queueing event %s.\n", midi_cmdname(event[0], cmdtab_seqevent))); - /* Now we queue the event. */ - mtx_lock(&sd->flagqueue_mtx); - switch (seq_queue(scp, event)) { - case EAGAIN: - /* The queue is full. Start playing now. */ - if ((sd->flags & SEQ_F_WRITING) == 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - mtx_unlock(&sd->flagqueue_mtx); - buf->uio_resid = count; - SEQ_DEBUG(printf("seq_write: resid %d.\n", buf->uio_resid)); - if (count < countorg) - return (0); - return (EAGAIN); - case EINTR: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_write: resid %d.\n", buf->uio_resid)); - return (EINTR); - case ERESTART: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_write: resid %d.\n", buf->uio_resid)); - return (ERESTART); - } - mtx_unlock(&sd->flagqueue_mtx); - p += ev_size; - count -= ev_size; - } - - /* We have written every single data. Start playing now. */ - mtx_lock(&sd->flagqueue_mtx); - if ((sd->flags & SEQ_F_WRITING) == 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - mtx_unlock(&sd->flagqueue_mtx); - - SEQ_DEBUG(printf("seq_write: resid %d.\n", buf->uio_resid)); - - return (0); -} - -int -seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - int unit, midiunit, ret, tmp; - sc_p scp; - seqdev_info *sd; - mididev_info *md; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - struct patmgr_info *patinfo; - struct seq_event_rec *event; - struct snd_size *sndsize; - - unit = MIDIUNIT(i_dev); - - SEQ_DEBUG(printf("seq_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_seqioctl))); - - if (unit >= NSEQ_MAX) { - SEQ_DEBUG(printf("seq_ioctl: unit %d does not exist.\n", unit)); - return (ENXIO); - } - sd = get_seqdev_info(i_dev, &unit); - if (sd == NULL) { - SEQ_DEBUG(printf("seq_ioctl: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = sd->softc; - - ret = 0; - - switch (cmd) { - - /* - * we start with the new ioctl interface. - */ - case AIONWRITE: /* how many bytes can be written ? */ - mtx_lock(&sd->flagqueue_mtx); - *(int *)arg = sd->midi_dbuf_out.fl; - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: fl %d.\n", *(int *)arg)); - break; - - case AIOSSIZE: /* set the current blocksize */ - sndsize = (struct snd_size *)arg; - SEQ_DEBUG(printf("seq_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size)); - mtx_lock(&sd->flagqueue_mtx); - if (sndsize->play_size <= sd->midi_dbuf_out.unit_size && sndsize->rec_size <= sd->midi_dbuf_in.unit_size) { - sd->midi_dbuf_out.blocksize = sd->midi_dbuf_out.unit_size; - sd->midi_dbuf_in.blocksize = sd->midi_dbuf_in.unit_size; - sndsize->play_size = sd->midi_dbuf_out.blocksize; - sndsize->rec_size = sd->midi_dbuf_in.blocksize; - sd->flags &= ~MIDI_F_HAS_SIZE; - mtx_unlock(&sd->flagqueue_mtx); - } - else { - if (sndsize->play_size > sd->midi_dbuf_out.bufsize / 4) - sndsize->play_size = sd->midi_dbuf_out.bufsize / 4; - if (sndsize->rec_size > sd->midi_dbuf_in.bufsize / 4) - sndsize->rec_size = sd->midi_dbuf_in.bufsize / 4; - /* Round up the size to the multiple of EV_SZ. */ - sd->midi_dbuf_out.blocksize = - ((sndsize->play_size + sd->midi_dbuf_out.unit_size - 1) - / sd->midi_dbuf_out.unit_size) * sd->midi_dbuf_out.unit_size; - sd->midi_dbuf_in.blocksize = - ((sndsize->rec_size + sd->midi_dbuf_in.unit_size - 1) - / sd->midi_dbuf_in.unit_size) * sd->midi_dbuf_in.unit_size; - sndsize->play_size = sd->midi_dbuf_out.blocksize; - sndsize->rec_size = sd->midi_dbuf_in.blocksize; - sd->flags |= MIDI_F_HAS_SIZE; - mtx_unlock(&sd->flagqueue_mtx); - } - - ret = 0; - break; - - case AIOGSIZE: /* get the current blocksize */ - sndsize = (struct snd_size *)arg; - mtx_lock(&sd->flagqueue_mtx); - sndsize->play_size = sd->midi_dbuf_out.blocksize; - sndsize->rec_size = sd->midi_dbuf_in.blocksize; - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size)); - - ret = 0; - break; - - case AIOSTOP: - if (*(int *)arg == AIOSYNC_PLAY) { - - /* Stop writing. */ - mtx_lock(&sd->flagqueue_mtx); - sd->callback(sd, SEQ_CB_ABORT | SEQ_CB_WR); - mtx_unlock(&sd->flagqueue_mtx); - - /* Pass the ioctl to the midi devices. */ - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - if ((md->flags & MIDI_F_WRITING) != 0) - midi_ioctl(MIDIMKDEV(major(i_dev), md->unit, SND_DEV_MIDIN), cmd, (caddr_t)arg, mode, td); - } - - mtx_lock(&sd->flagqueue_mtx); - *(int *)arg = sd->midi_dbuf_out.rl; - mtx_unlock(&sd->flagqueue_mtx); - } - else if (*(int *)arg == AIOSYNC_CAPTURE) { - - /* Stop reading. */ - mtx_lock(&sd->flagqueue_mtx); - sd->callback(sd, SEQ_CB_ABORT | SEQ_CB_RD); - mtx_unlock(&sd->flagqueue_mtx); - - /* Pass the ioctl to the midi devices. */ - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - if ((md->flags & MIDI_F_WRITING) != 0) - midi_ioctl(MIDIMKDEV(major(i_dev), md->unit, SND_DEV_MIDIN), cmd, (caddr_t)arg, mode, td); - } - - mtx_lock(&sd->flagqueue_mtx); - *(int *)arg = sd->midi_dbuf_in.rl; - mtx_unlock(&sd->flagqueue_mtx); - } - - ret = 0; - break; - - case AIOSYNC: - mtx_lock(&sd->flagqueue_mtx); - scp->sync_parm = *(snd_sync_parm *)arg; - mtx_unlock(&sd->flagqueue_mtx); - - /* XXX Should select(2) against us watch the blocksize, or sync_parm? */ - - ret = 0; - break; - - case FIONBIO: /* set/clear non-blocking i/o */ - mtx_lock(&sd->flagqueue_mtx); - if (*(int *)arg == 0) - sd->flags &= ~SEQ_F_NBIO ; - else - sd->flags |= SEQ_F_NBIO ; - mtx_unlock(&sd->flagqueue_mtx); - MIDI_DEBUG(printf("seq_ioctl: arg %d.\n", *(int *)arg)); - break ; - - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SOURCE: - mtx_lock(&sd->flagqueue_mtx); - if (scp->seq_mode != SND_DEV_MUSIC) { - ret = EINVAL; - mtx_unlock(&sd->flagqueue_mtx); - break; - } - mtx_unlock(&sd->flagqueue_mtx); - /* XXX We should adopt am sx to protect scp->timer */ - ret = scp->timer->ioctl(scp->timer, cmd, arg, mode, td); - break; - case SNDCTL_TMR_SELECT: - mtx_lock(&sd->flagqueue_mtx); - if (scp->seq_mode != SND_DEV_MUSIC) { - ret = EINVAL; - mtx_unlock(&sd->flagqueue_mtx); - break; - } - mtx_unlock(&sd->flagqueue_mtx); - scp->pending_timer = *(int *)arg; - mtx_lock(&sd->flagqueue_mtx); - if (scp->pending_timer < 0) { - scp->pending_timer = -1; - ret = EINVAL; - mtx_unlock(&sd->flagqueue_mtx); - break; - } - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: new timer %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_SEQ_PANIC: - mtx_lock(&sd->flagqueue_mtx); - seq_panic(scp); - mtx_unlock(&sd->flagqueue_mtx); - ret = 0; - break; - case SNDCTL_SEQ_SYNC: - if (mode == O_RDONLY) { - ret = 0; - break; - } - mtx_lock(&scp->devinfo->flagqueue_mtx); - ret = seq_sync(scp); - mtx_unlock(&scp->devinfo->flagqueue_mtx); - break; - case SNDCTL_SEQ_RESET: - mtx_lock(&scp->devinfo->flagqueue_mtx); - seq_reset(scp); - mtx_unlock(&scp->devinfo->flagqueue_mtx); - ret = 0; - break; - case SNDCTL_SEQ_TESTMIDI: - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev_midi(scp, *(int *)arg, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - break; - case SNDCTL_SEQ_GETINCOUNT: - if (mode == O_WRONLY) - *(int *)arg = 0; - else { - mtx_lock(&sd->flagqueue_mtx); - *(int *)arg = sd->midi_dbuf_in.rl; - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: incount %d.\n", *(int *)arg)); - } - ret = 0; - break; - case SNDCTL_SEQ_GETOUTCOUNT: - if (mode == O_RDONLY) - *(int *)arg = 0; - else { - mtx_lock(&sd->flagqueue_mtx); - *(int *)arg = sd->midi_dbuf_out.fl; - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: outcount %d.\n", *(int *)arg)); - } - ret = 0; - break; - case SNDCTL_SEQ_CTRLRATE: - mtx_lock(&sd->flagqueue_mtx); - if (scp->seq_mode == SND_DEV_MUSIC) { - mtx_unlock(&sd->flagqueue_mtx); - ret = scp->timer->ioctl(scp->timer, cmd, arg, mode, td); - break; - } - mtx_unlock(&sd->flagqueue_mtx); - if (*(int *)arg != 0) { - ret = EINVAL; - break; - } - *(int *)arg = hz; - SEQ_DEBUG(printf("seq_ioctl: ctrlrate %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_SEQ_RESETSAMPLES: - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_SEQ_NRSYNTHS: - mtx_lock(&sd->flagqueue_mtx); - if (scp->seq_mode == SND_DEV_MUSIC) - *(int *)arg = mididev_synth_number() + mididev_midi_number(); - else - *(int *)arg = mididev_synth_number(); - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: synths %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_SEQ_NRMIDIS: - mtx_lock(&sd->flagqueue_mtx); - if (scp->seq_mode == SND_DEV_MUSIC) - *(int *)arg = 0; - else - *(int *)arg = mididev_midi_number(); - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: midis %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_SYNTH_MEMAVL: - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_FM_4OP_ENABLE: - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_SYNTH_INFO: - synthinfo = (struct synth_info *)arg; - midiunit = synthinfo->device; - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_SEQ_OUTOFBAND: - event = (struct seq_event_rec *)arg; - mtx_lock(&sd->flagqueue_mtx); - ret = seq_playevent(scp, event->arr); - mtx_unlock(&sd->flagqueue_mtx); - break; - case SNDCTL_MIDI_INFO: - midiinfo = (struct midi_info *)arg; - midiunit = midiinfo->device; - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev_midi(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_PMGR_IFACE: - patinfo = (struct patmgr_info *)arg; - midiunit = patinfo->device; - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_PMGR_ACCESS: - patinfo = (struct patmgr_info *)arg; - midiunit = patinfo->device; - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - case SNDCTL_SEQ_THRESHOLD: - mtx_lock(&sd->flagqueue_mtx); - RANGE(*(int *)arg, 1, sd->midi_dbuf_out.bufsize - 1); - scp->output_threshould = *(int *)arg; - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: threshold %d.\n", *(int *)arg)); - ret = 0; - break; - case SNDCTL_MIDI_PRETIME: - tmp = *(int *)arg; - if (tmp < 0) - tmp = 0; - mtx_lock(&sd->flagqueue_mtx); - scp->pre_event_timeout = (hz * tmp) / 10; - *(int *)arg = scp->pre_event_timeout; - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_ioctl: pretime %d.\n", *(int *)arg)); - ret = 0; - break; - default: - if ((scp->fflags & O_ACCMODE) == FREAD) { - ret = EIO; - break; - } - mtx_lock(&sd->flagqueue_mtx); - ret = lookup_mididev(scp, 0, LOOKUP_OPEN, &md); - mtx_unlock(&sd->flagqueue_mtx); - if (ret != 0) - break; - ret = midi_ioctl(MIDIMKDEV(major(i_dev), 0, SND_DEV_MIDIN), cmd, arg, mode, td); - break; - } - - return (ret); -} - -int -seq_poll(dev_t i_dev, int events, struct thread *td) -{ - int unit, ret, lim; - sc_p scp; - seqdev_info *sd; - - unit = MIDIUNIT(i_dev); - - SEQ_DEBUG(printf("seq_poll: unit %d.\n", unit)); - - if (unit >= NSEQ_MAX) { - SEQ_DEBUG(printf("seq_poll: unit %d does not exist.\n", unit)); - return (ENXIO); - } - sd = get_seqdev_info(i_dev, &unit); - if (sd == NULL) { - SEQ_DEBUG(printf("seq_poll: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = sd->softc; - - mtx_lock(&sd->flagqueue_mtx); - - ret = 0; - - /* Look up the apropriate queue and select it. */ - if ((events & (POLLOUT | POLLWRNORM)) != 0) { - /* Start playing. */ - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - - /* Find out the boundary. */ - if ((sd->flags & SEQ_F_HAS_SIZE) != 0) - lim = sd->midi_dbuf_out.blocksize; - else - lim = sd->midi_dbuf_out.unit_size; - if (sd->midi_dbuf_out.fl < lim) - /* No enough space, record select. */ - selrecord(td, &sd->midi_dbuf_out.sel); - else - /* We can write now. */ - ret |= events & (POLLOUT | POLLWRNORM); - } - if ((events & (POLLIN | POLLRDNORM)) != 0) { - /* Start recording. */ - sd->callback(sd, SEQ_CB_START | SEQ_CB_RD); - - /* Find out the boundary. */ - if ((sd->flags & SEQ_F_HAS_SIZE) != 0) - lim = sd->midi_dbuf_in.blocksize; - else - lim = sd->midi_dbuf_in.unit_size; - if (sd->midi_dbuf_in.rl < lim) - /* No data ready, record select. */ - selrecord(td, &sd->midi_dbuf_in.sel); - else - /* We can write now. */ - ret |= events & (POLLIN | POLLRDNORM); - } - - mtx_unlock(&sd->flagqueue_mtx); - - return (ret); -} - -static void -seq_intr(void *p, mididev_info *md) -{ - sc_p scp; - seqdev_info *sd; - - sd = (seqdev_info *)p; - scp = sd->softc; - - mtx_lock(&sd->flagqueue_mtx); - - /* Restart playing if we have the data to output. */ - if (scp->queueout_pending) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - /* Check the midi device if we are reading. */ - if ((sd->flags & SEQ_F_READING) != 0) - seq_midiinput(scp, md); - - mtx_unlock(&sd->flagqueue_mtx); -} - -static int -seq_callback(void *d, int reason) -{ - int unit; - sc_p scp; - seqdev_info *sd; - - sd = (seqdev_info *)d; - - SEQ_DEBUG(printf("seq_callback: reason 0x%x.\n", reason)); - - if (sd == NULL) { - SEQ_DEBUG(printf("seq_callback: device not configured.\n")); - return (ENXIO); - } - scp = sd->softc; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - switch (reason & SEQ_CB_REASON_MASK) { - case SEQ_CB_START: - if ((reason & SEQ_CB_RD) != 0 && (sd->flags & SEQ_F_READING) == 0) - /* Begin recording. */ - sd->flags |= SEQ_F_READING; - if ((reason & SEQ_CB_WR) != 0 && (sd->flags & SEQ_F_WRITING) == 0) - /* Start playing. */ - seq_startplay(scp); - break; - case SEQ_CB_STOP: - case SEQ_CB_ABORT: - if ((reason & SEQ_CB_RD) != 0 && (sd->flags & SEQ_F_READING) != 0) { - /* Stop recording. */ - sd->flags &= ~SEQ_F_READING; - scp->seq_time = seq_gettime(); - scp->prev_input_time = 0; - } - if ((reason & SEQ_CB_WR) != 0 && (sd->flags & SEQ_F_WRITING) != 0) { - /* Stop Playing. */ - sd->flags &= ~SEQ_F_WRITING; - scp->queueout_pending = 0; - scp->seq_time = seq_gettime(); - scp->prev_input_time = 0; - - /* Stop the timer. */ - seq_stoptimer(scp); - } - } - - return (0); -} - -/* - * The functions below here are the libraries for the above ones. - */ - -static int -seq_queue(sc_p scp, u_char *note) -{ - int unit, err, lenw; - seqdev_info *sd; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - SEQ_DEBUG(printf("seq_queue: unit %d.\n", unit)); - - if ((sd->flags & SEQ_F_INSYNC) != 0) - cv_wait(&sd->insync_cv, &sd->flagqueue_mtx); - - if (sd->midi_dbuf_out.fl < EV_SZ) { - /* We have no space. Start playing if not yet. */ - if ((sd->flags & SEQ_F_WRITING) == 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - if ((sd->flags & SEQ_F_NBIO) != 0 && sd->midi_dbuf_out.fl < EV_SZ) - /* We would block. */ - return (EAGAIN); - } - - /* Write to the queue. */ - err = midibuf_seqwrite(&sd->midi_dbuf_out, note, EV_SZ, &lenw, - sd->callback, sd, SEQ_CB_START | SEQ_CB_WR, - &sd->flagqueue_mtx); - - if (err == 0) { - /* Start playing if we have some data in the queue. */ - if (sd->midi_dbuf_out.rl >= EV_SZ && ((sd->flags & SEQ_F_WRITING) == 0)) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - } - - return (err); -} - -static void -seq_startplay(sc_p scp) -{ - int unit, lenr; - u_char event[EV_SZ]; - seqdev_info *sd; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - sd->flags |= SEQ_F_WRITING; - - /* Dequeue the events to play. */ - while (sd->midi_dbuf_out.rl >= EV_SZ) { - - midibuf_seqcopy(&sd->midi_dbuf_out, event, EV_SZ, &lenr, - NULL, NULL, 0, - &sd->flagqueue_mtx); - - switch (seq_playevent(scp, event)) { - case TIMERARMED: - midibuf_seqdelete(&sd->midi_dbuf_out, EV_SZ, &lenr, - NULL, NULL, 0, - &sd->flagqueue_mtx); - return; - case QUEUEFULL: - /* We cannot play any further. */ - return; - case MORE: - midibuf_seqdelete(&sd->midi_dbuf_out, EV_SZ, &lenr, - NULL, NULL, 0, - &sd->flagqueue_mtx); - break; - } - } - - /* Played every event in the queue. */ - sd->flags &= ~SEQ_F_WRITING; -} - -static int -seq_playevent(sc_p scp, u_char *event) -{ - int unit, ret, lenw; - long *delay; - seqdev_info *sd; - mididev_info *md; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - ret = lookup_mididev(scp, 0, LOOKUP_OPEN, &md); - if (ret != 0) - return (MORE); - - SEQ_DEBUG(printf("seq_playevent: unit %d, event %s.\n", sd->unit, midi_cmdname(event[0], cmdtab_seqevent))); - - switch(event[0]) { - case SEQ_NOTEOFF: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_playevent: chn %d, note %d, vel %d.\n", event[1], event[2], event[3])); - if (md->synth.killnote(md, event[1], 255, event[3]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - ret = QUEUEFULL; - break; - } - mtx_lock(&sd->flagqueue_mtx); - ret = MORE; - break; - case SEQ_NOTEON: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_playevent: chn %d, note %d, vel %d, aux %d.\n", event[1], event[2], event[3], event[4])); - if ((event[4] < 128 || event[4] == 255) && md->synth.startnote(md, event[1], event[2], event[3]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - ret = QUEUEFULL; - break; - } - mtx_lock(&sd->flagqueue_mtx); - ret = MORE; - break; - case SEQ_WAIT: - - /* Extract the delay. */ - delay = (long *)event; - *delay = (*delay >> 8) & 0xffffff; - SEQ_DEBUG(printf("seq_playevent: delay %ld.\n", *delay)); - if (*delay > 0) { - /* Arm the timer. */ - sd->flags |= SEQ_F_WRITING; - if (seq_requesttimer(scp, *delay)) { - ret = TIMERARMED; - break; - } - } - ret = MORE; - break; - case SEQ_PGMCHANGE: - SEQ_DEBUG(printf("seq_playevent: chn %d, instr %d.\n", event[1], event[2])); - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.setinstr(md, event[1], event[2]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - ret = QUEUEFULL; - break; - } - mtx_lock(&sd->flagqueue_mtx); - ret = MORE; - break; - case SEQ_SYNCTIMER: - /* Reset the timer. */ - scp->seq_time = seq_gettime(); - scp->prev_input_time = 0; - scp->prev_event_time = 0; - scp->prev_wakeup_time = scp->seq_time; - ret = MORE; - break; - case SEQ_MIDIPUTC: - SEQ_DEBUG(printf("seq_playevent: data 0x%02x, unit %d.\n", event[1], event[2])); - /* Pass through to the midi device. */ - ret = lookup_mididev_midi(scp, event[2], LOOKUP_OPEN, &md); - if (ret != 0) { - ret = MORE; - break; - } - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.writeraw(md, &event[1], sizeof(event[1]), &lenw, 1) == EAGAIN) - /* The queue was full. Try again later. */ - ret = QUEUEFULL; - else - ret = MORE; - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_ECHO: - /* Echo this event back. */ - if (seq_copytoinput(scp, event, 4) == EAGAIN) { - ret = QUEUEFULL; - break; - } - ret = MORE; - break; - case SEQ_PRIVATE: - ret = lookup_mididev(scp, event[1], LOOKUP_OPEN, &md); - if (ret != 0) { - ret = MORE; - break; - } - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.hwcontrol(md, event) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - ret = QUEUEFULL; - break; - } - mtx_lock(&sd->flagqueue_mtx); - ret = MORE; - break; - case SEQ_EXTENDED: - ret = seq_extended(scp, event); - break; - case EV_CHN_VOICE: - ret = seq_chnvoice(scp, event); - break; - case EV_CHN_COMMON: - ret = seq_chncommon(scp, event); - break; - case EV_TIMING: - ret = seq_timing(scp, event); - break; - case EV_SEQ_LOCAL: - ret = seq_local(scp, event); - break; - case EV_SYSEX: - ret = seq_sysex(scp, event); - break; - default: - ret = MORE; - break; - } - - switch (ret) { - case QUEUEFULL: - SEQ_DEBUG(printf("seq_playevent: the queue is full.\n")); - /* The queue was full. Try again on the interrupt by the midi device. */ - sd->flags |= SEQ_F_WRITING; - scp->queueout_pending = 1; - break; - case TIMERARMED: - SEQ_DEBUG(printf("seq_playevent: armed timer.\n")); - sd->flags |= SEQ_F_WRITING; - /* FALLTHRU */ - case MORE: - scp->queueout_pending = 0; - break; - } - - return (ret); -} - -static u_long -seq_gettime(void) -{ - struct timeval timecopy; - - getmicrotime(&timecopy); - return timecopy.tv_usec / (1000000 / hz) + (u_long) timecopy.tv_sec * hz; -} - -static int -seq_requesttimer(sc_p scp, int delay) -{ - u_long cur_time, rel_base; - - SEQ_DEBUG(printf("seq_requesttimer: unit %d, delay %d.\n", scp->devinfo->unit, delay)); - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - cur_time = seq_gettime(); - - scp->prev_event_time = delay; - if (delay < 0) - /* Request a new timer. */ - delay = -delay; - else { - rel_base = cur_time - scp->seq_time; - if (delay <= rel_base) { - seq_stoptimer(scp); - return 0; - } - delay -= rel_base; - } - -#if notdef - /* - * Compensate the delay of midi message transmission. - * XXX Do we have to consider the accumulation of errors - * less than 1/hz second? - */ - delay -= (cur_time - scp->prev_wakeup_time); - if (delay < 1) { - printf("sequencer: prev = %lu, cur = %lu, delay = %d, skip sleeping.\n", - scp->prev_wakeup_time, cur_time, delay); - seq_stoptimer(scp); - return 0; - } -#endif /* notdef */ - - callout_reset(&scp->timeout_ch, delay, seq_timer, (void *)scp); - scp->timer_running = 1; - - return 1; -} - -static void -seq_stoptimer(sc_p scp) -{ - SEQ_DEBUG(printf("seq_stoptimer: unit %d.\n", scp->devinfo->unit)); - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - if (scp->timer_running) { - callout_stop(&scp->timeout_ch); - scp->timer_running = 0; - } -} - -static void -seq_midiinput(sc_p scp, mididev_info *md) -{ - int unit, midiunit, lenr; - u_long tstamp; - u_char event[4]; - seqdev_info *sd; - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - sd = scp->devinfo; - unit = sd->unit; - - /* Can this midi device interrupt for input? */ - midiunit = md->midiunit; - if (lookup_mididev_midi(scp, midiunit, LOOKUP_EXIST, NULL) != 0) - return; - - if ((md->flags & MIDI_F_READING) != 0 && md->intrarg == sd) { - /* Read the input data. */ - mtx_unlock(&scp->devinfo->flagqueue_mtx); - while (md->synth.readraw(md, &event[1], sizeof(event[1]), &lenr, 1) == 0) { - mtx_lock(&scp->devinfo->flagqueue_mtx); - tstamp = seq_gettime() - scp->seq_time; - if (tstamp != scp->prev_input_time) { - /* Insert a wait between events. */ - tstamp = (tstamp << 8) | SEQ_WAIT; - seq_copytoinput(scp, (u_char *)&tstamp, 4); - scp->prev_input_time = tstamp; - } - bzero(event, sizeof(event)); - event[0] = SEQ_MIDIPUTC; - event[2] = midiunit; - event[3] = 0; - seq_copytoinput(scp, event, sizeof(event)); - mtx_unlock(&scp->devinfo->flagqueue_mtx); - } - mtx_lock(&scp->devinfo->flagqueue_mtx); - } -} - -int -seq_copytoinput(void *arg, u_char *event, int len) -{ - int ret, leni; - sc_p scp; - seqdev_info *sd; - - scp = arg; - sd = scp->devinfo; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - if (len != 4 && len != 8) - return (EINVAL); - if (scp->seq_mode == SND_DEV_MUSIC && len != 8) - return (EINVAL); - - ret = midibuf_input_intr(&sd->midi_dbuf_in, event, len, &leni); - if (ret == EAGAIN) - ret = 0; - - return (ret); -} - -static int -seq_extended(sc_p scp, u_char *event) -{ - int unit; - seqdev_info *sd; - mididev_info *md; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - if (lookup_mididev(scp, event[2], LOOKUP_OPEN, &md) != 0) - return (MORE); - - SEQ_DEBUG(printf("seq_extended: unit %d, event %s, midiunit %d.\n", unit, midi_cmdname(event[1], cmdtab_seqevent), event[2])); - - switch (event[1]) { - case SEQ_NOTEOFF: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: chn %d, note %d, vel %d.\n", event[3], event[4], event[5])); - if (md->synth.killnote(md, event[3], event[4], event[5]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_NOTEON: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: chn %d, note %d, vel %d.\n", event[3], event[4], event[5])); - if ((event[4] < 128 || event[4] == 255) && md->synth.startnote(md, event[3], event[4], event[5]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_PGMCHANGE: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: chn %d, instr %d.\n", event[3], event[4])); - if (md->synth.setinstr(md, event[3], event[4]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_AFTERTOUCH: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: chn %d, press %d.\n", event[3], event[4])); - if (md->synth.aftertouch(md, event[3], event[4]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_BALANCE: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: chn %d, pan %d.\n", event[3], event[4])); - if (md->synth.panning(md, event[3], (char)event[4]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_CONTROLLER: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: chn %d, ctrlnum %d, val %d.\n", event[3], event[4], *(short *)&event[5])); - if (md->synth.controller(md, event[3], event[4], *(short *)&event[5]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case SEQ_VOLMODE: - mtx_unlock(&sd->flagqueue_mtx); - SEQ_DEBUG(printf("seq_extended: mode %d.\n", event[3])); - if (md->synth.volumemethod != NULL && md->synth.volumemethod(md, event[3]) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - } - - return (MORE); -} - -static int -seq_chnvoice(sc_p scp, u_char *event) -{ - int voice; - seqdev_info *sd; - mididev_info *md; - u_char dev, cmd, chn, note, parm; - - voice = -1; - dev = event[1]; - cmd = event[2]; - chn = event[3]; - note = event[4]; - parm = event[5]; - - sd = scp->devinfo; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - if (lookup_mididev(scp, dev, LOOKUP_OPEN, &md) != 0) - return (MORE); - - SEQ_DEBUG(printf("seq_chnvoice: unit %d, dev %d, cmd %s, chn %d, note %d, parm %d.\n", - sd->unit, - dev, - midi_cmdname(cmd, cmdtab_seqcv), - chn, - note, - parm)); - - if (scp->seq_mode == SND_DEV_MUSIC && md->synth.allocvoice != NULL) - voice = seq_allocvoice(scp, md, chn, note); - switch (cmd) { - case MIDI_NOTEON: - if (note < 128 || note == 255) { - if (voice == -1 && scp->seq_mode == SND_DEV_MUSIC && md->synth.allocvoice) - /* This is an internal synthesizer. (FM, GUS, etc) */ - if ((voice = seq_allocvoice(scp, md, chn, note)) == EAGAIN) - return (QUEUEFULL); - if (voice == -1) - voice = chn; - - if (scp->seq_mode == SND_DEV_MUSIC && chn == 9) { - /* This channel is a percussion. The note number is the patch number. */ - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.setinstr(md, voice, 128 + note) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - - note = 60; /* Middle C. */ - } - if (scp->seq_mode == SND_DEV_MUSIC) { - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.setupvoice(md, voice, chn) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.startnote(md, voice, note, parm) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - break; - case MIDI_NOTEOFF: - if (voice == -1) - voice = chn; - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.killnote(md, voice, note, parm) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - case MIDI_KEY_PRESSURE: - if (voice == -1) - voice = chn; - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.aftertouch(md, voice, parm) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - break; - } - - return (MORE); -} - -static int -seq_findvoice(mididev_info *md, int chn, int note) -{ - int i; - u_short key; - - key = (chn << 8) | (note + 1); - - mtx_lock(&md->synth.vc_mtx); - for (i = 0 ; i < md->synth.alloc.max_voice ; i++) - if (md->synth.alloc.map[i] == key) { - mtx_unlock(&md->synth.vc_mtx); - return (i); - } - mtx_unlock(&md->synth.vc_mtx); - - return (-1); -} - -static int -seq_allocvoice(sc_p scp, mididev_info *md, int chn, int note) -{ - int voice; - u_short key; - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - key = (chn << 8) | (note + 1); - - mtx_unlock(&scp->devinfo->flagqueue_mtx); - if ((voice = md->synth.allocvoice(md, chn, note, &md->synth.alloc)) == EAGAIN) { - mtx_lock(&scp->devinfo->flagqueue_mtx); - return (EAGAIN); - } - mtx_lock(&scp->devinfo->flagqueue_mtx); - - mtx_lock(&md->synth.vc_mtx); - md->synth.alloc.map[voice] = key; - md->synth.alloc.alloc_times[voice] = md->synth.alloc.timestamp++; - mtx_unlock(&md->synth.vc_mtx); - - return (voice); -} - -static int -seq_chncommon(sc_p scp, u_char *event) -{ - int unit, i, val, key; - u_short w14; - u_char dev, cmd, chn, p1; - seqdev_info *sd; - mididev_info *md; - - dev = event[1]; - cmd = event[2]; - chn = event[3]; - p1 = event[4]; - w14 = *(u_short *)&event[6]; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - if (lookup_mididev(scp, dev, LOOKUP_OPEN, &md) != 0) - return (MORE); - - SEQ_DEBUG(printf("seq_chnvoice: unit %d, dev %d, cmd %s, chn %d, p1 %d, w14 %d.\n", - sd->unit, - dev, - midi_cmdname(cmd, cmdtab_seqccmn), - chn, - p1, - w14)); - - switch (cmd) { - case MIDI_PGM_CHANGE: - if (scp->seq_mode == SND_DEV_MUSIC) { - mtx_lock(&md->synth.vc_mtx); - md->synth.chn_info[chn].pgm_num = p1; - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&sd->flagqueue_mtx); - if (md->midiunit >= 0) { - if (md->synth.setinstr(md, chn, p1) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - } - mtx_lock(&sd->flagqueue_mtx); - } else { - /* For Mode 1. */ - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.setinstr(md, chn, p1) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - break; - case MIDI_CTL_CHANGE: - /* mtx_lock(&md->giant); */ - if (scp->seq_mode == SND_DEV_MUSIC) { - if (chn < 16 && p1 < 128) { - mtx_lock(&md->synth.vc_mtx); - md->synth.chn_info[chn].controllers[p1] = w14 & 0x7f; - if (p1 < 32) - /* We have set the MSB, clear the LSB. */ - md->synth.chn_info[chn].controllers[p1 + 32] = 0; - if (md->midiunit >= 0) { - val = w14 & 0x7f; - if (p1 < 64) { - /* Combine the MSB and the LSB. */ - val = ((md->synth.chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) - | (md->synth.chn_info[chn].controllers[p1 | 32] & 0x7f); - p1 &= ~32; - } - /* Handle all of the notes playing on this channel. */ - key = ((int)chn << 8); - for (i = 0 ; i < md->synth.alloc.max_voice ; i++) - if ((md->synth.alloc.map[i] & 0xff00) == key) { - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.controller(md, i, p1, val) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - mtx_lock(&md->synth.vc_mtx); - } - mtx_unlock(&md->synth.vc_mtx); - } else { - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.controller(md, chn, p1, w14) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - } - } else { - /* For Mode 1. */ - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.controller(md, chn, p1, w14) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - break; - case MIDI_PITCH_BEND: - if (scp->seq_mode == SND_DEV_MUSIC) { - mtx_lock(&md->synth.vc_mtx); - md->synth.chn_info[chn].bender_value = w14; - if (md->midiunit >= 0) { - /* Handle all of the notes playing on this channel. */ - key = ((int)chn << 8); - for (i = 0 ; i < md->synth.alloc.max_voice ; i++) - if ((md->synth.alloc.map[i] & 0xff00) == key) { - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.bender(md, i, w14) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - } else { - mtx_unlock(&md->synth.vc_mtx); - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.bender(md, chn, w14) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - } else { - /* For Mode 1. */ - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.bender(md, chn, w14) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - break; - } - - return (MORE); -} - -static int -seq_timing(sc_p scp, u_char *event) -{ - int unit, ret; - long parm; - seqdev_info *sd; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - parm = *(long *)&event[4]; - - if (scp->seq_mode == SND_DEV_MUSIC) { - ret = scp->timer->event(scp->timer, event); - if (ret == TIMERARMED) - sd->flags |= SEQ_F_WRITING; - return (ret); - } - - SEQ_DEBUG(printf("seq_timing: unit %d, cmd %s, parm %lu.\n", - unit, midi_cmdname(event[1], cmdtab_timer), parm)); - - ret = MORE; - switch (event[1]) { - case TMR_WAIT_REL: - parm += scp->prev_event_time; - /* FALLTHRU */ - case TMR_WAIT_ABS: - if (parm > 0) { - sd->flags |= SEQ_F_WRITING; - if (seq_requesttimer(scp, parm)) - ret = TIMERARMED; - } - break; - case TMR_START: - scp->seq_time = seq_gettime(); - scp->prev_input_time = 0; - scp->prev_event_time = 0; - scp->prev_wakeup_time = scp->seq_time; - break; - case TMR_STOP: - break; - case TMR_CONTINUE: - break; - case TMR_TEMPO: - break; - case TMR_ECHO: - if (scp->seq_mode == SND_DEV_MUSIC) - seq_copytoinput(scp, event, 8); - else { - parm = (parm << 8 | SEQ_ECHO); - seq_copytoinput(scp, (u_char *)&parm, 4); - } - break; - } - - SEQ_DEBUG(printf("seq_timing: timer %s.\n", - ret == TIMERARMED ? "armed" : "not armed")); - - return (ret); -} - -static int -seq_local(sc_p scp, u_char *event) -{ - int unit; - seqdev_info *sd; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - switch (event[1]) { - case LOCL_STARTAUDIO: -#if notyet - DMAbuf_start_devices(*(u_int *)&event[4]); -#endif /* notyet */ - break; - } - - return (MORE); -} - -static int -seq_sysex(sc_p scp, u_char *event) -{ - int unit, i, l; - seqdev_info *sd; - mididev_info *md; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - if (lookup_mididev(scp, event[1], LOOKUP_OPEN, &md) != 0) - return (MORE); - - l = 0; - for (i = 0 ; i < 6 && event[i + 2] != 0xff ; i++) - l = i + 1; - if (l > 0) { - mtx_unlock(&sd->flagqueue_mtx); - if (md->synth.sendsysex(md, &event[2], l) == EAGAIN) { - mtx_lock(&sd->flagqueue_mtx); - return (QUEUEFULL); - } - mtx_lock(&sd->flagqueue_mtx); - } - - return (MORE); -} - -void -seq_timer(void *arg) -{ - sc_p scp; - seqdev_info *sd; - - scp = arg; - sd = scp->devinfo; - - SEQ_DEBUG(printf("seq_timer: unit %d, timer fired.\n", sd->unit)); - - /* Record the current timestamp. */ - mtx_lock(&sd->flagqueue_mtx); - - scp->timer_running = 0; - scp->prev_wakeup_time = seq_gettime(); - seq_startplay(scp); - - mtx_unlock(&sd->flagqueue_mtx); -} - -static int -seq_openmidi(sc_p scp, mididev_info *md, int flags, int mode, struct thread *td) -{ - int midiunit, err, insync, chn; - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - midiunit = md->unit; - - SEQ_DEBUG(printf("seq_openmidi: opening midi unit %d.\n", midiunit)); - - err = midi_open(MIDIMKDEV(MIDI_CDEV_MAJOR, midiunit, SND_DEV_MIDIN), flags, mode, td); - if (err != 0) { - printf("seq_openmidi: failed to open midi device %d.\n", midiunit); - return (err); - } - mtx_lock(&md->synth.status_mtx); - mtx_lock(&md->flagqueue_mtx); - md->intr = seq_intr; - md->intrarg = scp->devinfo; - mtx_unlock(&md->flagqueue_mtx); - md->synth.sysex_state = 0; - if (scp->seq_mode == SND_DEV_MUSIC) { - for (chn = 0 ; chn < 16 ; chn++) { - md->synth.chn_info[chn].pgm_num = 0; - md->synth.reset(md); - md->synth.chn_info[chn].bender_value = (1 << 7); - } - } - mtx_unlock(&md->synth.status_mtx); - - insync = 0; - if ((scp->devinfo->flags & SEQ_F_INSYNC) != 0) { - insync = 1; - cv_wait(&scp->devinfo->insync_cv, &scp->devinfo->flagqueue_mtx); - } - - TAILQ_INSERT_TAIL(&scp->midi_open, md, md_linkseq); - - if (insync) - cv_broadcast(&scp->devinfo->insync_cv); - - return (0); -} - -static int -seq_closemidi(sc_p scp, mididev_info *md, int flags, int mode, struct thread *td) -{ - int midiunit, insync; - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - if (md == NULL || !MIDICONFED(md)) { - SEQ_DEBUG(printf("seq_closemidi: midi device does not exist.\n")); - return (ENXIO); - } - midiunit = md->unit; - - SEQ_DEBUG(printf("seq_closemidi: closing midi unit %d.\n", midiunit)); - - midi_close(MIDIMKDEV(MIDI_CDEV_MAJOR, midiunit, SND_DEV_MIDIN), flags, mode, td); - mtx_lock(&md->flagqueue_mtx); - md->intr = NULL; - md->intrarg = NULL; - mtx_unlock(&md->flagqueue_mtx); - - insync = 0; - if ((scp->devinfo->flags & SEQ_F_INSYNC) != 0) { - insync = 1; - cv_wait(&scp->devinfo->insync_cv, &scp->devinfo->flagqueue_mtx); - } - - TAILQ_REMOVE(&scp->midi_open, md, md_linkseq); - - if (insync) - cv_broadcast(&scp->devinfo->insync_cv); - - return (0); -} - -static void -seq_panic(sc_p scp) -{ - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - seq_reset(scp); -} - -static int -seq_reset(sc_p scp) -{ - int unit, chn, lenw, ret; - seqdev_info *sd; - mididev_info *md; - u_char c[3]; - - sd = scp->devinfo; - unit = sd->unit; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - SEQ_DEBUG(printf("seq_reset: unit %d.\n", unit)); - - if ((sd->flags & SEQ_F_INSYNC) != 0) - cv_wait(&sd->insync_cv, &sd->flagqueue_mtx); - - /* Stop reading and writing. */ - sd->callback(sd, SEQ_CB_ABORT | SEQ_CB_RD | SEQ_CB_WR); - - /* Clear the queues. */ - midibuf_clear(&sd->midi_dbuf_in); - midibuf_clear(&sd->midi_dbuf_out); - - /* Reset the synthesizers. */ - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) - md->synth.reset(md); - - if (scp->seq_mode == SND_DEV_MUSIC) { - for (chn = 0 ; chn < 16 ; chn++) { - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - mtx_unlock(&sd->flagqueue_mtx); - ret = 0; - if (md->synth.controller(md, chn, 123, 0) == EAGAIN /* All notes off. */ - || md->synth.controller(md, chn, 121, 0) == EAGAIN /* Reset all controllers. */ - || md->synth.bender(md, chn, 1 << 13) == EAGAIN) /* Reset pitch bend. */ - ret = EAGAIN; - mtx_lock(&sd->flagqueue_mtx); - return (ret); - } - } - } else { - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - for (chn = 0 ; chn < 16 ; chn++) { - mtx_unlock(&sd->flagqueue_mtx); - c[0] = 0xb0 | (chn & 0x0f); - c[1] = (u_char)0x78; /* All sound off */ - c[2] = (u_char)0; - md->synth.writeraw(md, c, 3, &lenw, 0); - c[1] = (u_char)0x7b; /* All note off */ - md->synth.writeraw(md, c, 3, &lenw, 0); - c[1] = (u_char)0x79; /* Reset all controller */ - md->synth.writeraw(md, c, 3, &lenw, 0); - mtx_lock(&sd->flagqueue_mtx); - } - } - seq_sync(scp); - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) - lookup_mididev(scp, md->unit, LOOKUP_CLOSE, NULL); - } - - return (0); -} - -#define SEQ_SYNC_TIMEOUT 8 -static int -seq_sync(sc_p scp) -{ - int i, rl; - seqdev_info *sd; - mididev_info *md; - - sd = scp->devinfo; - - mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - - SEQ_DEBUG(printf("seq_sync: unit %d.\n", sd->unit)); - sd->flags |= SEQ_F_INSYNC; - - while (sd->midi_dbuf_out.rl >= EV_SZ) { - if ((sd->flags & SEQ_F_WRITING) == 0) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - rl = sd->midi_dbuf_out.rl; - i = cv_timedwait_sig(&sd->midi_dbuf_out.cv_out, &sd->flagqueue_mtx, SEQ_SYNC_TIMEOUT * hz); - if (i == EINTR || i == ERESTART) { - if (i == EINTR) - sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); - sd->flags &= ~SEQ_F_INSYNC; - return (i); - } - if (i == EWOULDBLOCK && rl == sd->midi_dbuf_out.rl && !scp->timer_running) { - /* A queue seems to be stuck up. Give up and clear queues. */ - sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); - midibuf_clear(&sd->midi_dbuf_out); - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - mtx_lock(&md->flagqueue_mtx); - md->callback(md, MIDI_CB_ABORT | MIDI_CB_WR); - midibuf_clear(&md->midi_dbuf_out); - mtx_unlock(&md->flagqueue_mtx); - } - break; - } - } - - /* - * Since syncing a midi device might block, unlock sd->flagqueue_mtx. - * Keep sd->midi_dbuf_out from writing by setting SEQ_F_INSYNC. - * sd->insync_cv is signalled when sync is finished. - */ - mtx_unlock(&sd->flagqueue_mtx); - - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - mtx_lock(&md->flagqueue_mtx); - midi_sync(md); - mtx_unlock(&md->flagqueue_mtx); - } - - mtx_lock(&sd->flagqueue_mtx); - sd->flags &= ~SEQ_F_INSYNC; - cv_broadcast(&sd->insync_cv); - - return (0); -} - -/* - * a small utility function which, given a device number, returns - * a pointer to the associated seqdev_info struct, and sets the unit - * number. - */ -static seqdev_info * -get_seqdev_info(dev_t i_dev, int *unit) -{ - int u; - - if (MIDIDEV(i_dev) != SND_DEV_SEQ && MIDIDEV(i_dev) != SND_DEV_MUSIC) - return NULL; - u = MIDIUNIT(i_dev); - if (unit) - *unit = u ; - - return get_seqdev_info_unit(u); -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated mididev_info struct. - */ -seqdev_info * -get_seqdev_info_unit(int unit) -{ - seqdev_info *sd; - - mtx_lock(&seqinfo_mtx); - TAILQ_FOREACH(sd, &seq_info, sd_link) { - if (sd->unit == unit) - break; - } - mtx_unlock(&seqinfo_mtx); - - return sd; -} - -/* Create a new sequencer device info structure. */ -seqdev_info * -create_seqdev_info_unit(int unit, seqdev_info *seq) -{ - seqdev_info *sd, *sdnew; - - /* As malloc(9) might block, allocate seqdev_info now. */ - sdnew = malloc(sizeof(seqdev_info), M_DEVBUF, M_WAITOK | M_ZERO); - if (sdnew == NULL) - return NULL; - bcopy(seq, sdnew, sizeof(seqdev_info)); - sdnew->unit = unit; - midibuf_init(&sdnew->midi_dbuf_in); - midibuf_init(&sdnew->midi_dbuf_out); - mtx_init(&sdnew->flagqueue_mtx, "seqflq", NULL, MTX_DEF); - cv_init(&sdnew->insync_cv, "seqins"); - - mtx_lock(&seqinfo_mtx); - - TAILQ_FOREACH(sd, &seq_info, sd_link) { - if (sd->unit == unit) { - mtx_unlock(&seqinfo_mtx); - midibuf_destroy(&sdnew->midi_dbuf_in); - midibuf_destroy(&sdnew->midi_dbuf_out); - mtx_destroy(&sdnew->flagqueue_mtx); - cv_destroy(&sdnew->insync_cv); - free(sdnew, M_DEVBUF); - return sd; - } - } - - mtx_lock(&sdnew->flagqueue_mtx); - TAILQ_INSERT_TAIL(&seq_info, sdnew, sd_link); - nseq++; - - mtx_unlock(&seqinfo_mtx); - - return sdnew; -} - -/* - * Look up a midi device by its unit number opened by this sequencer. - * If the device is not opened and mode is LOOKUP_OPEN, open the device. - */ -static int -lookup_mididev(sc_p scp, int unit, int mode, mididev_info **mdp) -{ - int ret; - mididev_info *md; - - if (mdp == NULL) - mdp = &md; - - *mdp = NULL; - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - if (scp->seq_mode == SND_DEV_MUSIC ? md->unit == unit : md->synthunit == unit) { - *mdp = md; - if (mode == LOOKUP_CLOSE) - return seq_closemidi(scp, md, scp->fflags, MIDIDEV_MODE, curthread); - - return (md != NULL && MIDICONFED(md)) ? 0 : ENXIO; - } - } - - if (mode == LOOKUP_OPEN) { - if (scp->seq_mode == SND_DEV_MUSIC) - md = get_mididev_info_unit(unit); - else - md = get_mididev_synth_unit(unit); - if (md != NULL) { - *mdp = md; - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curthread); - return ret; - } - } - - return ENXIO; -} - -/* - * Look up a midi device by its midi unit number opened by this sequencer. - * If the device is not opened and mode is LOOKUP_OPEN, open the device. - */ -static int -lookup_mididev_midi(sc_p scp, int unit, int mode, mididev_info **mdp) -{ - int ret; - mididev_info *md; - - if (mdp == NULL) - mdp = &md; - - *mdp = NULL; - - if (scp->seq_mode == SND_DEV_MUSIC) - return (ENXIO); - - mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - - TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { - if (md->midiunit == unit) { - *mdp = md; - if (mode == LOOKUP_CLOSE) - return seq_closemidi(scp, md, scp->fflags, MIDIDEV_MODE, curthread); - - return (md != NULL && MIDICONFED(md)) ? 0 : ENXIO; - } - } - - if (mode == LOOKUP_OPEN) { - md = get_mididev_midi_unit(unit); - if (md != NULL) { - *mdp = md; - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curthread); - return ret; - } - } - - return ENXIO; -} - -/* XXX These functions are actually redundant. */ -static int -seqopen(dev_t i_dev, int flags, int mode, struct thread *td) -{ - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_SEQ: - case MIDI_DEV_MUSIC: - return seq_open(i_dev, flags, mode, td); - } - - return (ENXIO); -} - -static int -seqclose(dev_t i_dev, int flags, int mode, struct thread *td) -{ - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_SEQ: - case MIDI_DEV_MUSIC: - return seq_close(i_dev, flags, mode, td); - } - - return (ENXIO); -} - -static int -seqread(dev_t i_dev, struct uio * buf, int flag) -{ - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_SEQ: - case MIDI_DEV_MUSIC: - return seq_read(i_dev, buf, flag); - } - - return (ENXIO); -} - -static int -seqwrite(dev_t i_dev, struct uio * buf, int flag) -{ - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_SEQ: - case MIDI_DEV_MUSIC: - return seq_write(i_dev, buf, flag); - } - - return (ENXIO); -} - -static int -seqioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) -{ - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_SEQ: - case MIDI_DEV_MUSIC: - return seq_ioctl(i_dev, cmd, arg, mode, td); - } - - return (ENXIO); -} - -static int -seqpoll(dev_t i_dev, int events, struct thread *td) -{ - switch (MIDIDEV(i_dev)) { - case MIDI_DEV_SEQ: - case MIDI_DEV_MUSIC: - return seq_poll(i_dev, events, td); - } - - return (ENXIO); -} - -static int -seq_modevent(module_t mod, int type, void *data) -{ - int retval; - - retval = 0; - - switch (type) { - case MOD_LOAD: - seq_init(); - break; - - case MOD_UNLOAD: - printf("sequencer: unload not supported yet.\n"); - retval = EOPNOTSUPP; - break; - - default: - break; - } - - return retval; -} - -DEV_MODULE(seq, seq_modevent, NULL); - -static void -seq_clone(arg, name, namelen, dev) - void *arg; - char *name; - int namelen; - dev_t *dev; -{ - int u; - - if (*dev != NODEV) - return; - if (bcmp(name, "sequencer", 9) != 0) - return; - if (name[10] != '\0' && name[11] != '\0') - return; - u = name[9] - '0'; - if (name[10] != '\0') { - u *= 10; - u += name[10] - '0'; - } - seq_initunit(u); - *dev = MIDIMKDEV(SEQ_CDEV_MAJOR, u, MIDI_DEV_SEQ); - return; -} diff --git a/sys/dev/sound/midi/sequencer.h b/sys/dev/sound/midi/sequencer.h deleted file mode 100644 index c5db26420131..000000000000 --- a/sys/dev/sound/midi/sequencer.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * 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 <sys/condvar.h> -#include <machine/clock.h> /* for DELAY */ -#include <sys/soundcard.h> - -#include <dev/sound/midi/timer.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 - -/* Return value from seq_playevent and timer event handers. */ -enum { - MORE, - TIMERARMED, - QUEUEFULL -}; - -typedef struct _seqdev_info seqdev_info; - -/* - * The order of mutex lock (from the first to the last) - * - * 1. sequencer flags, queues, timer and device list - * 2. midi synth voice and channel - * 3. midi synth status - * 4. generic midi flags and queues - * 5. midi device - */ - -/* - * 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; - 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 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. - */ - - struct mtx flagqueue_mtx; /* Mutex to protect flags and queues */ - struct cv insync_cv; /* Conditional variable for sync */ - - /* Queues */ - 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. - */ - - /* Flags */ - 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 */ - -#define SEQ_F_INSYNC 0x8000 /* a pending sync */ - - 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...*/ - - /* The tailq entry of the next sequencer device. */ - TAILQ_ENTRY(_seqdev_info) sd_link; -}; - - -/* - * then ioctls and other stuff - */ -#define NSEQ_MAX 16 /* 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 (1024) /* XXX */ - -#define MIDI_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - synthesizer and MIDI output) */ -#define MIDI_DEV_MUSIC 8 /* Sequencer output /dev/music (FM - synthesizer and MIDI output) */ - -#ifdef _KERNEL - -extern midi_cmdtab cmdtab_seqioctl[]; -extern midi_cmdtab cmdtab_timer[]; - -void seq_timer(void *arg); -int seq_copytoinput(void *arg, u_char *event, int len); - -SYSCTL_DECL(_hw_midi_seq); - -extern int seq_debug; -#define SEQ_DEBUG(x) \ - do { \ - if (seq_debug) { \ - (x); \ - } \ - } while(0) - -#endif /* _KERNEL */ - - -#endif /* _SEQUENCER_H_ */ diff --git a/sys/dev/sound/midi/timer.c b/sys/dev/sound/midi/timer.c deleted file mode 100644 index ba4bce0d5828..000000000000 --- a/sys/dev/sound/midi/timer.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * This is the timer engine of /dev/music for FreeBSD. - * - * (C) 2002 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. - * - * $FreeBSD$ - * - */ - -#include <dev/sound/midi/midi.h> -#include <dev/sound/midi/sequencer.h> - -#define TMR2TICKS(scp, tmr_val) \ - ((((tmr_val) * (scp)->tempo * (scp)->timebase) + (30 * hz)) / (60 * hz)) -#define CURTICKS(scp) \ - ((scp)->ticks_offset + (scp)->ticks_cur - (scp)->ticks_base) - -struct systmr_timer_softc { - int running; - - u_long ticks_offset; - u_long ticks_base; - u_long ticks_cur; - - int tempo; - int timebase; - - u_long nexteventtime; - u_long preveventtime; - - struct callout timer; -}; - -static timeout_t systmr_timer; -static void systmr_reset(timerdev_info *tmd); -static u_long systmr_time(void); - -static tmr_open_t systmr_open; -static tmr_close_t systmr_close; -static tmr_event_t systmr_event; -static tmr_gettime_t systmr_gettime; -static tmr_ioctl_t systmr_ioctl; -static tmr_armtimer_t systmr_armtimer; - -static timerdev_info systmr_timerdev = { - "System clock", - 0, - 0, - systmr_open, - systmr_close, - systmr_event, - systmr_gettime, - systmr_ioctl, - systmr_armtimer, -}; - -static TAILQ_HEAD(,_timerdev_info) timer_info; -static struct mtx timerinfo_mtx; -static int timerinfo_mtx_init; -static int ntimer; - - -/* Install a system timer. */ -int -timerdev_install(void) -{ - int ret; - timerdev_info *tmd; - struct systmr_timer_softc *scp; - - SEQ_DEBUG(printf("timerdev_install: install a new timer.\n")); - - ret = 0; - tmd = NULL; - scp = NULL; - - scp = malloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO); - if (scp == NULL) { - ret = ENOMEM; - goto fail; - } - - tmd = create_timerdev_info_unit(&systmr_timerdev); - if (tmd == NULL) { - ret = ENOMEM; - goto fail; - } - - tmd->softc = scp; - callout_init(&scp->timer, 0); - - mtx_unlock(&tmd->mtx); - - SEQ_DEBUG(printf("timerdev_install: installed a new timer, unit %d.\n", tmd->unit)); - - return (0); - -fail: - if (scp != NULL) - free(scp, M_DEVBUF); - if (tmd != NULL) { - TAILQ_REMOVE(&timer_info, tmd, tmd_link); - free(tmd, M_DEVBUF); - } - - SEQ_DEBUG(printf("timerdev_install: installation failed.\n")); - - return (ret); -} - -/* Create a new timer device info structure. */ -timerdev_info * -create_timerdev_info_unit(timerdev_info *tmdinf) -{ - int unit; - timerdev_info *tmd, *tmdnew; - - /* XXX */ - if (!timerinfo_mtx_init) { - timerinfo_mtx_init = 1; - mtx_init(&timerinfo_mtx, "tmrinf", NULL, MTX_DEF); - TAILQ_INIT(&timer_info); - } - - /* As malloc(9) might block, allocate timerdev_info now. */ - tmdnew = malloc(sizeof(timerdev_info), M_DEVBUF, M_WAITOK | M_ZERO); - if (tmdnew == NULL) - return NULL; - bcopy(tmdinf, tmdnew, sizeof(timerdev_info)); - mtx_init(&tmdnew->mtx, "tmrmtx", NULL, MTX_DEF); - - mtx_lock(&timerinfo_mtx); - - ntimer++; - - for (unit = 0 ; ; unit++) { - TAILQ_FOREACH(tmd, &timer_info, tmd_link) { - if (tmd->unit == unit) - break; - } - if (tmd == NULL) - break; - } - - tmdnew->unit = unit; - mtx_lock(&tmdnew->mtx); - tmd = TAILQ_FIRST(&timer_info); - while (tmd != NULL) { - if (tmd->prio < tmdnew->prio) - break; - tmd = TAILQ_NEXT(tmd, tmd_link); - } - if (tmd != NULL) - TAILQ_INSERT_BEFORE(tmd, tmdnew, tmd_link); - else - TAILQ_INSERT_TAIL(&timer_info, tmdnew, tmd_link); - - mtx_unlock(&timerinfo_mtx); - - return (tmdnew); -} - -/* - * a small utility function which, given a unit number, returns - * a pointer to the associated timerdev_info struct. - */ -timerdev_info * -get_timerdev_info_unit(int unit) -{ - timerdev_info *tmd; - - /* XXX */ - if (!timerinfo_mtx_init) { - timerinfo_mtx_init = 1; - mtx_init(&timerinfo_mtx, "tmrinf", NULL, MTX_DEF); - TAILQ_INIT(&timer_info); - } - - mtx_lock(&timerinfo_mtx); - TAILQ_FOREACH(tmd, &timer_info, tmd_link) { - mtx_lock(&tmd->mtx); - if (tmd->unit == unit && tmd->seq == NULL) - break; - mtx_unlock(&tmd->mtx); - } - mtx_unlock(&timerinfo_mtx); - - return tmd; -} - -/* - * a small utility function which returns a pointer - * to the best preferred timerdev_info struct with - * no sequencer. - */ -timerdev_info * -get_timerdev_info(void) -{ - timerdev_info *tmd; - - /* XXX */ - if (!timerinfo_mtx_init) { - timerinfo_mtx_init = 1; - mtx_init(&timerinfo_mtx, "tmrinf", NULL, MTX_DEF); - TAILQ_INIT(&timer_info); - } - - mtx_lock(&timerinfo_mtx); - TAILQ_FOREACH(tmd, &timer_info, tmd_link) { - mtx_lock(&tmd->mtx); - if (tmd->seq == NULL) - break; - mtx_unlock(&tmd->mtx); - } - mtx_unlock(&timerinfo_mtx); - - return tmd; -} - - -/* ARGSUSED */ -static void -systmr_timer(void *d) -{ - timerdev_info *tmd; - struct systmr_timer_softc *scp; - void *seq; - - tmd = (timerdev_info *)d; - scp = (struct systmr_timer_softc *)tmd->softc; - seq = NULL; - - mtx_lock(&tmd->mtx); - - if (tmd->opened) { - callout_reset(&scp->timer, 1, systmr_timer, tmd); - - if (scp->running) { - scp->ticks_cur = TMR2TICKS(scp, systmr_time()); - - if (CURTICKS(scp) >= scp->nexteventtime) { - SEQ_DEBUG(printf("systmr_timer: CURTICKS %lu, call the sequencer.\n", CURTICKS(scp))); - scp->nexteventtime = ULONG_MAX; - seq = tmd->seq; - } - } - } - - mtx_unlock(&tmd->mtx); - - if (seq != NULL) - seq_timer(seq); -} - -static void -systmr_reset(timerdev_info *tmd) -{ - struct systmr_timer_softc *scp; - - scp = (struct systmr_timer_softc *)tmd->softc; - - mtx_assert(&tmd->mtx, MA_OWNED); - - SEQ_DEBUG(printf("systmr_reset: unit %d.\n", tmd->unit)); - - scp->ticks_offset = 0; - scp->ticks_base = scp->ticks_cur = TMR2TICKS(scp, systmr_time()); - - scp->nexteventtime = ULONG_MAX; - scp->preveventtime = 0; -} - -static u_long -systmr_time(void) -{ - struct timeval timecopy; - - getmicrotime(&timecopy); - return timecopy.tv_usec / (1000000 / hz) + (u_long) timecopy.tv_sec * hz; -} - - -/* ARGSUSED */ -static int -systmr_open(timerdev_info *tmd, int oflags, int devtype, struct thread *td) -{ - struct systmr_timer_softc *scp; - - scp = (struct systmr_timer_softc *)tmd->softc; - - SEQ_DEBUG(printf("systmr_open: unit %d.\n", tmd->unit)); - - mtx_lock(&tmd->mtx); - - if (tmd->opened) { - mtx_unlock(&tmd->mtx); - return (EBUSY); - } - - systmr_reset(tmd); - scp->tempo = 60; - scp->timebase = hz; - tmd->opened = 1; - - callout_reset(&scp->timer, 1, systmr_timer, tmd); - - mtx_unlock(&tmd->mtx); - - return (0); -} - -static int -systmr_close(timerdev_info *tmd, int fflag, int devtype, struct thread *td) -{ - struct systmr_timer_softc *scp; - - scp = (struct systmr_timer_softc *)tmd->softc; - - SEQ_DEBUG(printf("systmr_close: unit %d.\n", tmd->unit)); - - mtx_lock(&tmd->mtx); - - tmd->opened = 0; - scp->running = 0; - - callout_stop(&scp->timer); - - mtx_unlock(&tmd->mtx); - - return (0); -} - -static int -systmr_event(timerdev_info *tmd, u_char *ev) -{ - struct systmr_timer_softc *scp; - u_char cmd; - u_long parm, t; - int ret; - void * seq; - - scp = (struct systmr_timer_softc *)tmd->softc; - cmd = ev[1]; - parm = *(int *)&ev[4]; - ret = MORE; - - SEQ_DEBUG(printf("systmr_event: unit %d, cmd %s, parm %lu.\n", - tmd->unit, midi_cmdname(cmd, cmdtab_timer), parm)); - - mtx_lock(&tmd->mtx); - - switch (cmd) { - case TMR_WAIT_REL: - parm += scp->preveventtime; - /* FALLTHRU */ - case TMR_WAIT_ABS: - if (parm > 0) { - if (parm <= CURTICKS(scp)) - break; - t = parm; - scp->nexteventtime = scp->preveventtime = t; - ret = TIMERARMED; - break; - } - break; - - case TMR_START: - systmr_reset(tmd); - scp->running = 1; - break; - - case TMR_STOP: - scp->running = 0; - break; - - case TMR_CONTINUE: - scp->running = 1; - break; - - case TMR_TEMPO: - if (parm > 0) { - RANGE(parm, 8, 360); - scp->ticks_offset += scp->ticks_cur - - scp->ticks_base; - scp->ticks_base = scp->ticks_cur; - scp->tempo = parm; - } - break; - - case TMR_ECHO: - seq = tmd->seq; - mtx_unlock(&tmd->mtx); - seq_copytoinput(seq, ev, 8); - mtx_lock(&tmd->mtx); - break; - } - - mtx_unlock(&tmd->mtx); - - SEQ_DEBUG(printf("systmr_event: timer %s.\n", - ret == TIMERARMED ? "armed" : "not armed")); - - return (ret); -} - -static int -systmr_gettime(timerdev_info *tmd, u_long *t) -{ - struct systmr_timer_softc *scp; - int ret; - - scp = (struct systmr_timer_softc *)tmd->softc; - - SEQ_DEBUG(printf("systmr_gettime: unit %d.\n", tmd->unit)); - - mtx_lock(&tmd->mtx); - - if (!tmd->opened || t == NULL) { - ret = EINVAL; - goto fail; - } - - *t = CURTICKS(scp); - SEQ_DEBUG(printf("systmr_gettime: ticks %lu.\n", *t)); - -fail: - mtx_unlock(&tmd->mtx); - - return (0); -} - -static int -systmr_ioctl(timerdev_info *tmd, u_long cmd, caddr_t data, int fflag, struct thread *td) -{ - struct systmr_timer_softc *scp; - int ret, val; - - scp = (struct systmr_timer_softc *)tmd->softc; - ret = 0; - - SEQ_DEBUG(printf("systmr_ioctl: unit %d, cmd %s.\n", - tmd->unit, midi_cmdname(cmd, cmdtab_seqioctl))); - - switch (cmd) { - case SNDCTL_TMR_SOURCE: - *(int *)data = TMR_INTERNAL; - break; - - case SNDCTL_TMR_START: - mtx_lock(&tmd->mtx); - systmr_reset(tmd); - scp->running = 1; - mtx_unlock(&tmd->mtx); - break; - - case SNDCTL_TMR_STOP: - mtx_lock(&tmd->mtx); - scp->running = 0; - mtx_unlock(&tmd->mtx); - break; - - case SNDCTL_TMR_CONTINUE: - mtx_lock(&tmd->mtx); - scp->running = 1; - mtx_unlock(&tmd->mtx); - break; - - case SNDCTL_TMR_TIMEBASE: - val = *(int *)data; - mtx_lock(&tmd->mtx); - if (val > 0) { - RANGE(val, 1, 1000); - scp->timebase = val; - } - *(int *)data = scp->timebase; - mtx_unlock(&tmd->mtx); - SEQ_DEBUG(printf("systmr_ioctl: timebase %d.\n", *(int *)data)); - break; - - case SNDCTL_TMR_TEMPO: - val = *(int *)data; - mtx_lock(&tmd->mtx); - if (val > 0) { - RANGE(val, 8, 360); - scp->ticks_offset += scp->ticks_cur - - scp->ticks_base; - scp->ticks_base = scp->ticks_cur; - scp->tempo = val; - } - *(int *)data = scp->tempo; - SEQ_DEBUG(printf("systmr_ioctl: tempo %d.\n", *(int *)data)); - mtx_unlock(&tmd->mtx); - break; - - case SNDCTL_SEQ_CTRLRATE: - val = *(int *)data; - if (val > 0) - ret = EINVAL; - else { - mtx_lock(&tmd->mtx); - *(int *)data = ((scp->tempo * scp->timebase) + 30) / 60; - mtx_unlock(&tmd->mtx); - SEQ_DEBUG(printf("systmr_ioctl: ctrlrate %d.\n", *(int *)data)); - } - break; - - case SNDCTL_TMR_METRONOME: - /* NOP. */ - break; - - case SNDCTL_TMR_SELECT: - /* NOP. */ - break; - - default: - ret = EINVAL; - } - - return (ret); -} - -static int -systmr_armtimer(timerdev_info *tmd, u_long t) -{ - struct systmr_timer_softc *scp; - - scp = (struct systmr_timer_softc *)tmd->softc; - - SEQ_DEBUG(printf("systmr_armtimer: unit %d, t %lu.\n", tmd->unit, t)); - - mtx_lock(&tmd->mtx); - - if (t < 0) - t = CURTICKS(scp) + 1; - else if (t > CURTICKS(scp)) - scp->nexteventtime = scp->preveventtime = t; - - mtx_unlock(&tmd->mtx); - - return (0); -} diff --git a/sys/dev/sound/midi/timer.h b/sys/dev/sound/midi/timer.h deleted file mode 100644 index a615ab64cdc9..000000000000 --- a/sys/dev/sound/midi/timer.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Include file for a midi timer. - * - * Copyright by Seigo Tanimura 2002. - * - * 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$ - * - */ - -#ifndef _TIMER_H_ -#define _TIMER_H_ - -typedef struct _timerdev_info timerdev_info; - -typedef int (tmr_open_t)(timerdev_info *tmd, int oflags, int devtype, struct thread *td); -typedef int (tmr_close_t)(timerdev_info *tmd, int fflag, int devtype, struct thread *td); -typedef int (tmr_event_t)(timerdev_info *tmd, u_char *ev); -typedef int (tmr_gettime_t)(timerdev_info *tmd, u_long *t); -typedef int (tmr_ioctl_t)(timerdev_info *tmd, u_long cmd, caddr_t data, int fflag, struct thread *td); -typedef int (tmr_armtimer_t)(timerdev_info *tmd, u_long t); - -struct _timerdev_info { - /* - * the first part of the descriptor is filled up from a - * template. - */ - char name[32]; - - int caps; - int prio; - - tmr_open_t *open; - tmr_close_t *close; - tmr_event_t *event; - tmr_gettime_t *gettime; - tmr_ioctl_t *ioctl; - tmr_armtimer_t *armtimer; - - - int unit; - void *softc; - void *seq; - - /* The tailq entry of the next timer device. */ - TAILQ_ENTRY(_timerdev_info) tmd_link; - - int opened; - - struct mtx mtx; -}; - -#ifdef _KERNEL -int timerdev_install(void); -timerdev_info *create_timerdev_info_unit(timerdev_info *tmdinf); -timerdev_info *get_timerdev_info_unit(int unit); -timerdev_info *get_timerdev_info(void); -#endif /* _KERNEL */ - -#endif /* _TIMER_H_ */ diff --git a/sys/dev/sound/pci/csamidi.c b/sys/dev/sound/pci/csamidi.c deleted file mode 100644 index 4f91b5f3af65..000000000000 --- a/sys/dev/sound/pci/csamidi.c +++ /dev/null @@ -1,586 +0,0 @@ -/*- - * 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 <dev/sound/midi/midi.h> -#include <dev/sound/chip.h> -#include <dev/sound/pci/csareg.h> -#include <machine/cpufunc.h> - -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.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 mtx mtx; /* Mutex to protect the device. */ - - 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, u_int8_t *value); -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); -/* Not used in this file. */ -#if notdef -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); -#endif /* notdef */ -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, - csamidi_ioctl, - - 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 = PCIR_BAR(0); - scp->mem_rid = PCIR_BAR(1); - 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; - - scp = device_get_softc(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; - mtx_init(&scp->mtx, "csamid", NULL, MTX_DEF); - scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &csamidi_op_desc, &midisynth_op_desc); - - /* Fill the midi info. */ - snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at irq %d", - (int)rman_get_start(scp->irq)); - - midiinit(devinfo, dev); - - /* Enable interrupt. */ - if (bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, 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 thread *td) -{ - sc_p scp; - mididev_info *devinfo; - int unit; - struct synth_info *synthinfo; - struct midi_info *midiinfo; - - unit = MIDIUNIT(i_dev); - - MIDI_DEBUG(printf("csamidi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl))); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - MIDI_DEBUG(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 != 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 != 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; - int leni; - - scp = (sc_p)arg; - devinfo = scp->devinfo; - - mtx_lock(&devinfo->flagqueue_mtx); - mtx_lock(&scp->mtx); - - /* Read the received data. */ - while ((csamidi_status(scp) & MIDSR_RBE) == 0) { - /* Receive the data. */ - csamidi_readdata(scp, &c); - mtx_unlock(&scp->mtx); - - /* 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), &leni); - 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), &leni); - } - mtx_lock(&scp->mtx); - } - mtx_unlock(&scp->mtx); - - /* Transmit out data. */ - if ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) - csamidi_xmit(scp); - - mtx_unlock(&devinfo->flagqueue_mtx); - - /* Invoke the upper layer. */ - midi_intr(devinfo); -} - -static int -csamidi_callback(void *di, int reason) -{ - int unit; - sc_p scp; - mididev_info *d; - - d = (mididev_info *)di; - - mtx_assert(&d->flagqueue_mtx, MA_OWNED); - - if (d == NULL) { - MIDI_DEBUG(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. - */ -static void -csamidi_startplay(sc_p scp) -{ - mididev_info *devinfo; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* 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; - int leno; - - devinfo = scp->devinfo; - - mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); - - /* 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) { - /* Do we have the data to transmit? */ - if (dbuf->rl == 0) { - /* Stop playing. */ - devinfo->flags &= ~MIDI_F_WRITING; - break; - } else { - mtx_lock(&scp->mtx); - if ((csamidi_status(scp) & MIDSR_TBF) != 0) { - mtx_unlock(&scp->mtx); - break; - } - /* Send the data. */ - midibuf_output_intr(dbuf, &c, sizeof(c), &leno); - csamidi_writedata(scp, c); - /* We are playing now. */ - devinfo->flags |= MIDI_F_WRITING; - mtx_unlock(&scp->mtx); - } - } -} - -/* Reset midi. */ -static int -csamidi_reset(sc_p scp) -{ - int i, resp; - - mtx_lock(&scp->mtx); - - /* 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) { - mtx_unlock(&scp->mtx); - 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); - - mtx_unlock(&scp->mtx); - - 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_int8_t *value) -{ - u_int status; - - if (value == NULL) - return (EINVAL); - - /* Is the interface ready to read? */ - status = csamidi_status(scp); - if ((status & MIDSR_RBE) != 0) - /* The interface is busy. */ - return (EAGAIN); - - *value = (u_int8_t)(csamidi_readio(scp, BA0_MIDRP) & 0xff); - - return (0); -} - -/* 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); -} - -/* Not used in this file. */ -#if notdef -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); -} -#endif /* notdef */ - -/* Allocates resources. */ -static int -csamidi_allocres(sc_p scp, device_t dev) -{ - if (scp->io == NULL) { - scp->io = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &scp->io_rid, RF_ACTIVE); - if (scp->io == NULL) - return (1); - } - if (scp->mem == NULL) { - scp->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &scp->mem_rid, RF_ACTIVE); - if (scp->mem == NULL) - return (1); - } - if (scp->irq == NULL) { - scp->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &scp->irq_rid, 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); |