sound: Import latest code from FreeBSD
authorFrançois Tigeot <ftigeot@wolfpond.org>
Thu, 8 Jan 2015 09:44:43 +0000 (10:44 +0100)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Thu, 8 Jan 2015 10:40:37 +0000 (11:40 +0100)
* As of 1bac48ea8f21c4121f1c45311ec4f05577c58abc (SVN id r275101)
  "Add bunch of PCI IDs of Intel Wildcat Point (9 Series) chipsets."

* Do not import isa, macio, sbus and usb drivers

* snd_au88x0 has been removed. According to the FreeBSD commit message, it
  never even got compiled into the kernel or as a module.

* Drop the ds1, csa and maestro3 drivers due to restrictive license terms
  or the need to use binary blobs. These drivers are not built by default
  on FreeBSD.

180 files changed:
Makefile_upgrade.inc
share/man/man4/Makefile
share/man/man4/pcm.4
share/man/man4/snd_csa.4 [deleted file]
share/man/man4/snd_ds1.4 [deleted file]
share/man/man4/snd_maestro.4
share/man/man4/snd_maestro3.4 [deleted file]
sys/boot/dloader/loader-bootp.conf
sys/boot/dloader/loader.conf
sys/conf/files
sys/conf/kmod.mk
sys/conf/options
sys/config/LINT
sys/config/LINT64
sys/dev/sound/Makefile
sys/dev/sound/Makefile.inc
sys/dev/sound/chip.h
sys/dev/sound/clone.c [new file with mode: 0644]
sys/dev/sound/clone.h [new file with mode: 0644]
sys/dev/sound/driver.c
sys/dev/sound/driver/Makefile
sys/dev/sound/driver/Makefile.inc
sys/dev/sound/driver/als4000/Makefile
sys/dev/sound/driver/atiixp/Makefile
sys/dev/sound/driver/au88x0/Makefile [deleted file]
sys/dev/sound/driver/audiocs/Makefile [deleted file]
sys/dev/sound/driver/cmi/Makefile
sys/dev/sound/driver/cs4281/Makefile
sys/dev/sound/driver/csa/Makefile [deleted file]
sys/dev/sound/driver/driver/Makefile
sys/dev/sound/driver/ds1/Makefile [deleted file]
sys/dev/sound/driver/emu10k1/Makefile
sys/dev/sound/driver/emu10kx/Makefile [new file with mode: 0644]
sys/dev/sound/driver/envy24/Makefile
sys/dev/sound/driver/envy24ht/Makefile
sys/dev/sound/driver/es137x/Makefile
sys/dev/sound/driver/fm801/Makefile
sys/dev/sound/driver/hda/Makefile
sys/dev/sound/driver/hdspe/Makefile [new file with mode: 0644]
sys/dev/sound/driver/ich/Makefile
sys/dev/sound/driver/maestro/Makefile
sys/dev/sound/driver/maestro3/Makefile [deleted file]
sys/dev/sound/driver/neomagic/Makefile
sys/dev/sound/driver/solo/Makefile
sys/dev/sound/driver/spicds/Makefile
sys/dev/sound/driver/t4dwave/Makefile
sys/dev/sound/driver/via8233/Makefile
sys/dev/sound/driver/via82c686/Makefile
sys/dev/sound/driver/vibes/Makefile
sys/dev/sound/midi/midi.c [new file with mode: 0644]
sys/dev/sound/midi/midi.h [copied from sys/dev/sound/pcm/vchan.h with 61% similarity]
sys/dev/sound/midi/midiq.h [new file with mode: 0644]
sys/dev/sound/midi/mpu401.c [new file with mode: 0644]
sys/dev/sound/midi/mpu401.h [copied from sys/dev/sound/pcm/dsp.h with 77% similarity]
sys/dev/sound/midi/mpu_if.m [copied from sys/dev/sound/pcm/mixer_if.m with 65% similarity]
sys/dev/sound/midi/mpufoi_if.m [copied from sys/dev/sound/pcm/ac97_if.m with 69% similarity]
sys/dev/sound/midi/sequencer.c [new file with mode: 0644]
sys/dev/sound/midi/sequencer.h [copied from sys/dev/sound/chip.h with 55% similarity]
sys/dev/sound/midi/synth_if.m [new file with mode: 0644]
sys/dev/sound/pci/allegro_code.h [new file with mode: 0644]
sys/dev/sound/pci/allegro_reg.h [moved from sys/gnu/dev/sound/pci/maestro3_reg.h with 76% similarity]
sys/dev/sound/pci/als4000.c
sys/dev/sound/pci/als4000.h
sys/dev/sound/pci/atiixp.c
sys/dev/sound/pci/atiixp.h
sys/dev/sound/pci/au88x0.c [deleted file]
sys/dev/sound/pci/au88x0.h [deleted file]
sys/dev/sound/pci/aureal.c
sys/dev/sound/pci/aureal.h
sys/dev/sound/pci/cmi.c
sys/dev/sound/pci/cmireg.h
sys/dev/sound/pci/cs4281.c
sys/dev/sound/pci/cs4281.h
sys/dev/sound/pci/cs461x_dsp.h [new file with mode: 0644]
sys/dev/sound/pci/csa.c [deleted file]
sys/dev/sound/pci/csapcm.c [deleted file]
sys/dev/sound/pci/csareg.h [deleted file]
sys/dev/sound/pci/csavar.h [deleted file]
sys/dev/sound/pci/ds1-fw.h [deleted file]
sys/dev/sound/pci/ds1.c [deleted file]
sys/dev/sound/pci/ds1.h [deleted file]
sys/dev/sound/pci/emu10k1.c
sys/dev/sound/pci/emu10kx-midi.c [new file with mode: 0644]
sys/dev/sound/pci/emu10kx-pcm.c [new file with mode: 0644]
sys/dev/sound/pci/emu10kx.c [new file with mode: 0644]
sys/dev/sound/pci/emu10kx.h [new file with mode: 0644]
sys/dev/sound/pci/emuxkireg.h [new file with mode: 0644]
sys/dev/sound/pci/envy24.c
sys/dev/sound/pci/envy24.h
sys/dev/sound/pci/envy24ht.c
sys/dev/sound/pci/envy24ht.h
sys/dev/sound/pci/es137x.c
sys/dev/sound/pci/es137x.h
sys/dev/sound/pci/fm801.c
sys/dev/sound/pci/hda/hda_reg.h
sys/dev/sound/pci/hda/hdaa.c [new file with mode: 0644]
sys/dev/sound/pci/hda/hdaa.h [new file with mode: 0644]
sys/dev/sound/pci/hda/hdaa_patches.c [new file with mode: 0644]
sys/dev/sound/pci/hda/hdac.c
sys/dev/sound/pci/hda/hdac.h
sys/dev/sound/pci/hda/hdac_if.m [new file with mode: 0644]
sys/dev/sound/pci/hda/hdac_private.h
sys/dev/sound/pci/hda/hdac_reg.h
sys/dev/sound/pci/hda/hdacc.c [new file with mode: 0644]
sys/dev/sound/pci/hdspe-pcm.c [new file with mode: 0644]
sys/dev/sound/pci/hdspe.c [new file with mode: 0644]
sys/dev/sound/pci/hdspe.h [new file with mode: 0644]
sys/dev/sound/pci/ich.c
sys/dev/sound/pci/ich.h
sys/dev/sound/pci/maestro.c
sys/dev/sound/pci/maestro3.c [deleted file]
sys/dev/sound/pci/maestro_reg.h
sys/dev/sound/pci/neomagic-coeff.h
sys/dev/sound/pci/neomagic.c
sys/dev/sound/pci/neomagic.h
sys/dev/sound/pci/sb.h
sys/dev/sound/pci/solo.c
sys/dev/sound/pci/spicds.c
sys/dev/sound/pci/spicds.h
sys/dev/sound/pci/t4dwave.c
sys/dev/sound/pci/t4dwave.h
sys/dev/sound/pci/via8233.c
sys/dev/sound/pci/via8233.h
sys/dev/sound/pci/via82c686.c
sys/dev/sound/pci/via82c686.h
sys/dev/sound/pci/vibes.c
sys/dev/sound/pci/vibes.h
sys/dev/sound/pcm/Makefile
sys/dev/sound/pcm/ac97.c
sys/dev/sound/pcm/ac97.h
sys/dev/sound/pcm/ac97_if.m
sys/dev/sound/pcm/ac97_patch.c
sys/dev/sound/pcm/ac97_patch.h
sys/dev/sound/pcm/buffer.c
sys/dev/sound/pcm/buffer.h
sys/dev/sound/pcm/channel.c
sys/dev/sound/pcm/channel.h
sys/dev/sound/pcm/channel_if.m
sys/dev/sound/pcm/dsp.c
sys/dev/sound/pcm/dsp.h
sys/dev/sound/pcm/fake.c [deleted file]
sys/dev/sound/pcm/feeder.c
sys/dev/sound/pcm/feeder.h
sys/dev/sound/pcm/feeder_chain.c [new file with mode: 0644]
sys/dev/sound/pcm/feeder_eq.c [new file with mode: 0644]
sys/dev/sound/pcm/feeder_fmt.c [deleted file]
sys/dev/sound/pcm/feeder_format.c [new file with mode: 0644]
sys/dev/sound/pcm/feeder_if.m
sys/dev/sound/pcm/feeder_matrix.c [new file with mode: 0644]
sys/dev/sound/pcm/feeder_mixer.c [new file with mode: 0644]
sys/dev/sound/pcm/feeder_rate.c
sys/dev/sound/pcm/feeder_volume.c
sys/dev/sound/pcm/g711.h [new file with mode: 0644]
sys/dev/sound/pcm/intpcm.h [new file with mode: 0644]
sys/dev/sound/pcm/matrix.h [new file with mode: 0644]
sys/dev/sound/pcm/matrix_map.h [new file with mode: 0644]
sys/dev/sound/pcm/mixer.c
sys/dev/sound/pcm/mixer.h
sys/dev/sound/pcm/mixer_if.m
sys/dev/sound/pcm/pcm.h [new file with mode: 0644]
sys/dev/sound/pcm/sndstat.c
sys/dev/sound/pcm/sndstat.h [new file with mode: 0644]
sys/dev/sound/pcm/sound.c
sys/dev/sound/pcm/sound.h
sys/dev/sound/pcm/vchan.c
sys/dev/sound/pcm/vchan.h
sys/dev/sound/sound/Makefile [new file with mode: 0644]
sys/dev/sound/unit.c [new file with mode: 0644]
sys/dev/sound/unit.h [copied from sys/dev/sound/pcm/vchan.h with 67% similarity]
sys/dev/sound/version.h [copied from sys/dev/sound/pcm/vchan.h with 73% similarity]
sys/gnu/dev/sound/pci/csaimg.h [deleted file]
sys/gnu/dev/sound/pci/emu10k1-ac97.h [deleted file]
sys/gnu/dev/sound/pci/emu10k1-alsa.h [deleted file]
sys/gnu/dev/sound/pci/emu10k1.h [deleted file]
sys/gnu/dev/sound/pci/maestro3_dsp.h [deleted file]
sys/sys/soundcard.h
sys/tools/sound/emu10k1-mkalsa.sh [moved from sys/tools/emu10k1-mkalsa.sh with 63% similarity]
sys/tools/sound/feeder_eq_mkfilter.awk [new file with mode: 0644]
sys/tools/sound/feeder_rate_mkfilter.awk [new file with mode: 0644]
sys/tools/sound/snd_fxdiv_gen.awk [new file with mode: 0644]

index 768e086..f3ab63a 100644 (file)
@@ -2810,3 +2810,10 @@ TO_REMOVE+=/usr/share/man/man4/iwl.4.gz
 TO_REMOVE+=/boot/kernel/if_rtw.ko
 TO_REMOVE+=/usr/share/man/cat4/rtw.4.gz
 TO_REMOVE+=/usr/share/man/man4/rtw.4.gz
+
+TO_REMOVE+=/usr/share/man/man4/snd_csa.4.gz
+TO_REMOVE+=/usr/share/man/man4/csa.4.gz
+TO_REMOVE+=/usr/share/man/man4/snd_ds1.4.gz
+TO_REMOVE+=/usr/share/man/man4/ds1.4.gz
+TO_REMOVE+=/usr/share/man/man4/snd_maestro3.4.gz
+TO_REMOVE+=/usr/share/man/man4/maestro3.4.gz
index cfe399d..888fc24 100644 (file)
@@ -284,8 +284,6 @@ MAN=        aac.4 \
        snd_atiixp.4 \
        snd_cmi.4 \
        snd_cs4281.4 \
-       snd_csa.4 \
-       snd_ds1.4 \
        snd_emu10k1.4 \
        snd_envy24.4 \
        snd_envy24ht.4 \
@@ -293,7 +291,6 @@ MAN=        aac.4 \
        snd_fm801.4 \
        snd_hda.4 \
        snd_ich.4 \
-       snd_maestro3.4 \
        snd_maestro.4 \
        snd_neomagic.4 \
        snd_solo.4 \
@@ -511,8 +508,6 @@ MLINKS+=snd_als4000.4 als4000.4
 MLINKS+=snd_atiixp.4 atiixp.4
 MLINKS+=snd_cmi.4 cmi.4
 MLINKS+=snd_cs4281.4 cs4281.4
-MLINKS+=snd_csa.4 csa.4
-MLINKS+=snd_ds1.4 ds1.4
 MLINKS+=snd_emu10k1.4 emu10k1.4
 MLINKS+=snd_envy24.4 envy24.4
 MLINKS+=snd_envy24ht.4 envy24ht.4
@@ -521,7 +516,6 @@ MLINKS+=snd_fm801.4 fm801.4
 MLINKS+=snd_hda.4 hda.4
 MLINKS+=snd_ich.4 ich.4
 MLINKS+=snd_maestro.4 maestro.4
-MLINKS+=snd_maestro3.4 maestro3.4
 MLINKS+=snd_neomagic.4 neomagic.4
 MLINKS+=snd_solo.4 solo.4
 MLINKS+=snd_spicds.4 spicds.4
index 7b9f05a..59cc421 100644 (file)
@@ -281,8 +281,6 @@ A device node is not created properly.
 .Xr snd_atiixp 4 ,
 .Xr snd_cmi 4 ,
 .Xr snd_cs4281 4 ,
-.Xr snd_csa 4 ,
-.Xr snd_ds1 4 ,
 .Xr snd_emu10k1 4 ,
 .Xr snd_envy24 4 ,
 .Xr snd_envy24ht 4 ,
@@ -291,7 +289,6 @@ A device node is not created properly.
 .Xr snd_hda 4 ,
 .Xr snd_ich 4 ,
 .Xr snd_maestro 4 ,
-.Xr snd_maestro3 4 ,
 .Xr snd_neomagic 4 ,
 .Xr snd_solo 4 ,
 .Xr snd_spicds 4 ,
diff --git a/share/man/man4/snd_csa.4 b/share/man/man4/snd_csa.4
deleted file mode 100644 (file)
index f9740ae..0000000
+++ /dev/null
@@ -1,98 +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: src/share/man/man4/snd_csa.4,v 1.13.2.3 2006/06/21 04:28:05 brueffer Exp $
-.\"
-.Dd December 15, 2005
-.Dt SND_CSA 4
-.Os
-.Sh NAME
-.Nm snd_csa
-.Nd Crystal Semiconductor CS461x/462x/4280 PCI bridge device driver
-.Sh SYNOPSIS
-To compile this driver into the kernel, place the following lines in your
-kernel configuration file:
-.Bd -ragged -offset indent
-.Cd "device pcm"
-.Cd "device snd_csa"
-.Ed
-.Pp
-Alternatively, to load the driver as a module at boot time, place the
-following line in
-.Xr loader.conf 5 :
-.Bd -literal -offset indent
-snd_csa_load="YES"
-.Ed
-.Sh DESCRIPTION
-The
-.Nm
-bridge driver allows the generic audio driver
-.Xr sound 4
-to attach to Crystal Semiconductor CS461x/462x/4280 based sound cards.
-.Sh HARDWARE
-The
-.Nm
-driver supports the following sound cards:
-.Pp
-.Bl -bullet -compact
-.It
-Crystal Semiconductor CS4280
-.It
-Crystal Semiconductor CS4610
-.It
-Crystal Semiconductor CS4611
-.It
-Crystal Semiconductor CS4614
-.It
-Crystal Semiconductor CS4615
-.It
-Crystal Semiconductor CS4622
-.It
-Crystal Semiconductor CS4624
-.It
-Crystal Semiconductor CS4630
-.It
-Genius Soundmaker 128 Value
-.It
-Hercules Game Theatre XP
-.It
-Turtle Beach Santa Cruz
-.El
-.Pp
-Some onboard CS4610 chips are accompanied by the CS423x ISA codec
-instead of the CS4297 AC97 codec.
-Such configurations are not
-supported by the
-.Nm
-driver yet.
-.Sh SEE ALSO
-.Xr sound 4
-.Sh HISTORY
-The
-.Nm
-device driver first appeared in
-.Fx 4.0 .
-.Sh AUTHORS
-.An Seigo Tanimura Aq Mt tanimura@r.dl.itc.u-tokyo.ac.jp
diff --git a/share/man/man4/snd_ds1.4 b/share/man/man4/snd_ds1.4
deleted file mode 100644 (file)
index 4069718..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" Copyright (c) 2004 Atte Peltomaki
-.\" 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: src/share/man/man4/snd_ds1.4,v 1.4.2.1 2006/01/09 12:48:39 joel Exp $
-.\"
-.Dd December 15, 2005
-.Dt SND_DS1 4
-.Os
-.Sh NAME
-.Nm snd_ds1
-.Nd "Yamaha DS-1 PCI bridge device driver"
-.Sh SYNOPSIS
-To compile this driver into the kernel, place the following lines in your
-kernel configuration file:
-.Bd -ragged -offset indent
-.Cd "device pcm"
-.Cd "device snd_ds1"
-.Ed
-.Pp
-Alternatively, to load the driver as a module at boot time, place the
-following line in
-.Xr loader.conf 5 :
-.Bd -literal -offset indent
-snd_ds1_load="YES"
-.Ed
-.Sh DESCRIPTION
-The
-.Nm
-bridge driver allows the generic audio driver
-.Xr sound 4
-to attach to the Yamaha DS-1 sound card.
-.Sh HARDWARE
-The
-.Nm
-driver supports the following sound cards:
-.Pp
-.Bl -bullet -compact
-.It
-Yamaha DS-1
-.It
-Yamaha DS-1E
-.El
-.Sh SEE ALSO
-.Xr sound 4
-.Sh HISTORY
-The
-.Nm
-device driver first appeared in
-.Fx 4.1 .
-.Sh AUTHORS
-.An Cameron Grant Aq Mt cg@FreeBSD.org
index 3335821..67318e1 100644 (file)
@@ -66,7 +66,6 @@ ESS Technology Maestro-2
 ESS Technology Maestro-2E
 .El
 .Sh SEE ALSO
-.Xr snd_maestro3 4 ,
 .Xr sound 4
 .Sh HISTORY
 The
diff --git a/share/man/man4/snd_maestro3.4 b/share/man/man4/snd_maestro3.4
deleted file mode 100644 (file)
index 9bfa26b..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-.\" Copyright (c) 2001 Scott Long
-.\" 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: src/share/man/man4/snd_maestro3.4,v 1.7.2.2 2006/01/10 08:25:15 joel Exp $
-.\"
-.Dd December 15, 2005
-.Dt SND_MAESTRO3 4
-.Os
-.Sh NAME
-.Nm snd_maestro3
-.Nd "ESS Maestro3/Allegro-1 bridge device driver"
-.Sh SYNOPSIS
-To compile this driver into the kernel, place the following lines in your
-kernel configuration file:
-.Bd -ragged -offset indent
-.Cd "device pcm"
-.Cd "device snd_maestro3"
-.Ed
-.Pp
-Alternatively, to load the driver as a module at boot time, place the
-following line in
-.Xr loader.conf 5 :
-.Bd -literal -offset indent
-snd_maestro3_load="YES"
-.Ed
-.Sh DESCRIPTION
-The
-.Nm
-driver provides support for the ESS Maestro3 and Allegro-1 sound chips
-under the PCM framework.
-These chips are mostly found in laptop computers and feature an AC97 mixer,
-a multi-channel sample rate converter that can mix up to four digital audio
-streams in hardware, recording support, and external volume control buttons.
-.Pp
-The firmware for the sound processor is licensed under the GNU Public
-License, and thus this driver is not included in the default
-.Pa GENERIC
-kernel.
-.Sh HARDWARE
-The
-.Nm
-driver supports the following audio devices:
-.Pp
-.Bl -bullet -compact
-.It
-ESS Technology Allegro-1
-.It
-ESS Technology Maestro3
-.El
-.Sh DIAGNOSTICS
-The hardware volume control buttons can be connected to two different pin
-sets (GPIO or GD) on the chip, depending on the manufacturer.
-The driver has no way of determining this configuration, so a hint may be
-used to override the default guess.
-The default setting for hardware volume control assumes that GD pins
-are wired to control the hardware volume.
-.Sh SEE ALSO
-.Xr sound 4 ,
-.Xr loader.conf 5
-.Sh HISTORY
-The
-.Nm
-driver first appeared in
-.Fx 4.3 .
-.Sh AUTHORS
-.An Scott Long Aq Mt scottl@FreeBSD.org
-.An Darrel Anderson Aq Mt anderson@cs.duke.edu
index 4d92d0d..0a43ee7 100644 (file)
@@ -266,7 +266,6 @@ snd_fm801_load="NO"         # fm801
 snd_hda_load="NO"              # hda
 snd_ich_load="NO"              # Intel ICH
 snd_maestro_load="NO"          # Maestro
-snd_maestro3_load="NO"         # Maestro3
 snd_neomagic_load="NO"         # Neomagic
 snd_solo_load="NO"             # Solo
 snd_t4dwave_load="NO"          # t4dwave
index ec44041..2885525 100644 (file)
@@ -270,7 +270,6 @@ snd_fm801_load="NO"         # fm801
 snd_hda_load="NO"              # hda
 snd_ich_load="NO"              # Intel ICH
 snd_maestro_load="NO"          # Maestro
-snd_maestro3_load="NO"         # Maestro3
 snd_neomagic_load="NO"         # Neomagic
 snd_solo_load="NO"             # Solo
 snd_t4dwave_load="NO"          # t4dwave
index 8f7ed63..c578e53 100644 (file)
@@ -35,11 +35,21 @@ aic79xx_{seq.h,reg.h,reg_print.c}   optional ahd pci                   \
 aic79xx_reg_print.o            optional ahd pci ahd_reg_pretty_print   \
        compile-with    "${NORMAL_C} ${WERROR}"                 \
        no-implicit-rule local
-emu10k1-alsa%diked.h           optional snd_emu10k1 pci                           \
-       dependency      "$S/tools/emu10k1-mkalsa.sh $S/gnu/dev/sound/pci/emu10k1-alsa.h" \
-       compile-with    "CC=${CC} AWK=${AWK} sh $S/tools/emu10k1-mkalsa.sh $S/gnu/dev/sound/pci/emu10k1-alsa.h emu10k1-alsa%diked.h" \
+feeder_eq_gen.h                        optional sound                             \
+       dependency      "$S/tools/sound/feeder_eq_mkfilter.awk"            \
+       compile-with    "${AWK} -f $S/tools/sound/feeder_eq_mkfilter.awk -- ${FEEDER_EQ_PRESETS} > feeder_eq_gen.h" \
        no-obj no-implicit-rule before-depend                              \
-       clean           "emu10k1-alsa%diked.h"
+       clean           "feeder_eq_gen.h"
+feeder_rate_gen.h              optional sound                             \
+       dependency      "$S/tools/sound/feeder_rate_mkfilter.awk"          \
+       compile-with    "${AWK} -f $S/tools/sound/feeder_rate_mkfilter.awk -- ${FEEDER_RATE_PRESETS} > feeder_rate_gen.h" \
+       no-obj no-implicit-rule before-depend                              \
+       clean           "feeder_rate_gen.h"
+snd_fxdiv_gen.h                        optional sound                             \
+       dependency      "$S/tools/sound/snd_fxdiv_gen.awk"                 \
+       compile-with    "${AWK} -f $S/tools/sound/snd_fxdiv_gen.awk -- > snd_fxdiv_gen.h" \
+       no-obj no-implicit-rule before-depend                              \
+       clean           "snd_fxdiv_gen.h"
 kern/device_if.m                       standard
 kern/bus_if.m                          standard
 bus/cam/cam.c                          optional scbus
@@ -1686,23 +1696,29 @@ dev/misc/tbridge/tbridge.c      optional tbridge
 bus/isa/pnp.c                  optional isa
 bus/isa/pnpparse.c             optional isa
 #
+dev/sound/clone.c              optional sound
+dev/sound/unit.c               optional sound
 dev/sound/pci/als4000.c                optional snd_als4000 pci
 dev/sound/pci/atiixp.c         optional snd_atiixp pci
 dev/sound/pci/cmi.c            optional snd_cmi pci
 dev/sound/pci/cs4281.c         optional snd_cs4281 pci
-dev/sound/pci/csa.c            optional snd_csa pci
-dev/sound/pci/csapcm.c         optional snd_csa pci
-dev/sound/pci/ds1.c            optional snd_ds1 pci
-dev/sound/pci/emu10k1.c                optional snd_emu10k1 pci \
-       dependency "emu10k1-alsa%diked.h"
+dev/sound/pci/emu10k1.c                optional snd_emu10k1 pci
+dev/sound/pci/emu10kx.c                optional snd_emu10kx pci
+dev/sound/pci/emu10kx-pcm.c    optional snd_emu10kx pci
+dev/sound/pci/emu10kx-midi.c   optional snd_emu10kx pci
 dev/sound/pci/envy24.c         optional snd_envy24 pci
 dev/sound/pci/envy24ht.c       optional snd_envy24ht pci
 dev/sound/pci/es137x.c         optional snd_es137x pci
 dev/sound/pci/fm801.c          optional snd_fm801 pci
+dev/sound/pci/hda/hdaa.c       optional snd_hda pci
+dev/sound/pci/hda/hdaa_patches.c       optional snd_hda pci
 dev/sound/pci/hda/hdac.c       optional snd_hda pci
+dev/sound/pci/hda/hdac_if.m    optional snd_hda pci
+dev/sound/pci/hda/hdacc.c      optional snd_hda pci
+dev/sound/pci/hdspe.c          optional snd_hdspe pci
+dev/sound/pci/hdspe-pcm.c      optional snd_hdspe pci
 dev/sound/pci/ich.c            optional snd_ich pci
-dev/sound/pci/maestro.c        optional snd_maestro pci
-dev/sound/pci/maestro3.c       optional snd_maestro3 pci
+dev/sound/pci/maestro.c                optional snd_maestro pci
 dev/sound/pci/neomagic.c       optional snd_neomagic pci
 dev/sound/pci/solo.c           optional snd_solo pci
 dev/sound/pci/spicds.c         optional snd_spicds pci
@@ -1710,24 +1726,42 @@ dev/sound/pci/t4dwave.c         optional snd_t4dwave pci
 dev/sound/pci/via8233.c                optional snd_via8233 pci
 dev/sound/pci/via82c686.c      optional snd_via82c686 pci
 dev/sound/pci/vibes.c          optional snd_vibes pci
-dev/sound/pcm/ac97.c           optional pcm
-dev/sound/pcm/ac97_if.m                optional pcm
-dev/sound/pcm/ac97_patch.c     optional pcm
-dev/sound/pcm/buffer.c         optional pcm
-dev/sound/pcm/channel.c                optional pcm
-dev/sound/pcm/channel_if.m     optional pcm
-dev/sound/pcm/dsp.c            optional pcm
-dev/sound/pcm/fake.c           optional pcm
-dev/sound/pcm/feeder.c         optional pcm
-dev/sound/pcm/feeder_fmt.c     optional pcm
-dev/sound/pcm/feeder_if.m      optional pcm
-dev/sound/pcm/feeder_rate.c    optional pcm
-dev/sound/pcm/feeder_volume.c  optional pcm
-dev/sound/pcm/mixer.c          optional pcm
-dev/sound/pcm/mixer_if.m       optional pcm
-dev/sound/pcm/sndstat.c                optional pcm
-dev/sound/pcm/sound.c          optional pcm
-dev/sound/pcm/vchan.c          optional pcm
+dev/sound/pcm/ac97.c           optional sound
+dev/sound/pcm/ac97_if.m                optional sound
+dev/sound/pcm/ac97_patch.c     optional sound
+dev/sound/pcm/buffer.c         optional sound  \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/channel.c                optional sound
+dev/sound/pcm/channel_if.m     optional sound
+dev/sound/pcm/dsp.c            optional sound
+dev/sound/pcm/feeder.c         optional sound
+dev/sound/pcm/feeder_chain.c   optional sound
+dev/sound/pcm/feeder_eq.c      optional sound  \
+       dependency      "feeder_eq_gen.h"       \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/feeder_if.m      optional sound
+dev/sound/pcm/feeder_format.c  optional sound  \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/feeder_matrix.c  optional sound  \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/feeder_mixer.c   optional sound  \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/feeder_rate.c    optional sound  \
+       dependency      "feeder_rate_gen.h"     \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/feeder_volume.c  optional sound  \
+       dependency      "snd_fxdiv_gen.h"
+dev/sound/pcm/mixer.c          optional sound
+dev/sound/pcm/mixer_if.m       optional sound
+dev/sound/pcm/sndstat.c                optional sound
+dev/sound/pcm/sound.c          optional sound
+dev/sound/pcm/vchan.c          optional sound
+dev/sound/midi/midi.c          optional sound
+dev/sound/midi/mpu401.c                optional sound
+dev/sound/midi/mpu_if.m                optional sound
+dev/sound/midi/mpufoi_if.m     optional sound
+dev/sound/midi/sequencer.c     optional sound
+dev/sound/midi/synth_if.m      optional sound
 #
 # These files in libkern/ are those needed by all architectures.  Some
 # of the files in libkern/ are only needed on some architectures, e.g.,
index bbf2c93..721ec2f 100644 (file)
@@ -310,8 +310,11 @@ MFILES?= kern/bus_if.m kern/device_if.m bus/iicbus/iicbb_if.m \
     bus/ppbus/ppbus_if.m bus/smbus/smbus_if.m bus/u4b/usb_if.m \
     dev/acpica/acpi_if.m dev/acpica/acpi_wmi_if.m dev/disk/nata/ata_if.m \
     dev/disk/sdhci/sdhci_if.m \
+    dev/sound/pci/hda/hdac_if.m \
     dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \
     dev/sound/pcm/feeder_if.m dev/sound/pcm/mixer_if.m \
+    dev/sound/midi/mpu_if.m dev/sound/midi/mpufoi_if.m \
+    dev/sound/midi/synth_if.m  \
     libiconv/iconv_converter_if.m dev/agp/agp_if.m opencrypto/cryptodev_if.m \
     bus/mmc/mmcbus_if.m bus/mmc/mmcbr_if.m \
     dev/virtual/virtio/virtio/virtio_bus_if.m \
index 07bdf53..370e7bc 100644 (file)
@@ -696,6 +696,15 @@ TDMA_TXRATE_QUARTER_DEFAULT        opt_tdma.h
 TDMA_TXRATE_11NA_DEFAULT       opt_tdma.h
 TDMA_TXRATE_11NG_DEFAULT       opt_tdma.h
 
+# Sound options
+SND_DEBUG              opt_snd.h
+SND_DIAGNOSTIC         opt_snd.h
+SND_FEEDER_MULTIFORMAT opt_snd.h
+SND_FEEDER_FULL_MULTIFORMAT    opt_snd.h
+SND_FEEDER_RATE_HP     opt_snd.h
+SND_PCM_64             opt_snd.h
+SND_OLDSTEREO          opt_snd.h
+
 PANIC_REBOOT_WAIT_TIME opt_panic.h
 
 # Obsolete options (will be removed in the future)
index 3c34e4d..534c58d 100644 (file)
@@ -63,7 +63,7 @@ makeoptions   CONF_CFLAGS=-fno-builtin  #Don't allow use of memcmp, etc.
 #makeoptions   DEBUG=-g                #Build kernel with gdb(1) debug symbols
 #makeoptions   KERNEL=foo              #Build kernel "foo" and install "/foo"
 # Only build Linux API modules and plus those parts of the sound system I need.
-#makeoptions   MODULES_OVERRIDE="linux sound/snd sound/pcm sound/driver/maestro3"
+#makeoptions   MODULES_OVERRIDE="linux sound/snd sound/pcm"
 #makeoptions   INSTALLSTRIPPED=1
 #makeoptions   INSTALLSTRIPPEDMODULES=1
 
@@ -1349,8 +1349,6 @@ device            "snd_als4000"
 device         "snd_atiixp"
 device         "snd_cmi"
 device         "snd_cs4281"
-device         "snd_csa"
-device         "snd_ds1"
 device         "snd_emu10k1"
 device         "snd_envy24"
 device         "snd_envy24ht"
@@ -1359,7 +1357,6 @@ device            "snd_fm801"
 device         "snd_hda"
 device         "snd_ich"
 device         "snd_maestro"
-device         "snd_maestro3"
 device         "snd_neomagic"
 device         "snd_solo"
 device         "snd_spicds"
@@ -1368,6 +1365,8 @@ device            "snd_uaudio"
 device         "snd_via8233"
 device         "snd_via82c686"
 device         "snd_vibes"
+# USB
+#device                "snd_uaudio"
 
 #
 # Miscellaneous hardware:
index 845fd0c..34673af 100644 (file)
@@ -63,7 +63,7 @@ makeoptions   CONF_CFLAGS=-fno-builtin  #Don't allow use of memcmp, etc.
 #makeoptions   DEBUG=-g                #Build kernel with gdb(1) debug symbols
 #makeoptions   KERNEL=foo              #Build kernel "foo" and install "/foo"
 # Only build Linux API modules and plus those parts of the sound system I need.
-#makeoptions   MODULES_OVERRIDE="linux sound/snd sound/pcm sound/driver/maestro3"
+#makeoptions   MODULES_OVERRIDE="linux sound/snd sound/pcm"
 #makeoptions   INSTALLSTRIPPED=1
 #makeoptions   INSTALLSTRIPPEDMODULES=1
 
@@ -1213,23 +1213,22 @@ device          bluetooth
 #
 
 # Basic sound card support:
-device         pcm
+device         sound
 # For PCI sound cards:
 device         "snd_als4000"
 device         "snd_atiixp"
 device         "snd_cmi"
 device         "snd_cs4281"
-device         "snd_csa"
-device         "snd_ds1"
 device         "snd_emu10k1"
+device         "snd_emu10kx"
 device         "snd_envy24"
 device         "snd_envy24ht"
 device         "snd_es137x"
 device         "snd_fm801"
 device         "snd_hda"
+device         "snd_hdspe"
 device         "snd_ich"
 device         "snd_maestro"
-device         "snd_maestro3"
 device         "snd_neomagic"
 device         "snd_solo"
 device         "snd_spicds"
@@ -1238,6 +1237,15 @@ device           "snd_uaudio"
 device         "snd_via8233"
 device         "snd_via82c686"
 device         "snd_vibes"
+options                SND_DEBUG
+options                SND_DIAGNOSTIC
+options                SND_FEEDER_MULTIFORMAT
+options                SND_FEEDER_FULL_MULTIFORMAT
+options                SND_FEEDER_RATE_HP
+options                SND_PCM_64
+options                SND_OLDSTEREO
+ # USB
+#device                "snd_uaudio"
 
 #
 # Miscellaneous hardware:
index a903dc4..ae96fd4 100644 (file)
@@ -1,6 +1,7 @@
-# $FreeBSD: src/sys/modules/sound/Makefile,v 1.1.2.2 2001/02/27 04:47:48 cg Exp $
-# $DragonFly: src/sys/dev/sound/Makefile,v 1.3 2007/01/04 21:47:00 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/Makefile 132236 2004-07-16 04:00:08Z tanimura $
 
-SUBDIR = pcm driver
+SUBDIR =
+SUBDIR += sound
+SUBDIR += driver
 
 .include <bsd.subdir.mk>
index 9adcbcf..2632659 100644 (file)
@@ -1,4 +1,3 @@
-# $FreeBSD: src/sys/modules/sound/Makefile.inc,v 1.1.2.1 2000/09/23 19:15:00 cg Exp $
-# $DragonFly: src/sys/dev/sound/Makefile.inc,v 1.3 2003/08/15 08:32:31 dillon Exp $
+# $FreeBSD: head/sys/modules/sound/Makefile.inc 62598 2000-07-04 23:32:15Z cg $
 
 #.include "../Makefile.inc"
index 43af963..1d930d5 100644 (file)
@@ -23,8 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/sound/chip.h,v 1.2 2000/01/03 02:51:14 tanimura Exp $
- * $DragonFly: src/sys/dev/sound/chip.h,v 1.2 2003/06/17 04:28:30 dillon Exp $
+ * $FreeBSD: head/sys/dev/sound/chip.h 55320 2000-01-03 02:51:16Z tanimura $
  */
 
 /*
diff --git a/sys/dev/sound/clone.c b/sys/dev/sound/clone.c
new file mode 100644 (file)
index 0000000..598dff0
--- /dev/null
@@ -0,0 +1,799 @@
+/*-
+ * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
+ * 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: head/sys/dev/sound/clone.c 193640 2009-06-07 19:12:08Z ariff $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
+#include <dev/sound/pcm/sound.h>
+#endif
+
+#include <dev/sound/clone.h>
+
+/*
+ * So here we go again, another clonedevs manager. Unlike default clonedevs,
+ * this clone manager is designed to withstand various abusive behavior
+ * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object
+ * after reaching certain expiration threshold, aggressive garbage collector,
+ * transparent device allocator and concurrency handling across multiple
+ * thread/proc. Due to limited information given by dev_clone EVENTHANDLER,
+ * we don't have much clues whether the caller wants a real open() or simply
+ * making fun of us with things like stat(), mtime() etc. Assuming that:
+ * 1) Time window between dev_clone EH <-> real open() should be small
+ * enough and 2) mtime()/stat() etc. always looks like a half way / stalled
+ * operation, we can decide whether a new cdev must be created, old
+ * (expired) cdev can be reused or an existing cdev can be shared.
+ *
+ * Most of the operations and logics are generic enough and can be applied
+ * on other places (such as if_tap, snp, etc).  Perhaps this can be
+ * rearranged to complement clone_*(). However, due to this still being
+ * specific to the sound driver (and as a proof of concept on how it can be
+ * done), si_drv2 is used to keep the pointer of the clone list entry to
+ * avoid expensive lookup.
+ */
+
+/* clone entry */
+struct snd_clone_entry {
+       TAILQ_ENTRY(snd_clone_entry) link;
+       struct snd_clone *parent;
+       struct cdev *devt;
+       struct timespec tsp;
+       uint32_t flags;
+       pid_t pid;
+       int unit;
+};
+
+/* clone manager */
+struct snd_clone {
+       TAILQ_HEAD(link_head, snd_clone_entry) head;
+       struct timespec tsp;
+       int refcount;
+       int size;
+       int typemask;
+       int maxunit;
+       int deadline;
+       uint32_t flags;
+};
+
+#ifdef SND_DIAGNOSTIC
+#define SND_CLONE_ASSERT(x, y)         do {                    \
+       if (!(x))                                               \
+               panic y;                                        \
+} while (0)
+#else
+#define SND_CLONE_ASSERT(...)          KASSERT(__VA_ARGS__)
+#endif
+
+/*
+ * Shamelessly ripped off from vfs_subr.c
+ * We need at least 1/HZ precision as default timestamping.
+ */
+enum { SND_TSP_SEC, SND_TSP_HZ, SND_TSP_USEC, SND_TSP_NSEC };
+
+static int snd_timestamp_precision = SND_TSP_HZ;
+TUNABLE_INT("hw.snd.timestamp_precision", &snd_timestamp_precision);
+
+void
+snd_timestamp(struct timespec *tsp)
+{
+       struct timeval tv;
+
+       switch (snd_timestamp_precision) {
+       case SND_TSP_SEC:
+               tsp->tv_sec = time_second;
+               tsp->tv_nsec = 0;
+               break;
+       case SND_TSP_HZ:
+               getnanouptime(tsp);
+               break;
+       case SND_TSP_USEC:
+               microuptime(&tv);
+               TIMEVAL_TO_TIMESPEC(&tv, tsp);
+               break;
+       case SND_TSP_NSEC:
+               nanouptime(tsp);
+               break;
+       default:
+               snd_timestamp_precision = SND_TSP_HZ;
+               getnanouptime(tsp);
+               break;
+       }
+}
+
+#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
+static int
+sysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS)
+{
+       int err, val;
+
+       val = snd_timestamp_precision;
+       err = sysctl_handle_int(oidp, &val, 0, req);
+       if (err == 0 && req->newptr != NULL) {
+               switch (val) {
+               case SND_TSP_SEC:
+               case SND_TSP_HZ:
+               case SND_TSP_USEC:
+               case SND_TSP_NSEC:
+                       snd_timestamp_precision = val;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return (err);
+}
+SYSCTL_PROC(_hw_snd, OID_AUTO, timestamp_precision, CTLTYPE_INT | CTLFLAG_RW,
+    0, sizeof(int), sysctl_hw_snd_timestamp_precision, "I",
+    "timestamp precision (0=s 1=hz 2=us 3=ns)");
+#endif
+
+/*
+ * snd_clone_create() : Return opaque allocated clone manager.
+ */
+struct snd_clone *
+snd_clone_create(int typemask, int maxunit, int deadline, uint32_t flags)
+{
+       struct snd_clone *c;
+
+       SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT),
+           ("invalid typemask: 0x%08x", typemask));
+       SND_CLONE_ASSERT(maxunit == -1 ||
+           !(maxunit & ~(~typemask & SND_CLONE_MAXUNIT)),
+           ("maxunit overflow: typemask=0x%08x maxunit=%d",
+           typemask, maxunit));
+       SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
+           ("invalid clone flags=0x%08x", flags));
+
+       c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
+       c->refcount = 0;
+       c->size = 0;
+       c->typemask = typemask;
+       c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) :
+           maxunit;
+       c->deadline = deadline;
+       c->flags = flags;
+       snd_timestamp(&c->tsp);
+       TAILQ_INIT(&c->head);
+
+       return (c);
+}
+
+int
+snd_clone_busy(struct snd_clone *c)
+{
+       struct snd_clone_entry *ce;
+
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       if (c->size == 0)
+               return (0);
+
+       TAILQ_FOREACH(ce, &c->head, link) {
+               if ((ce->flags & SND_CLONE_BUSY) ||
+                   (ce->devt != NULL && ce->devt->si_threadcount != 0))
+                       return (EBUSY);
+       }
+
+       return (0);
+}
+
+/*
+ * snd_clone_enable()/disable() : Suspend/resume clone allocation through
+ * snd_clone_alloc(). Everything else will not be affected by this.
+ */
+int
+snd_clone_enable(struct snd_clone *c)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       if (c->flags & SND_CLONE_ENABLE)
+               return (EINVAL);
+
+       c->flags |= SND_CLONE_ENABLE;
+
+       return (0);
+}
+
+int
+snd_clone_disable(struct snd_clone *c)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       if (!(c->flags & SND_CLONE_ENABLE))
+               return (EINVAL);
+
+       c->flags &= ~SND_CLONE_ENABLE;
+
+       return (0);
+}
+
+/*
+ * Getters / Setters. Not worth explaining :)
+ */
+int
+snd_clone_getsize(struct snd_clone *c)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       return (c->size);
+}
+
+int
+snd_clone_getmaxunit(struct snd_clone *c)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       return (c->maxunit);
+}
+
+int
+snd_clone_setmaxunit(struct snd_clone *c, int maxunit)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+       SND_CLONE_ASSERT(maxunit == -1 ||
+           !(maxunit & ~(~c->typemask & SND_CLONE_MAXUNIT)),
+           ("maxunit overflow: typemask=0x%08x maxunit=%d",
+           c->typemask, maxunit));
+
+       c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) :
+           maxunit;
+
+       return (c->maxunit);
+}
+
+int
+snd_clone_getdeadline(struct snd_clone *c)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       return (c->deadline);
+}
+
+int
+snd_clone_setdeadline(struct snd_clone *c, int deadline)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       c->deadline = deadline;
+
+       return (c->deadline);
+}
+
+int
+snd_clone_gettime(struct snd_clone *c, struct timespec *tsp)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+       SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
+
+       *tsp = c->tsp;
+
+       return (0);
+}
+
+uint32_t
+snd_clone_getflags(struct snd_clone *c)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       return (c->flags);
+}
+
+uint32_t
+snd_clone_setflags(struct snd_clone *c, uint32_t flags)
+{
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+       SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
+           ("invalid clone flags=0x%08x", flags));
+
+       c->flags = flags;
+
+       return (c->flags);
+}
+
+int
+snd_clone_getdevtime(struct cdev *dev, struct timespec *tsp)
+{
+       struct snd_clone_entry *ce;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+       SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (ENODEV);
+
+       SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
+
+       *tsp = ce->tsp;
+
+       return (0);
+}
+
+uint32_t
+snd_clone_getdevflags(struct cdev *dev)
+{
+       struct snd_clone_entry *ce;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (0xffffffff);
+
+       SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
+
+       return (ce->flags);
+}
+
+uint32_t
+snd_clone_setdevflags(struct cdev *dev, uint32_t flags)
+{
+       struct snd_clone_entry *ce;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+       SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK),
+           ("invalid clone dev flags=0x%08x", flags));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (0xffffffff);
+
+       SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
+
+       ce->flags = flags;
+
+       return (ce->flags);
+}
+
+/* Elapsed time conversion to ms */
+#define SND_CLONE_ELAPSED(x, y)                                                \
+       ((((x)->tv_sec - (y)->tv_sec) * 1000) +                         \
+       (((y)->tv_nsec > (x)->tv_nsec) ?                                \
+       (((1000000000L + (x)->tv_nsec -                                 \
+       (y)->tv_nsec) / 1000000) - 1000) :                              \
+       (((x)->tv_nsec - (y)->tv_nsec) / 1000000)))
+
+#define SND_CLONE_EXPIRED(x, y, z)                                     \
+       ((x)->deadline < 1 ||                                           \
+       ((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) ||         \
+       SND_CLONE_ELAPSED(y, z) > (x)->deadline)
+
+/*
+ * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to
+ * clone.h for explanations on GC settings.
+ */
+int
+snd_clone_gc(struct snd_clone *c)
+{
+       struct snd_clone_entry *ce, *tce;
+       struct timespec now;
+       int pruned;
+
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0)
+               return (0);
+
+       snd_timestamp(&now);
+
+       /*
+        * Bail out if the last clone handler was invoked below the deadline
+        * threshold.
+        */
+       if ((c->flags & SND_CLONE_GC_EXPIRED) &&
+           !SND_CLONE_EXPIRED(c, &now, &c->tsp))
+               return (0);
+
+       pruned = 0;
+
+       /*
+        * Visit each object in reverse order. If the object is still being
+        * referenced by a valid open(), skip it. Look for expired objects
+        * and either revoke its clone invocation status or mercilessly
+        * throw it away.
+        */
+       TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) {
+               if (!(ce->flags & SND_CLONE_BUSY) &&
+                   (!(ce->flags & SND_CLONE_INVOKE) ||
+                   SND_CLONE_EXPIRED(c, &now, &ce->tsp))) {
+                       if ((c->flags & SND_CLONE_GC_REVOKE) ||
+                           ce->devt->si_threadcount != 0) {
+                               ce->flags &= ~SND_CLONE_INVOKE;
+                               ce->pid = -1;
+                       } else {
+                               TAILQ_REMOVE(&c->head, ce, link);
+                               destroy_dev(ce->devt);
+                               free(ce, M_DEVBUF);
+                               c->size--;
+                       }
+                       pruned++;
+               }
+       }
+
+       /* return total pruned objects */
+       return (pruned);
+}
+
+void
+snd_clone_destroy(struct snd_clone *c)
+{
+       struct snd_clone_entry *ce, *tmp;
+
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+
+       ce = TAILQ_FIRST(&c->head);
+       while (ce != NULL) {
+               tmp = TAILQ_NEXT(ce, link);
+               if (ce->devt != NULL)
+                       destroy_dev(ce->devt);
+               free(ce, M_DEVBUF);
+               ce = tmp;
+       }
+
+       free(c, M_DEVBUF);
+}
+
+/*
+ * snd_clone_acquire() : The vital part of concurrency management. Must be
+ * called somewhere at the beginning of open() handler. ENODEV is not really
+ * fatal since it just tell the caller that this is not cloned stuff.
+ * EBUSY is *real*, don't forget that!
+ */
+int
+snd_clone_acquire(struct cdev *dev)
+{
+       struct snd_clone_entry *ce;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (ENODEV);
+
+       SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
+
+       ce->flags &= ~SND_CLONE_INVOKE;
+
+       if (ce->flags & SND_CLONE_BUSY)
+               return (EBUSY);
+
+       ce->flags |= SND_CLONE_BUSY;
+
+       return (0);
+}
+
+/*
+ * snd_clone_release() : Release busy status. Must be called somewhere at
+ * the end of close() handler, or somewhere after fail open().
+ */
+int
+snd_clone_release(struct cdev *dev)
+{
+       struct snd_clone_entry *ce;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (ENODEV);
+
+       SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
+
+       ce->flags &= ~SND_CLONE_INVOKE;
+
+       if (!(ce->flags & SND_CLONE_BUSY))
+               return (EBADF);
+
+       ce->flags &= ~SND_CLONE_BUSY;
+       ce->pid = -1;
+
+       return (0);
+}
+
+/*
+ * snd_clone_ref/unref() : Garbage collector reference counter. To make
+ * garbage collector run automatically, the sequence must be something like
+ * this (both in open() and close() handlers):
+ *
+ *  open() - 1) snd_clone_acquire()
+ *           2) .... check check ... if failed, snd_clone_release()
+ *           3) Success. Call snd_clone_ref()
+ *
+ * close() - 1) .... check check check ....
+ *           2) Success. snd_clone_release()
+ *           3) snd_clone_unref() . Garbage collector will run at this point
+ *              if this is the last referenced object.
+ */
+int
+snd_clone_ref(struct cdev *dev)
+{
+       struct snd_clone_entry *ce;
+       struct snd_clone *c;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (0);
+
+       c = ce->parent;
+       SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
+       SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0"));
+
+       return (++c->refcount);
+}
+
+int
+snd_clone_unref(struct cdev *dev)
+{
+       struct snd_clone_entry *ce;
+       struct snd_clone *c;
+
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+
+       ce = dev->si_drv2;
+       if (ce == NULL)
+               return (0);
+
+       c = ce->parent;
+       SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
+       SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0"));
+
+       c->refcount--;
+
+       /* 
+        * Run automatic garbage collector, if needed.
+        */
+       if ((c->flags & SND_CLONE_GC_UNREF) &&
+           (!(c->flags & SND_CLONE_GC_LASTREF) ||
+           (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
+               (void)snd_clone_gc(c);
+
+       return (c->refcount);
+}
+
+void
+snd_clone_register(struct snd_clone_entry *ce, struct cdev *dev)
+{
+       SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry"));
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
+       SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL"));
+       SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC,
+           ("invalid clone alloc flags=0x%08x", ce->flags));
+       SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL"));
+       SND_CLONE_ASSERT(ce->unit == dev2unit(dev),
+           ("invalid unit ce->unit=0x%08x dev2unit=0x%08x",
+           ce->unit, dev2unit(dev)));
+
+       SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
+
+       dev->si_drv2 = ce;
+       ce->devt = dev;
+       ce->flags &= ~SND_CLONE_ALLOC;
+       ce->flags |= SND_CLONE_INVOKE;
+}
+
+struct snd_clone_entry *
+snd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask)
+{
+       struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce;
+       struct timespec now;
+       int cunit, allocunit;
+       pid_t curpid;
+
+       SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
+       SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer"));
+       SND_CLONE_ASSERT((c->typemask & tmask) == tmask,
+           ("invalid tmask: typemask=0x%08x tmask=0x%08x",
+           c->typemask, tmask));
+       SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer"));
+       SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)),
+           ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d",
+           c->typemask, tmask, *unit));
+
+       if (!(c->flags & SND_CLONE_ENABLE) ||
+           (*unit != -1 && *unit > c->maxunit))
+               return (NULL);
+
+       ce = NULL;
+       after = NULL;
+       bce = NULL;     /* "b"usy candidate */
+       cce = NULL;     /* "c"urthread/proc candidate */
+       nce = NULL;     /* "n"ull, totally unbusy candidate */
+       tce = NULL;     /* Last "t"ry candidate */
+       cunit = 0;
+       allocunit = (*unit == -1) ? 0 : *unit;
+       curpid = curthread->td_proc->p_pid;
+
+       snd_timestamp(&now);
+
+       TAILQ_FOREACH(ce, &c->head, link) {
+               /*
+                * Sort incrementally according to device type.
+                */
+               if (tmask > (ce->unit & c->typemask)) {
+                       if (cunit == 0)
+                               after = ce;
+                       continue;
+               } else if (tmask < (ce->unit & c->typemask))
+                       break;
+
+               /*
+                * Shoot.. this is where the grumpiness begin. Just
+                * return immediately.
+                */
+               if (*unit != -1 && *unit == (ce->unit & ~tmask))
+                       goto snd_clone_alloc_out;
+
+               cunit++;
+               /*
+                * Simmilar device type. Sort incrementally according
+                * to allocation unit. While here, look for free slot
+                * and possible collision for new / future allocation.
+                */
+               if (*unit == -1 && (ce->unit & ~tmask) == allocunit)
+                       allocunit++;
+               if ((ce->unit & ~tmask) < allocunit)
+                       after = ce;
+               /*
+                * Clone logic:
+                *   1. Look for non busy, but keep track of the best
+                *      possible busy cdev.
+                *   2. Look for the best (oldest referenced) entry that is
+                *      in a same process / thread.
+                *   3. Look for the best (oldest referenced), absolute free
+                *      entry.
+                *   4. Lastly, look for the best (oldest referenced)
+                *      any entries that doesn't fit with anything above.
+                */
+               if (ce->flags & SND_CLONE_BUSY) {
+                       if (ce->devt != NULL && (bce == NULL ||
+                           timespeccmp(&ce->tsp, &bce->tsp, <)))
+                               bce = ce;
+                       continue;
+               }
+               if (ce->pid == curpid &&
+                   (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <)))
+                       cce = ce;
+               else if (!(ce->flags & SND_CLONE_INVOKE) &&
+                   (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <)))
+                       nce = ce;
+               else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <))
+                       tce = ce;
+       }
+       if (*unit != -1)
+               goto snd_clone_alloc_new;
+       else if (cce != NULL) {
+               /* Same proc entry found, go for it */
+               ce = cce;
+               goto snd_clone_alloc_out;
+       } else if (nce != NULL) {
+               /*
+                * Next, try absolute free entry. If the calculated
+                * allocunit is smaller, create new entry instead.
+                */
+               if (allocunit < (nce->unit & ~tmask))
+                       goto snd_clone_alloc_new;
+               ce = nce;
+               goto snd_clone_alloc_out;
+       } else if (allocunit > c->maxunit) {
+               /*
+                * Maximum allowable unit reached. Try returning any
+                * available cdev and hope for the best. If the lookup is
+                * done for things like stat(), mtime() etc. , things should
+                * be ok. Otherwise, open() handler should do further checks
+                * and decide whether to return correct error code or not.
+                */
+               if (tce != NULL) {
+                       ce = tce;
+                       goto snd_clone_alloc_out;
+               } else if (bce != NULL) {
+                       ce = bce;
+                       goto snd_clone_alloc_out;
+               }
+               return (NULL);
+       }
+
+snd_clone_alloc_new:
+       /*
+        * No free entries found, and we still haven't reached maximum
+        * allowable units. Allocate, setup a minimal unique entry with busy
+        * status so nobody will monkey on this new entry. Unit magic is set
+        * right here to avoid collision with other contesting handler.
+        * The caller must be carefull here to maintain its own
+        * synchronization, as long as it will not conflict with malloc(9)
+        * operations.
+        *
+        * That said, go figure.
+        */
+       ce = malloc(sizeof(*ce), M_DEVBUF,
+           ((c->flags & SND_CLONE_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO);
+       if (ce == NULL) {
+               if (*unit != -1)
+                       return (NULL);
+               /*
+                * We're being dense, ignorance is bliss,
+                * Super Regulatory Measure (TM).. TRY AGAIN!
+                */
+               if (nce != NULL) {
+                       ce = nce;
+                       goto snd_clone_alloc_out;
+               } else if (tce != NULL) {
+                       ce = tce;
+                       goto snd_clone_alloc_out;
+               } else if (bce != NULL) {
+                       ce = bce;
+                       goto snd_clone_alloc_out;
+               }
+               return (NULL);
+       }
+       /* Setup new entry */
+       ce->parent = c;
+       ce->unit = tmask | allocunit;
+       ce->pid = curpid;
+       ce->tsp = now;
+       ce->flags |= SND_CLONE_ALLOC;
+       if (after != NULL) {
+               TAILQ_INSERT_AFTER(&c->head, after, ce, link);
+       } else {
+               TAILQ_INSERT_HEAD(&c->head, ce, link);
+       }
+       c->size++;
+       c->tsp = now;
+       /*
+        * Save new allocation unit for caller which will be used
+        * by make_dev().
+        */
+       *unit = allocunit;
+
+       return (ce);
+
+snd_clone_alloc_out:
+       /*
+        * Set, mark, timestamp the entry if this is a truly free entry.
+        * Leave busy entry alone.
+        */
+       if (!(ce->flags & SND_CLONE_BUSY)) {
+               ce->pid = curpid;
+               ce->tsp = now;
+               ce->flags |= SND_CLONE_INVOKE;
+       }
+       c->tsp = now;
+       *dev = ce->devt;
+
+       return (NULL);
+}
diff --git a/sys/dev/sound/clone.h b/sys/dev/sound/clone.h
new file mode 100644 (file)
index 0000000..3e9bfb6
--- /dev/null
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
+ * 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: head/sys/dev/sound/clone.h 170719 2007-06-14 11:10:21Z ariff $
+ */
+
+#ifndef _SND_CLONE_H_
+#define _SND_CLONE_H_
+
+struct snd_clone_entry;
+struct snd_clone;
+
+/*
+ * 750 milisecond default deadline. Short enough to not cause excessive
+ * garbage collection, long enough to indicate stalled VFS.
+ */
+#define SND_CLONE_DEADLINE_DEFAULT     750
+
+/*
+ * Fit within 24bit MAXMINOR.
+ */
+#define SND_CLONE_MAXUNIT              0xffffff
+
+/*
+ * Creation flags, mostly related to the behaviour of garbage collector.
+ *
+ * SND_CLONE_ENABLE     - Enable clone allocation.
+ * SND_CLONE_GC_ENABLE  - Enable garbage collector operation, automatically
+ *                        or if explicitly called upon.
+ * SND_CLONE_GC_UNREF   - Garbage collect during unref operation.
+ * SND_CLONE_GC_LASTREF - Garbage collect during last reference
+ *                        (refcount = 0)
+ * SND_CLONE_GC_EXPIRED - Don't garbage collect unless the global clone
+ *                        handler has been expired.
+ * SND_CLONE_GC_REVOKE  - Revoke clone invocation status which has been
+ *                        expired instead of removing and freeing it.
+ * SND_CLONE_WAITOK     - malloc() is allowed to sleep while allocating
+ *                        clone entry.
+ */
+#define SND_CLONE_ENABLE       0x00000001
+#define SND_CLONE_GC_ENABLE    0x00000002
+#define SND_CLONE_GC_UNREF     0x00000004
+#define SND_CLONE_GC_LASTREF   0x00000008
+#define SND_CLONE_GC_EXPIRED   0x00000010
+#define SND_CLONE_GC_REVOKE    0x00000020
+#define SND_CLONE_WAITOK       0x80000000
+
+#define SND_CLONE_GC_MASK      (SND_CLONE_GC_ENABLE  |                 \
+                                SND_CLONE_GC_UNREF   |                 \
+                                SND_CLONE_GC_LASTREF |                 \
+                                SND_CLONE_GC_EXPIRED |                 \
+                                SND_CLONE_GC_REVOKE)
+
+#define SND_CLONE_MASK         (SND_CLONE_ENABLE | SND_CLONE_GC_MASK | \
+                                SND_CLONE_WAITOK)
+
+/*
+ * Runtime clone device flags
+ *
+ * These are mostly private to the clone manager operation:
+ *
+ * SND_CLONE_NEW    - New clone allocation in progress.
+ * SND_CLONE_INVOKE - Cloning being invoked, waiting for next VFS operation.
+ * SND_CLONE_BUSY   - In progress, being referenced by living thread/proc.
+ */
+#define SND_CLONE_NEW          0x00000001
+#define SND_CLONE_INVOKE       0x00000002
+#define SND_CLONE_BUSY         0x00000004
+
+/*
+ * Nothing important, just for convenience.
+ */
+#define SND_CLONE_ALLOC                (SND_CLONE_NEW | SND_CLONE_INVOKE |     \
+                                SND_CLONE_BUSY)
+
+#define SND_CLONE_DEVMASK      SND_CLONE_ALLOC
+
+
+void snd_timestamp(struct timespec *);
+
+struct snd_clone *snd_clone_create(int, int, int, uint32_t);
+int snd_clone_busy(struct snd_clone *);
+int snd_clone_enable(struct snd_clone *);
+int snd_clone_disable(struct snd_clone *);
+int snd_clone_getsize(struct snd_clone *);
+int snd_clone_getmaxunit(struct snd_clone *);
+int snd_clone_setmaxunit(struct snd_clone *, int);
+int snd_clone_getdeadline(struct snd_clone *);
+int snd_clone_setdeadline(struct snd_clone *, int);
+int snd_clone_gettime(struct snd_clone *, struct timespec *);
+uint32_t snd_clone_getflags(struct snd_clone *);
+uint32_t snd_clone_setflags(struct snd_clone *, uint32_t);
+int snd_clone_getdevtime(struct cdev *, struct timespec *);
+uint32_t snd_clone_getdevflags(struct cdev *);
+uint32_t snd_clone_setdevflags(struct cdev *, uint32_t);
+int snd_clone_gc(struct snd_clone *);
+void snd_clone_destroy(struct snd_clone *);
+int snd_clone_acquire(struct cdev *);
+int snd_clone_release(struct cdev *);
+int snd_clone_ref(struct cdev *);
+int snd_clone_unref(struct cdev *);
+void snd_clone_register(struct snd_clone_entry *, struct cdev *);
+struct snd_clone_entry *snd_clone_alloc(struct snd_clone *, struct cdev **,
+    int *, int);
+
+#define snd_clone_enabled(x)   ((x) != NULL &&                         \
+                               (snd_clone_getflags(x) & SND_CLONE_ENABLE))
+#define snd_clone_disabled(x)  (!snd_clone_enabled(x))
+
+#endif /* !_SND_CLONE_H */
index 9deb383..5869b20 100644 (file)
  * 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, WHETHERIN CONTRACT, STRICT
+ * 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 THEPOSSIBILITY OF
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/sound/driver.c,v 1.13.2.3 2007/05/13 21:11:40 ariff Exp $
+ * $FreeBSD: head/sys/dev/sound/driver.c 193640 2009-06-07 19:12:08Z ariff $
  */
 
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
 #include <dev/sound/pcm/sound.h>
 
 static int
@@ -38,7 +42,7 @@ snd_modevent(module_t mod, int type, void *data)
        case MOD_UNLOAD:
                break;
        default:
-               return (EOPNOTSUPP);
+               return (ENOTSUP);
                break;
        }
        return 0;
@@ -57,10 +61,7 @@ MODULE_DEPEND(snd_driver, snd_atiixp, 1, 1, 1);
 /* MODULE_DEPEND(snd_driver, snd_aureal, 1, 1, 1); */
 MODULE_DEPEND(snd_driver, snd_cmi, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_cs4281, 1, 1, 1);
-MODULE_DEPEND(snd_driver, snd_csa, 1, 1, 1);
-/* MODULE_DEPEND(snd_driver, snd_csapcm, 1, 1, 1); in csa */
-MODULE_DEPEND(snd_driver, snd_ds1, 1, 1, 1);
-MODULE_DEPEND(snd_driver, snd_emu10k1, 1, 1, 1);
+MODULE_DEPEND(snd_driver, snd_emu10kx, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_envy24, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_envy24ht, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_es137x, 1, 1, 1);
@@ -68,7 +69,6 @@ MODULE_DEPEND(snd_driver, snd_fm801, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_hda, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_ich, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_maestro, 1, 1, 1);
-MODULE_DEPEND(snd_driver, snd_maestro3, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_neomagic, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_solo, 1, 1, 1);
 MODULE_DEPEND(snd_driver, snd_spicds, 1, 1, 1);
index bded3b4..ad5f2da 100644 (file)
@@ -1,7 +1,7 @@
-# $FreeBSD: src/sys/modules/sound/driver/Makefile,v 1.16.2.2 2007/05/13 21:11:40 ariff Exp $
+# $FreeBSD: head/sys/modules/sound/driver/Makefile 232337 2012-03-01 13:10:18Z mav $
 
-SUBDIR  = als4000 atiixp cmi cs4281 csa ds1 emu10k1 envy24
-SUBDIR += envy24ht es137x fm801 hda ich maestro maestro3 neomagic
+SUBDIR  = als4000 atiixp cmi cs4281 emu10k1 emu10kx envy24
+SUBDIR += envy24ht es137x fm801 hda hdspe ich maestro neomagic
 SUBDIR += solo spicds t4dwave via8233 via82c686 vibes
 SUBDIR += driver
 
index b92aa03..55c4aaa 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/Makefile.inc,v 1.3 2001/04/08 21:50:41 obrien Exp $
-# $DragonFly: src/sys/dev/sound/driver/Makefile.inc,v 1.5 2007/01/04 21:47:00 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/Makefile.inc 75325 2001-04-08 21:50:41Z obrien $
 
 SRCS+= ac97_if.h channel_if.h feeder_if.h mixer_if.h
 
index fbcc320..c3366b8 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/als4000/Makefile,v 1.2 2003/02/07 13:56:31 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/als4000/Makefile,v 1.3 2007/01/04 21:47:00 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/als4000/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index 5a48fe6..0d5d96c 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/atiixp/Makefile,v 1.1.2.1 2005/12/30 19:55:55 netchild Exp $
-# $DragonFly: src/sys/dev/sound/driver/atiixp/Makefile,v 1.1 2007/01/04 21:47:00 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/atiixp/Makefile 152851 2005-11-27 03:29:59Z ariff $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
diff --git a/sys/dev/sound/driver/au88x0/Makefile b/sys/dev/sound/driver/au88x0/Makefile
deleted file mode 100644 (file)
index d74e9ef..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# $FreeBSD: src/sys/modules/sound/driver/au88x0/Makefile,v 1.1 2003/06/01 11:58:46 des Exp $
-# $DragonFly: src/sys/dev/sound/driver/au88x0/Makefile,v 1.1 2007/01/04 21:47:00 corecode Exp $
-
-.PATH: ${.CURDIR}/../../../../dev/sound/pci
-
-KMOD=  snd_au88x0
-SRCS=  device_if.h bus_if.h pci_if.h
-SRCS+= au88x0.c
-
-.include <bsd.kmod.mk>
diff --git a/sys/dev/sound/driver/audiocs/Makefile b/sys/dev/sound/driver/audiocs/Makefile
deleted file mode 100644 (file)
index 4244337..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# $FreeBSD: src/sys/modules/sound/driver/audiocs/Makefile,v 1.1 2004/10/25 10:29:57 yongari Exp $
-# $DragonFly: src/sys/dev/sound/driver/audiocs/Makefile,v 1.1 2007/01/04 21:47:00 corecode Exp $
-
-.PATH: ${.CURDIR}/../../../../dev/sound/sbus
-
-KMOD=  snd_audiocs
-SRCS=  device_if.h bus_if.h ofw_bus_if.h
-SRCS+= channel_if.h feeder_if.h mixer_if.h
-SRCS+= cs4231.c
-
-.include <bsd.kmod.mk>
index 9365540..f06f4eb 100644 (file)
@@ -1,10 +1,10 @@
-# $FreeBSD: src/sys/modules/sound/driver/cmi/Makefile,v 1.3 2003/02/07 13:56:31 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/cmi/Makefile,v 1.3 2007/01/04 21:47:00 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/cmi/Makefile 158979 2006-05-27 16:32:05Z netchild $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
 KMOD=  snd_cmi
 SRCS=  device_if.h bus_if.h pci_if.h
+SRCS+= mpufoi_if.h
 SRCS+= cmi.c
 
 .include <bsd.kmod.mk>
index b794437..732bd07 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/cs4281/Makefile,v 1.3 2003/02/07 13:56:31 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/cs4281/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/cs4281/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
diff --git a/sys/dev/sound/driver/csa/Makefile b/sys/dev/sound/driver/csa/Makefile
deleted file mode 100644 (file)
index 95abe12..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# $FreeBSD: src/sys/modules/sound/driver/csa/Makefile,v 1.4 2003/02/07 13:56:31 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/csa/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
-
-.PATH: ${.CURDIR}/../../../../dev/sound/pci
-
-KMOD=  snd_csa
-SRCS=  device_if.h bus_if.h pci_if.h
-SRCS+= csa.c csapcm.c
-
-.include <bsd.kmod.mk>
index 2972582..c167dd8 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/driver/Makefile,v 1.4 2003/02/07 15:05:37 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/driver/Makefile,v 1.1 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/driver/Makefile 110502 2003-02-07 15:05:37Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound
 
diff --git a/sys/dev/sound/driver/ds1/Makefile b/sys/dev/sound/driver/ds1/Makefile
deleted file mode 100644 (file)
index 8851efb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# $FreeBSD: src/sys/modules/sound/driver/ds1/Makefile,v 1.3 2003/02/07 13:56:31 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/ds1/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
-
-.PATH: ${.CURDIR}/../../../../dev/sound/pci
-
-KMOD=  snd_ds1
-SRCS=  device_if.h bus_if.h pci_if.h
-SRCS+= ds1.c
-
-.include <bsd.kmod.mk>
index 98f5922..8daef6f 100644 (file)
@@ -1,18 +1,10 @@
-# $FreeBSD: src/sys/modules/sound/driver/emu10k1/Makefile,v 1.4 2004/01/11 10:30:56 obrien Exp $
+# $FreeBSD: head/sys/modules/sound/driver/emu10k1/Makefile 230915 2012-02-02 17:25:39Z joel $
 
-.PATH: ${.CURDIR}/../../pci \
-       ${.CURDIR}/../../../../gnu/dev/sound/pci
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
 
 KMOD=  snd_emu10k1
-SRCS=  device_if.h bus_if.h pci_if.h emu10k1-alsa%diked.h
+SRCS=  device_if.h bus_if.h pci_if.h
+SRCS+= mpufoi_if.h
 SRCS+= emu10k1.c
 
-CLEANFILES+= emu10k1-alsa%diked.h
-
-emu10k1-alsa%diked.h: emu10k1-alsa.h
-       grep -v '#include' ${.OODATE} | $(CC) -E -D__KERNEL__ -dM - \
-           | awk -F"[  (]" '/define/ \
-           { print "#ifndef " $$2 ; print ; print "#endif" }' \
-           >${.TARGET}
-
 .include <bsd.kmod.mk>
diff --git a/sys/dev/sound/driver/emu10kx/Makefile b/sys/dev/sound/driver/emu10kx/Makefile
new file mode 100644 (file)
index 0000000..b96e40d
--- /dev/null
@@ -0,0 +1,13 @@
+# $FreeBSD: head/sys/modules/sound/driver/emu10kx/Makefile 230915 2012-02-02 17:25:39Z joel $
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+
+KMOD=  snd_emu10kx
+
+SRCS=  device_if.h bus_if.h pci_if.h
+SRCS+= channel_if.h ac97_if.h mixer_if.h mpufoi_if.h
+# Master, PCM and MIDI devices
+SRCS+= emu10kx.c
+SRCS+= emu10kx-pcm.c
+SRCS+= emu10kx-midi.c
+
+.include <bsd.kmod.mk>
index d46c89c..05785b3 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/envy24/Makefile,v 1.3.2.1 2007/05/13 21:03:46 ariff Exp $
-# $DragonFly: src/sys/dev/sound/driver/envy24/Makefile,v 1.1 2007/06/16 19:48:05 hasso Exp $
+# $FreeBSD: head/sys/modules/sound/driver/envy24/Makefile 162892 2006-09-30 18:12:33Z netchild $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index 81081c7..9c31793 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/envy24ht/Makefile,v 1.2.2.1 2007/05/13 21:03:46 ariff Exp $
-# $DragonFly: src/sys/dev/sound/driver/envy24ht/Makefile,v 1.1 2007/06/16 19:48:05 hasso Exp $
+# $FreeBSD: head/sys/modules/sound/driver/envy24ht/Makefile 162892 2006-09-30 18:12:33Z netchild $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index ef8c8c4..81f6775 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/es137x/Makefile,v 1.3 2003/02/07 13:56:32 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/es137x/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/es137x/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index 7a47248..7c9be65 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/fm801/Makefile,v 1.3 2003/02/07 13:56:32 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/fm801/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/fm801/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index 150bb41..1cce7c8 100644 (file)
@@ -1,9 +1,10 @@
-# $FreeBSD: src/sys/modules/sound/driver/hda/Makefile,v 1.1 2006/10/01 11:13:00 ariff Exp $
+# $FreeBSD: head/sys/modules/sound/driver/hda/Makefile 230130 2012-01-15 13:21:36Z mav $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci/hda
 
 KMOD=  snd_hda
-SRCS=  device_if.h bus_if.h pci_if.h channel_if.h mixer_if.h
-SRCS+= hdac.c hdac_private.h hdac_reg.h hda_reg.h hdac.h
+SRCS=  device_if.h bus_if.h pci_if.h channel_if.h mixer_if.h hdac_if.h
+SRCS+= hdaa.c hdaa.h hdaa_patches.c hdac.c hdac_if.h hdac_if.c
+SRCS+= hdacc.c hdac_private.h hdac_reg.h hda_reg.h hdac.h
 
 .include <bsd.kmod.mk>
diff --git a/sys/dev/sound/driver/hdspe/Makefile b/sys/dev/sound/driver/hdspe/Makefile
new file mode 100644 (file)
index 0000000..2b3f640
--- /dev/null
@@ -0,0 +1,9 @@
+# $FreeBSD: head/sys/modules/sound/driver/hdspe/Makefile 232337 2012-03-01 13:10:18Z mav $
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+
+KMOD=  snd_hdspe
+SRCS=  device_if.h bus_if.h pci_if.h
+SRCS+= hdspe.c hdspe-pcm.c hdspe.h
+
+.include <bsd.kmod.mk>
index 72ddbd9..66dda2f 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/ich/Makefile,v 1.2 2003/02/07 13:56:32 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/ich/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/ich/Makefile 245952 2013-01-26 22:08:21Z pfg $
 
 .PATH:         ${.CURDIR}/../../../../dev/sound/pci
 KMOD           = snd_ich
index de6c149..6392ff1 100644 (file)
@@ -1,12 +1,10 @@
-# $FreeBSD: src/sys/modules/sound/driver/maestro/Makefile,v 1.4 2005/01/26 16:29:07 imp Exp $
-# $DragonFly: src/sys/dev/sound/driver/maestro/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/maestro/Makefile 140867 2005-01-26 16:29:07Z imp $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
 KMOD=  snd_maestro
 SRCS=  device_if.h bus_if.h pci_if.h
 SRCS+= maestro.c
-
 WERROR=
 
 .include <bsd.kmod.mk>
diff --git a/sys/dev/sound/driver/maestro3/Makefile b/sys/dev/sound/driver/maestro3/Makefile
deleted file mode 100644 (file)
index 20a53b3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD: src/sys/modules/sound/driver/maestro3/Makefile,v 1.3 2003/02/07 13:56:32 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/maestro3/Makefile,v 1.4 2007/01/04 21:47:01 corecode Exp $
-
-.PATH: ${.CURDIR}/../../pci
-
-KMOD=  snd_maestro3
-SRCS=  device_if.h bus_if.h pci_if.h
-SRCS+= maestro3.c
-
-CFLAGS+= -Wall -DM3_DEBUG_LEVEL=-1
-
-.include <bsd.kmod.mk>
index ffaa121..ea93288 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/neomagic/Makefile,v 1.3 2003/02/07 13:56:32 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/neomagic/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/neomagic/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index 0857b99..716f87c 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/solo/Makefile,v 1.3 2003/02/07 13:56:32 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/solo/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/solo/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index f236957..d683a7c 100644 (file)
@@ -1,4 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/spicds/Makefile,v 1.2.2.1 2007/05/13 21:03:46 ariff Exp $
+# $FreeBSD: head/sys/modules/sound/driver/spicds/Makefile 162892 2006-09-30 18:12:33Z netchild $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index fe4ac0c..ca7dec6 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/t4dwave/Makefile,v 1.3 2003/02/07 13:56:33 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/t4dwave/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/t4dwave/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index 72c7e9d..668b950 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/via8233/Makefile,v 1.2 2003/02/07 13:56:33 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/via8233/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/via8233/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index b9ed231..d1f51a6 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/via82c686/Makefile,v 1.3 2003/02/07 13:56:33 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/via82c686/Makefile,v 1.3 2007/01/04 21:47:01 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/via82c686/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
index b7d5b3d..64bd694 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/sys/modules/sound/driver/vibes/Makefile,v 1.4 2003/02/07 13:56:33 nyan Exp $
-# $DragonFly: src/sys/dev/sound/driver/vibes/Makefile,v 1.3 2007/01/04 21:47:02 corecode Exp $
+# $FreeBSD: head/sys/modules/sound/driver/vibes/Makefile 110498 2003-02-07 13:56:33Z nyan $
 
 .PATH: ${.CURDIR}/../../../../dev/sound/pci
 
diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c
new file mode 100644 (file)
index 0000000..ace7dfc
--- /dev/null
@@ -0,0 +1,1531 @@
+/*-
+ * Copyright (c) 2003 Mathew Kanner
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+ /*
+  * Parts of this file started out as NetBSD: midi.c 1.31
+  * They are mostly gone.  Still the most obvious will be the state
+  * machine midi_in
+  */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/sound/midi/midi.c 227309 2011-11-07 15:43:11Z ed $");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/conf.h>
+#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <sys/sbuf.h>
+#include <sys/kobj.h>
+#include <sys/module.h>
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/midi/midi.h>
+#include "mpu_if.h"
+
+#include <dev/sound/midi/midiq.h>
+#include "synth_if.h"
+MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
+
+#ifndef KOBJMETHOD_END
+#define KOBJMETHOD_END { NULL, NULL }
+#endif
+
+#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
+#define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
+
+#define MIDI_DEV_RAW   2
+#define MIDI_DEV_MIDICTL 12
+
+enum midi_states {
+       MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
+};
+
+/*
+ * The MPU interface current has init() uninit() inqsize(( outqsize()
+ * callback() : fiddle with the tx|rx status.
+ */
+
+#include "mpu_if.h"
+
+/*
+ * /dev/rmidi  Structure definitions
+ */
+
+#define MIDI_NAMELEN   16
+struct snd_midi {
+       KOBJ_FIELDS;
+       struct mtx lock;                /* Protects all but queues */
+       void   *cookie;
+
+       int     unit;                   /* Should only be used in midistat */
+       int     channel;                /* Should only be used in midistat */
+
+       int     busy;
+       int     flags;                  /* File flags */
+       char    name[MIDI_NAMELEN];
+       struct mtx qlock;               /* Protects inq, outq and flags */
+       MIDIQ_HEAD(, char) inq, outq;
+       int     rchan, wchan;
+       struct selinfo rsel, wsel;
+       int     hiwat;                  /* QLEN(outq)>High-water -> disable
+                                        * writes from userland */
+       enum midi_states inq_state;
+       int     inq_status, inq_left;   /* Variables for the state machine in
+                                        * Midi_in, this is to provide that
+                                        * signals only get issued only
+                                        * complete command packets. */
+       struct proc *async;
+       struct cdev *dev;
+       struct synth_midi *synth;
+       int     synth_flags;
+       TAILQ_ENTRY(snd_midi) link;
+};
+
+struct synth_midi {
+       KOBJ_FIELDS;
+       struct snd_midi *m;
+};
+
+static synth_open_t midisynth_open;
+static synth_close_t midisynth_close;
+static synth_writeraw_t midisynth_writeraw;
+static synth_killnote_t midisynth_killnote;
+static synth_startnote_t midisynth_startnote;
+static synth_setinstr_t midisynth_setinstr;
+static synth_alloc_t midisynth_alloc;
+static synth_controller_t midisynth_controller;
+static synth_bender_t midisynth_bender;
+
+
+static kobj_method_t midisynth_methods[] = {
+       KOBJMETHOD(synth_open, midisynth_open),
+       KOBJMETHOD(synth_close, midisynth_close),
+       KOBJMETHOD(synth_writeraw, midisynth_writeraw),
+       KOBJMETHOD(synth_setinstr, midisynth_setinstr),
+       KOBJMETHOD(synth_startnote, midisynth_startnote),
+       KOBJMETHOD(synth_killnote, midisynth_killnote),
+       KOBJMETHOD(synth_alloc, midisynth_alloc),
+       KOBJMETHOD(synth_controller, midisynth_controller),
+       KOBJMETHOD(synth_bender, midisynth_bender),
+       KOBJMETHOD_END
+};
+
+DEFINE_CLASS(midisynth, midisynth_methods, 0);
+
+/*
+ * Module Exports & Interface
+ *
+ * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan) int
+ * midi_uninit(struct snd_midi *) 0 == no error EBUSY or other error int
+ * Midi_in(struct midi_chan *, char *buf, int count) int Midi_out(struct
+ * midi_chan *, char *buf, int count)
+ *
+ * midi_{in,out} return actual size transfered
+ *
+ */
+
+
+/*
+ * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
+ */
+
+TAILQ_HEAD(, snd_midi) midi_devs;
+
+/*
+ * /dev/midistat variables and declarations, protected by midistat_lock
+ */
+
+static struct mtx midistat_lock;
+static int      midistat_isopen = 0;
+static struct sbuf midistat_sbuf;
+static int      midistat_bufptr;
+static struct cdev *midistat_dev;
+
+/*
+ * /dev/midistat       dev_t declarations
+ */
+
+static d_open_t midistat_open;
+static d_close_t midistat_close;
+static d_read_t midistat_read;
+
+static struct cdevsw midistat_cdevsw = {
+       .d_version = D_VERSION,
+       .d_open = midistat_open,
+       .d_close = midistat_close,
+       .d_read = midistat_read,
+       .d_name = "midistat",
+};
+
+
+/*
+ * /dev/rmidi dev_t declarations, struct variable access is protected by
+ * locks contained within the structure.
+ */
+
+static d_open_t midi_open;
+static d_close_t midi_close;
+static d_ioctl_t midi_ioctl;
+static d_read_t midi_read;
+static d_write_t midi_write;
+static d_poll_t midi_poll;
+
+static struct cdevsw midi_cdevsw = {
+       .d_version = D_VERSION,
+       .d_open = midi_open,
+       .d_close = midi_close,
+       .d_read = midi_read,
+       .d_write = midi_write,
+       .d_ioctl = midi_ioctl,
+       .d_poll = midi_poll,
+       .d_name = "rmidi",
+};
+
+/*
+ * Prototypes of library functions
+ */
+
+static int      midi_destroy(struct snd_midi *, int);
+static int      midistat_prepare(struct sbuf * s);
+static int      midi_load(void);
+static int      midi_unload(void);
+
+/*
+ * Misc declr.
+ */
+SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
+static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device");
+
+int             midi_debug;
+/* XXX: should this be moved into debug.midi? */
+SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
+
+int             midi_dumpraw;
+SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
+
+int             midi_instroff;
+SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
+
+int             midistat_verbose;
+SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW, 
+       &midistat_verbose, 0, "");
+
+#define MIDI_DEBUG(l,a)        if(midi_debug>=l) a
+/*
+ * CODE START
+ */
+
+/*
+ * Register a new rmidi device. cls midi_if interface unit == 0 means
+ * auto-assign new unit number unit != 0 already assigned a unit number, eg.
+ * not the first channel provided by this device. channel,     sub-unit
+ * cookie is passed back on MPU calls Typical device drivers will call with
+ * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
+ * what unit number is used.
+ *
+ * It is an error to call midi_init with an already used unit/channel combo.
+ *
+ * Returns NULL on error
+ *
+ */
+struct snd_midi *
+midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
+{
+       struct snd_midi *m;
+       int i;
+       int inqsize, outqsize;
+       MIDI_TYPE *buf;
+
+       MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
+       mtx_lock(&midistat_lock);
+       /*
+        * Protect against call with existing unit/channel or auto-allocate a
+        * new unit number.
+        */
+       i = -1;
+       TAILQ_FOREACH(m, &midi_devs, link) {
+               mtx_lock(&m->lock);
+               if (unit != 0) {
+                       if (m->unit == unit && m->channel == channel) {
+                               mtx_unlock(&m->lock);
+                               goto err0;
+                       }
+               } else {
+                       /*
+                        * Find a better unit number
+                        */
+                       if (m->unit > i)
+                               i = m->unit;
+               }
+               mtx_unlock(&m->lock);
+       }
+
+       if (unit == 0)
+               unit = i + 1;
+
+       MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
+       m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
+       if (m == NULL)
+               goto err0;
+
+       m->synth = malloc(sizeof(*m->synth), M_MIDI, M_NOWAIT | M_ZERO);
+       kobj_init((kobj_t)m->synth, &midisynth_class);
+       m->synth->m = m;
+       kobj_init((kobj_t)m, cls);
+       inqsize = MPU_INQSIZE(m, cookie);
+       outqsize = MPU_OUTQSIZE(m, cookie);
+
+       MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
+       if (!inqsize && !outqsize)
+               goto err1;
+
+       mtx_init(&m->lock, "raw midi", NULL, 0);
+       mtx_init(&m->qlock, "q raw midi", NULL, 0);
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if (inqsize)
+               buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT);
+       else
+               buf = NULL;
+
+       MIDIQ_INIT(m->inq, buf, inqsize);
+
+       if (outqsize)
+               buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT);
+       else
+               buf = NULL;
+       m->hiwat = outqsize / 2;
+
+       MIDIQ_INIT(m->outq, buf, outqsize);
+
+       if ((inqsize && !MIDIQ_BUF(m->inq)) ||
+           (outqsize && !MIDIQ_BUF(m->outq)))
+               goto err2;
+
+
+       m->busy = 0;
+       m->flags = 0;
+       m->unit = unit;
+       m->channel = channel;
+       m->cookie = cookie;
+
+       if (MPU_INIT(m, cookie))
+               goto err2;
+
+       mtx_unlock(&m->lock);
+       mtx_unlock(&m->qlock);
+
+       TAILQ_INSERT_TAIL(&midi_devs, m, link);
+
+       mtx_unlock(&midistat_lock);
+
+       m->dev = make_dev(&midi_cdevsw,
+           MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
+           UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
+       m->dev->si_drv1 = m;
+
+       return m;
+
+err2:  mtx_destroy(&m->qlock);
+       mtx_destroy(&m->lock);
+
+       if (MIDIQ_BUF(m->inq))
+               free(MIDIQ_BUF(m->inq), M_MIDI);
+       if (MIDIQ_BUF(m->outq))
+               free(MIDIQ_BUF(m->outq), M_MIDI);
+err1:  free(m, M_MIDI);
+err0:  mtx_unlock(&midistat_lock);
+       MIDI_DEBUG(1, printf("midi_init ended in error\n"));
+       return NULL;
+}
+
+/*
+ * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
+ * entry point. midi_unint if fact, does not send any methods. A call to
+ * midi_uninit is a defacto promise that you won't manipulate ch anymore
+ *
+ */
+
+int
+midi_uninit(struct snd_midi *m)
+{
+       int err;
+
+       err = ENXIO;
+       mtx_lock(&midistat_lock);
+       mtx_lock(&m->lock);
+       if (m->busy) {
+               if (!(m->rchan || m->wchan))
+                       goto err;
+
+               if (m->rchan) {
+                       wakeup(&m->rchan);
+                       m->rchan = 0;
+               }
+               if (m->wchan) {
+                       wakeup(&m->wchan);
+                       m->wchan = 0;
+               }
+       }
+       err = midi_destroy(m, 0);
+       if (!err)
+               goto exit;
+
+err:   mtx_unlock(&m->lock);
+exit:  mtx_unlock(&midistat_lock);
+       return err;
+}
+
+/*
+ * midi_in: process all data until the queue is full, then discards the rest.
+ * Since midi_in is a state machine, data discards can cause it to get out of
+ * whack.  Process as much as possible.  It calls, wakeup, selnotify and
+ * psignal at most once.
+ */
+
+#ifdef notdef
+static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
+
+#endif                                 /* notdef */
+/* Number of bytes in a MIDI command */
+#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
+#define MIDI_ACK       0xfe
+#define MIDI_IS_STATUS(d) ((d) >= 0x80)
+#define MIDI_IS_COMMON(d) ((d) >= 0xf0)
+
+#define MIDI_SYSEX_START       0xF0
+#define MIDI_SYSEX_END     0xF7
+
+
+int
+midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size)
+{
+       /* int             i, sig, enq; */
+       int used;
+
+       /* MIDI_TYPE       data; */
+       MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
+
+/*
+ * XXX: locking flub
+ */
+       if (!(m->flags & M_RX))
+               return size;
+
+       used = 0;
+
+       mtx_lock(&m->qlock);
+#if 0
+       /*
+        * Don't bother queuing if not in read mode.  Discard everything and
+        * return size so the caller doesn't freak out.
+        */
+
+       if (!(m->flags & M_RX))
+               return size;
+
+       for (i = sig = 0; i < size; i++) {
+
+               data = buf[i];
+               enq = 0;
+               if (data == MIDI_ACK)
+                       continue;
+
+               switch (m->inq_state) {
+               case MIDI_IN_START:
+                       if (MIDI_IS_STATUS(data)) {
+                               switch (data) {
+                               case 0xf0:      /* Sysex */
+                                       m->inq_state = MIDI_IN_SYSEX;
+                                       break;
+                               case 0xf1:      /* MTC quarter frame */
+                               case 0xf3:      /* Song select */
+                                       m->inq_state = MIDI_IN_DATA;
+                                       enq = 1;
+                                       m->inq_left = 1;
+                                       break;
+                               case 0xf2:      /* Song position pointer */
+                                       m->inq_state = MIDI_IN_DATA;
+                                       enq = 1;
+                                       m->inq_left = 2;
+                                       break;
+                               default:
+                                       if (MIDI_IS_COMMON(data)) {
+                                               enq = 1;
+                                               sig = 1;
+                                       } else {
+                                               m->inq_state = MIDI_IN_DATA;
+                                               enq = 1;
+                                               m->inq_status = data;
+                                               m->inq_left = MIDI_LENGTH(data);
+                                       }
+                                       break;
+                               }
+                       } else if (MIDI_IS_STATUS(m->inq_status)) {
+                               m->inq_state = MIDI_IN_DATA;
+                               if (!MIDIQ_FULL(m->inq)) {
+                                       used++;
+                                       MIDIQ_ENQ(m->inq, &m->inq_status, 1);
+                               }
+                               enq = 1;
+                               m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
+                       }
+                       break;
+                       /*
+                        * End of case MIDI_IN_START:
+                        */
+
+               case MIDI_IN_DATA:
+                       enq = 1;
+                       if (--m->inq_left <= 0)
+                               sig = 1;/* deliver data */
+                       break;
+               case MIDI_IN_SYSEX:
+                       if (data == MIDI_SYSEX_END)
+                               m->inq_state = MIDI_IN_START;
+                       break;
+               }
+
+               if (enq)
+                       if (!MIDIQ_FULL(m->inq)) {
+                               MIDIQ_ENQ(m->inq, &data, 1);
+                               used++;
+                       }
+               /*
+                * End of the state machines main "for loop"
+                */
+       }
+       if (sig) {
+#endif
+               MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
+                   (intmax_t)MIDIQ_LEN(m->inq),
+                   (intmax_t)MIDIQ_AVAIL(m->inq)));
+               if (MIDIQ_AVAIL(m->inq) > size) {
+                       used = size;
+                       MIDIQ_ENQ(m->inq, buf, size);
+               } else {
+                       MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
+                       mtx_unlock(&m->qlock);
+                       return 0;
+               }
+               if (m->rchan) {
+                       wakeup(&m->rchan);
+                       m->rchan = 0;
+               }
+               selwakeup(&m->rsel);
+               if (m->async) {
+                       PROC_LOCK(m->async);
+                       kern_psignal(m->async, SIGIO);
+                       PROC_UNLOCK(m->async);
+               }
+#if 0
+       }
+#endif
+       mtx_unlock(&m->qlock);
+       return used;
+}
+
+/*
+ * midi_out: The only clearer of the M_TXEN flag.
+ */
+int
+midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size)
+{
+       int used;
+
+/*
+ * XXX: locking flub
+ */
+       if (!(m->flags & M_TXEN))
+               return 0;
+
+       MIDI_DEBUG(2, printf("midi_out: %p\n", m));
+       mtx_lock(&m->qlock);
+       used = MIN(size, MIDIQ_LEN(m->outq));
+       MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
+       if (used)
+               MIDIQ_DEQ(m->outq, buf, used);
+       if (MIDIQ_EMPTY(m->outq)) {
+               m->flags &= ~M_TXEN;
+               MPU_CALLBACKP(m, m->cookie, m->flags);
+       }
+       if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
+               if (m->wchan) {
+                       wakeup(&m->wchan);
+                       m->wchan = 0;
+               }
+               selwakeup(&m->wsel);
+               if (m->async) {
+                       PROC_LOCK(m->async);
+                       kern_psignal(m->async, SIGIO);
+                       PROC_UNLOCK(m->async);
+               }
+       }
+       mtx_unlock(&m->qlock);
+       return used;
+}
+
+
+/*
+ * /dev/rmidi#.#       device access functions
+ */
+int
+midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
+{
+       struct snd_midi *m = i_dev->si_drv1;
+       int retval;
+
+       MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
+           flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
+       if (m == NULL)
+               return ENXIO;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       retval = 0;
+
+       if (flags & FREAD) {
+               if (MIDIQ_SIZE(m->inq) == 0)
+                       retval = ENXIO;
+               else if (m->flags & M_RX)
+                       retval = EBUSY;
+               if (retval)
+                       goto err;
+       }
+       if (flags & FWRITE) {
+               if (MIDIQ_SIZE(m->outq) == 0)
+                       retval = ENXIO;
+               else if (m->flags & M_TX)
+                       retval = EBUSY;
+               if (retval)
+                       goto err;
+       }
+       m->busy++;
+
+       m->rchan = 0;
+       m->wchan = 0;
+       m->async = 0;
+
+       if (flags & FREAD) {
+               m->flags |= M_RX | M_RXEN;
+               /*
+                * Only clear the inq, the outq might still have data to drain
+                * from a previous session
+                */
+               MIDIQ_CLEAR(m->inq);
+       };
+
+       if (flags & FWRITE)
+               m->flags |= M_TX;
+
+       MPU_CALLBACK(m, m->cookie, m->flags);
+
+       MIDI_DEBUG(2, printf("midi_open: opened.\n"));
+
+err:   mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+       return retval;
+}
+
+int
+midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
+{
+       struct snd_midi *m = i_dev->si_drv1;
+       int retval;
+       int oldflags;
+
+       MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
+           flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
+
+       if (m == NULL)
+               return ENXIO;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if ((flags & FREAD && !(m->flags & M_RX)) ||
+           (flags & FWRITE && !(m->flags & M_TX))) {
+               retval = ENXIO;
+               goto err;
+       }
+       m->busy--;
+
+       oldflags = m->flags;
+
+       if (flags & FREAD)
+               m->flags &= ~(M_RX | M_RXEN);
+       if (flags & FWRITE)
+               m->flags &= ~M_TX;
+
+       if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
+               MPU_CALLBACK(m, m->cookie, m->flags);
+
+       MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
+
+       mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+       retval = 0;
+err:   return retval;
+}
+
+/*
+ * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
+ * as data is available.
+ */
+int
+midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
+{
+#define MIDI_RSIZE 32
+       struct snd_midi *m = i_dev->si_drv1;
+       int retval;
+       int used;
+       char buf[MIDI_RSIZE];
+
+       MIDI_DEBUG(5, printf("midiread: count=%lu\n",
+           (unsigned long)uio->uio_resid));
+
+       retval = EIO;
+
+       if (m == NULL)
+               goto err0;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if (!(m->flags & M_RX))
+               goto err1;
+
+       while (uio->uio_resid > 0) {
+               while (MIDIQ_EMPTY(m->inq)) {
+                       retval = EWOULDBLOCK;
+                       if (ioflag & O_NONBLOCK)
+                               goto err1;
+                       mtx_unlock(&m->lock);
+                       m->rchan = 1;
+                       retval = msleep(&m->rchan, &m->qlock,
+                           PCATCH | PDROP, "midi RX", 0);
+                       /*
+                        * We slept, maybe things have changed since last
+                        * dying check
+                        */
+                       if (retval == EINTR)
+                               goto err0;
+                       if (m != i_dev->si_drv1)
+                               retval = ENXIO;
+                       /* if (retval && retval != ERESTART) */
+                       if (retval)
+                               goto err0;
+                       mtx_lock(&m->lock);
+                       mtx_lock(&m->qlock);
+                       m->rchan = 0;
+                       if (!m->busy)
+                               goto err1;
+               }
+               MIDI_DEBUG(6, printf("midi_read start\n"));
+               /*
+                * At this point, it is certain that m->inq has data
+                */
+
+               used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
+               used = MIN(used, MIDI_RSIZE);
+
+               MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
+               MIDIQ_DEQ(m->inq, buf, used);
+               retval = uiomove(buf, used, uio);
+               if (retval)
+                       goto err1;
+       }
+
+       /*
+        * If we Made it here then transfer is good
+        */
+       retval = 0;
+err1:  mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+err0:  MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
+       return retval;
+}
+
+/*
+ * midi_write: The only setter of M_TXEN
+ */
+
+int
+midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
+{
+#define MIDI_WSIZE 32
+       struct snd_midi *m = i_dev->si_drv1;
+       int retval;
+       int used;
+       char buf[MIDI_WSIZE];
+
+
+       MIDI_DEBUG(4, printf("midi_write\n"));
+       retval = 0;
+       if (m == NULL)
+               goto err0;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if (!(m->flags & M_TX))
+               goto err1;
+
+       while (uio->uio_resid > 0) {
+               while (MIDIQ_AVAIL(m->outq) == 0) {
+                       retval = EWOULDBLOCK;
+                       if (ioflag & O_NONBLOCK)
+                               goto err1;
+                       mtx_unlock(&m->lock);
+                       m->wchan = 1;
+                       MIDI_DEBUG(3, printf("midi_write msleep\n"));
+                       retval = msleep(&m->wchan, &m->qlock,
+                           PCATCH | PDROP, "midi TX", 0);
+                       /*
+                        * We slept, maybe things have changed since last
+                        * dying check
+                        */
+                       if (retval == EINTR)
+                               goto err0;
+                       if (m != i_dev->si_drv1)
+                               retval = ENXIO;
+                       if (retval)
+                               goto err0;
+                       mtx_lock(&m->lock);
+                       mtx_lock(&m->qlock);
+                       m->wchan = 0;
+                       if (!m->busy)
+                               goto err1;
+               }
+
+               /*
+                * We are certain than data can be placed on the queue
+                */
+
+               used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
+               used = MIN(used, MIDI_WSIZE);
+               MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
+                   uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
+                   (intmax_t)MIDIQ_AVAIL(m->outq)));
+
+
+               MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
+               retval = uiomove(buf, used, uio);
+               if (retval)
+                       goto err1;
+               MIDIQ_ENQ(m->outq, buf, used);
+               /*
+                * Inform the bottom half that data can be written
+                */
+               if (!(m->flags & M_TXEN)) {
+                       m->flags |= M_TXEN;
+                       MPU_CALLBACK(m, m->cookie, m->flags);
+               }
+       }
+       /*
+        * If we Made it here then transfer is good
+        */
+       retval = 0;
+err1:  mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+err0:  return retval;
+}
+
+int
+midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
+    struct thread *td)
+{
+       return ENXIO;
+}
+
+int
+midi_poll(struct cdev *i_dev, int events, struct thread *td)
+{
+       struct snd_midi *m = i_dev->si_drv1;
+       int revents;
+
+       if (m == NULL)
+               return 0;
+
+       revents = 0;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if (events & (POLLIN | POLLRDNORM))
+               if (!MIDIQ_EMPTY(m->inq))
+                       events |= events & (POLLIN | POLLRDNORM);
+
+       if (events & (POLLOUT | POLLWRNORM))
+               if (MIDIQ_AVAIL(m->outq) < m->hiwat)
+                       events |= events & (POLLOUT | POLLWRNORM);
+
+       if (revents == 0) {
+               if (events & (POLLIN | POLLRDNORM))
+                       selrecord(td, &m->rsel);
+
+               if (events & (POLLOUT | POLLWRNORM))
+                       selrecord(td, &m->wsel);
+       }
+       mtx_unlock(&m->lock);
+       mtx_unlock(&m->qlock);
+
+       return (revents);
+}
+
+/*
+ * /dev/midistat device functions
+ *
+ */
+static int
+midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
+{
+       int error;
+
+       MIDI_DEBUG(1, printf("midistat_open\n"));
+       mtx_lock(&midistat_lock);
+
+       if (midistat_isopen) {
+               mtx_unlock(&midistat_lock);
+               return EBUSY;
+       }
+       midistat_isopen = 1;
+       mtx_unlock(&midistat_lock);
+
+       if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
+               error = ENXIO;
+               mtx_lock(&midistat_lock);
+               goto out;
+       }
+       mtx_lock(&midistat_lock);
+       midistat_bufptr = 0;
+       error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
+
+out:   if (error)
+               midistat_isopen = 0;
+       mtx_unlock(&midistat_lock);
+       return error;
+}
+
+static int
+midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
+{
+       MIDI_DEBUG(1, printf("midistat_close\n"));
+       mtx_lock(&midistat_lock);
+       if (!midistat_isopen) {
+               mtx_unlock(&midistat_lock);
+               return EBADF;
+       }
+       sbuf_delete(&midistat_sbuf);
+       midistat_isopen = 0;
+
+       mtx_unlock(&midistat_lock);
+       return 0;
+}
+
+static int
+midistat_read(struct cdev *i_dev, struct uio *buf, int flag)
+{
+       int l, err;
+
+       MIDI_DEBUG(4, printf("midistat_read\n"));
+       mtx_lock(&midistat_lock);
+       if (!midistat_isopen) {
+               mtx_unlock(&midistat_lock);
+               return EBADF;
+       }
+       l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr);
+       err = 0;
+       if (l > 0) {
+               mtx_unlock(&midistat_lock);
+               err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l,
+                   buf);
+               mtx_lock(&midistat_lock);
+       } else
+               l = 0;
+       midistat_bufptr += l;
+       mtx_unlock(&midistat_lock);
+       return err;
+}
+
+/*
+ * Module library functions
+ */
+
+static int
+midistat_prepare(struct sbuf *s)
+{
+       struct snd_midi *m;
+
+       mtx_assert(&midistat_lock, MA_OWNED);
+
+       sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
+       if (TAILQ_EMPTY(&midi_devs)) {
+               sbuf_printf(s, "No devices installed.\n");
+               sbuf_finish(s);
+               return sbuf_len(s);
+       }
+       sbuf_printf(s, "Installed devices:\n");
+
+       TAILQ_FOREACH(m, &midi_devs, link) {
+               mtx_lock(&m->lock);
+               sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
+                   MPU_PROVIDER(m, m->cookie));
+               sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
+               sbuf_printf(s, "\n");
+               mtx_unlock(&m->lock);
+       }
+
+       sbuf_finish(s);
+       return sbuf_len(s);
+}
+
+#ifdef notdef
+/*
+ * Convert IOCTL command to string for debugging
+ */
+
+static char *
+midi_cmdname(int cmd)
+{
+       static struct {
+               int     cmd;
+               char   *name;
+       }     *tab, cmdtab_midiioctl[] = {
+#define A(x)   {x, ## x}
+               /*
+                * Once we have some real IOCTLs define, the following will
+                * be relavant.
+                *
+                * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
+                * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
+                * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
+                * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
+                * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
+                * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
+                * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
+                * A(AIOGCAP),
+                */
+#undef A
+               {
+                       -1, "unknown"
+               },
+       };
+
+       for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
+       return tab->name;
+}
+
+#endif                                 /* notdef */
+
+/*
+ * midisynth
+ */
+
+
+int
+midisynth_open(void *n, void *arg, int flags)
+{
+       struct snd_midi *m = ((struct synth_midi *)n)->m;
+       int retval;
+
+       MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
+           flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
+
+       if (m == NULL)
+               return ENXIO;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       retval = 0;
+
+       if (flags & FREAD) {
+               if (MIDIQ_SIZE(m->inq) == 0)
+                       retval = ENXIO;
+               else if (m->flags & M_RX)
+                       retval = EBUSY;
+               if (retval)
+                       goto err;
+       }
+       if (flags & FWRITE) {
+               if (MIDIQ_SIZE(m->outq) == 0)
+                       retval = ENXIO;
+               else if (m->flags & M_TX)
+                       retval = EBUSY;
+               if (retval)
+                       goto err;
+       }
+       m->busy++;
+
+       /*
+        * TODO: Consider m->async = 0;
+        */
+
+       if (flags & FREAD) {
+               m->flags |= M_RX | M_RXEN;
+               /*
+                * Only clear the inq, the outq might still have data to drain
+                * from a previous session
+                */
+               MIDIQ_CLEAR(m->inq);
+               m->rchan = 0;
+       };
+
+       if (flags & FWRITE) {
+               m->flags |= M_TX;
+               m->wchan = 0;
+       }
+       m->synth_flags = flags & (FREAD | FWRITE);
+
+       MPU_CALLBACK(m, m->cookie, m->flags);
+
+
+err:   mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+       MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
+       return retval;
+}
+
+int
+midisynth_close(void *n)
+{
+       struct snd_midi *m = ((struct synth_midi *)n)->m;
+       int retval;
+       int oldflags;
+
+       MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
+           m->synth_flags & FREAD ? "M_RX" : "",
+           m->synth_flags & FWRITE ? "M_TX" : ""));
+
+       if (m == NULL)
+               return ENXIO;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
+           (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
+               retval = ENXIO;
+               goto err;
+       }
+       m->busy--;
+
+       oldflags = m->flags;
+
+       if (m->synth_flags & FREAD)
+               m->flags &= ~(M_RX | M_RXEN);
+       if (m->synth_flags & FWRITE)
+               m->flags &= ~M_TX;
+
+       if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
+               MPU_CALLBACK(m, m->cookie, m->flags);
+
+       MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
+
+       mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+       retval = 0;
+err:   return retval;
+}
+
+/*
+ * Always blocking.
+ */
+
+int
+midisynth_writeraw(void *n, uint8_t *buf, size_t len)
+{
+       struct snd_midi *m = ((struct synth_midi *)n)->m;
+       int retval;
+       int used;
+       int i;
+
+       MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
+
+       retval = 0;
+
+       if (m == NULL)
+               return ENXIO;
+
+       mtx_lock(&m->lock);
+       mtx_lock(&m->qlock);
+
+       if (!(m->flags & M_TX))
+               goto err1;
+
+       if (midi_dumpraw)
+               printf("midi dump: ");
+
+       while (len > 0) {
+               while (MIDIQ_AVAIL(m->outq) == 0) {
+                       if (!(m->flags & M_TXEN)) {
+                               m->flags |= M_TXEN;
+                               MPU_CALLBACK(m, m->cookie, m->flags);
+                       }
+                       mtx_unlock(&m->lock);
+                       m->wchan = 1;
+                       MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
+                       retval = msleep(&m->wchan, &m->qlock,
+                           PCATCH | PDROP, "midi TX", 0);
+                       /*
+                        * We slept, maybe things have changed since last
+                        * dying check
+                        */
+                       if (retval == EINTR)
+                               goto err0;
+
+                       if (retval)
+                               goto err0;
+                       mtx_lock(&m->lock);
+                       mtx_lock(&m->qlock);
+                       m->wchan = 0;
+                       if (!m->busy)
+                               goto err1;
+               }
+
+               /*
+                * We are certain than data can be placed on the queue
+                */
+
+               used = MIN(MIDIQ_AVAIL(m->outq), len);
+               used = MIN(used, MIDI_WSIZE);
+               MIDI_DEBUG(5,
+                   printf("midi_synth: resid %zu len %jd avail %jd\n",
+                   len, (intmax_t)MIDIQ_LEN(m->outq),
+                   (intmax_t)MIDIQ_AVAIL(m->outq)));
+
+               if (midi_dumpraw)
+                       for (i = 0; i < used; i++)
+                               printf("%x ", buf[i]);
+
+               MIDIQ_ENQ(m->outq, buf, used);
+               len -= used;
+
+               /*
+                * Inform the bottom half that data can be written
+                */
+               if (!(m->flags & M_TXEN)) {
+                       m->flags |= M_TXEN;
+                       MPU_CALLBACK(m, m->cookie, m->flags);
+               }
+       }
+       /*
+        * If we Made it here then transfer is good
+        */
+       if (midi_dumpraw)
+               printf("\n");
+
+       retval = 0;
+err1:  mtx_unlock(&m->qlock);
+       mtx_unlock(&m->lock);
+err0:  return retval;
+}
+
+static int
+midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
+{
+       u_char c[3];
+
+
+       if (note > 127 || chn > 15)
+               return (EINVAL);
+
+       if (vel > 127)
+               vel = 127;
+
+       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;
+       }
+
+       return midisynth_writeraw(n, c, 3);
+}
+
+static int
+midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
+{
+       u_char c[2];
+
+       if (instr > 127 || chn > 15)
+               return EINVAL;
+
+       c[0] = 0xc0 | (chn & 0x0f);     /* Progamme change. */
+       c[1] = instr + midi_instroff;
+
+       return midisynth_writeraw(n, c, 2);
+}
+
+static int
+midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
+{
+       u_char c[3];
+
+       if (note > 127 || chn > 15)
+               return EINVAL;
+
+       if (vel > 127)
+               vel = 127;
+
+       c[0] = 0x90 | (chn & 0x0f);     /* Note on. */
+       c[1] = (u_char)note;
+       c[2] = (u_char)vel;
+
+       return midisynth_writeraw(n, c, 3);
+}
+static int
+midisynth_alloc(void *n, uint8_t chan, uint8_t note)
+{
+       return chan;
+}
+
+static int
+midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
+{
+       u_char c[3];
+
+       if (ctrlnum > 127 || chn > 15)
+               return EINVAL;
+
+       c[0] = 0xb0 | (chn & 0x0f);     /* Control Message. */
+       c[1] = ctrlnum;
+       c[2] = val;
+       return midisynth_writeraw(n, c, 3);
+}
+
+static int
+midisynth_bender(void *n, uint8_t chn, uint16_t val)
+{
+       u_char c[3];
+
+
+       if (val > 16383 || chn > 15)
+               return EINVAL;
+
+       c[0] = 0xe0 | (chn & 0x0f);     /* Pitch bend. */
+       c[1] = (u_char)val & 0x7f;
+       c[2] = (u_char)(val >> 7) & 0x7f;
+
+       return midisynth_writeraw(n, c, 3);
+}
+
+/*
+ * Single point of midi destructions.
+ */
+static int
+midi_destroy(struct snd_midi *m, int midiuninit)
+{
+
+       mtx_assert(&midistat_lock, MA_OWNED);
+       mtx_assert(&m->lock, MA_OWNED);
+
+       MIDI_DEBUG(3, printf("midi_destroy\n"));
+       m->dev->si_drv1 = NULL;
+       mtx_unlock(&m->lock);   /* XXX */
+       destroy_dev(m->dev);
+       TAILQ_REMOVE(&midi_devs, m, link);
+       if (midiuninit)
+               MPU_UNINIT(m, m->cookie);
+       free(MIDIQ_BUF(m->inq), M_MIDI);
+       free(MIDIQ_BUF(m->outq), M_MIDI);
+       mtx_destroy(&m->qlock);
+       mtx_destroy(&m->lock);
+       free(m, M_MIDI);
+       return 0;
+}
+
+/*
+ * Load and unload functions, creates the /dev/midistat device
+ */
+
+static int
+midi_load()
+{
+       mtx_init(&midistat_lock, "midistat lock", NULL, 0);
+       TAILQ_INIT(&midi_devs);         /* Initialize the queue. */
+
+       midistat_dev = make_dev(&midistat_cdevsw,
+           MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
+           UID_ROOT, GID_WHEEL, 0666, "midistat");
+
+       return 0;
+}
+
+static int
+midi_unload()
+{
+       struct snd_midi *m;
+       int retval;
+
+       MIDI_DEBUG(1, printf("midi_unload()\n"));
+       retval = EBUSY;
+       mtx_lock(&midistat_lock);
+       if (midistat_isopen)
+               goto exit0;
+
+       TAILQ_FOREACH(m, &midi_devs, link) {
+               mtx_lock(&m->lock);
+               if (m->busy)
+                       retval = EBUSY;
+               else
+                       retval = midi_destroy(m, 1);
+               if (retval)
+                       goto exit1;
+       }
+
+       mtx_unlock(&midistat_lock);     /* XXX */
+
+       destroy_dev(midistat_dev);
+       /*
+        * Made it here then unload is complete
+        */
+       mtx_destroy(&midistat_lock);
+       return 0;
+
+exit1:
+       mtx_unlock(&m->lock);
+exit0:
+       mtx_unlock(&midistat_lock);
+       if (retval)
+               MIDI_DEBUG(2, printf("midi_unload: failed\n"));
+       return retval;
+}
+
+extern int seq_modevent(module_t mod, int type, void *data);
+
+static int
+midi_modevent(module_t mod, int type, void *data)
+{
+       int retval;
+
+       retval = 0;
+
+       switch (type) {
+       case MOD_LOAD:
+               retval = midi_load();
+#if 0
+               if (retval == 0)
+                       retval = seq_modevent(mod, type, data);
+#endif
+               break;
+
+       case MOD_UNLOAD:
+               retval = midi_unload();
+#if 0
+               if (retval == 0)
+                       retval = seq_modevent(mod, type, data);
+#endif
+               break;
+
+       default:
+               break;
+       }
+
+       return retval;
+}
+
+kobj_t
+midimapper_addseq(void *arg1, int *unit, void **cookie)
+{
+       unit = 0;
+
+       return (kobj_t)arg1;
+}
+
+int
+midimapper_open(void *arg1, void **cookie)
+{
+       int retval = 0;
+       struct snd_midi *m;
+
+       mtx_lock(&midistat_lock);
+
+       TAILQ_FOREACH(m, &midi_devs, link) {
+               retval++;
+       }
+
+       mtx_unlock(&midistat_lock);
+       return retval;
+}
+
+int
+midimapper_close(void *arg1, void *cookie)
+{
+       return 0;
+}
+
+kobj_t
+midimapper_fetch_synth(void *arg, void *cookie, int unit)
+{
+       struct snd_midi *m;
+       int retval = 0;
+
+       mtx_lock(&midistat_lock);
+
+       TAILQ_FOREACH(m, &midi_devs, link) {
+               if (unit == retval) {
+                       mtx_unlock(&midistat_lock);
+                       return (kobj_t)m->synth;
+               }
+               retval++;
+       }
+
+       mtx_unlock(&midistat_lock);
+       return NULL;
+}
+
+DEV_MODULE(midi, midi_modevent, NULL);
+MODULE_VERSION(midi, 1);
similarity index 61%
copy from sys/dev/sound/pcm/vchan.h
copy to sys/dev/sound/midi/midi.h
index 797499a..3a13db2 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2001 Cameron Grant <cg@freebsd.org>
+ * Copyright (c) 2003 Mathew Kanner
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/sound/pcm/vchan.h,v 1.4 2005/01/06 01:43:21 imp Exp $
- * $DragonFly: src/sys/dev/sound/pcm/vchan.h,v 1.3 2007/01/04 21:47:03 corecode Exp $
+ * $FreeBSD: head/sys/dev/sound/midi/midi.h 166971 2007-02-25 13:51:52Z netchild $
  */
 
-int vchan_create(struct pcm_channel *parent);
-int vchan_destroy(struct pcm_channel *c);
-int vchan_initsys(device_t dev);
+#ifndef MIDI_H
+#define MIDI_H
 
+#include <sys/types.h>
+#include <sys/malloc.h>
 
+MALLOC_DECLARE(M_MIDI);
+
+#define M_RX           0x01
+#define M_TX           0x02
+#define M_RXEN         0x04
+#define M_TXEN         0x08
+
+#define MIDI_TYPE unsigned char
+
+struct snd_midi;
+
+struct snd_midi *
+midi_init(kobj_class_t _mpu_cls, int _unit, int _channel, void *cookie);
+int    midi_uninit(struct snd_midi *_m);
+int    midi_out(struct snd_midi *_m, MIDI_TYPE *_buf, int _size);
+int    midi_in(struct snd_midi *_m, MIDI_TYPE *_buf, int _size);
+
+kobj_t midimapper_addseq(void *arg1, int *unit, void **cookie);
+int    midimapper_open(void *arg1, void **cookie);
+int    midimapper_close(void *arg1, void *cookie);
+kobj_t midimapper_fetch_synth(void *arg, void *cookie, int unit);
+
+#endif
diff --git a/sys/dev/sound/midi/midiq.h b/sys/dev/sound/midi/midiq.h
new file mode 100644 (file)
index 0000000..14fb25d
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 2003 Mathew Kanner
+ * 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: head/sys/dev/sound/midi/midiq.h 166971 2007-02-25 13:51:52Z netchild $
+ */
+
+#ifndef MIDIQ_H
+#define MIDIQ_H
+
+#define MIDIQ_MOVE(a,b,c) bcopy(b,a,c)
+
+#define MIDIQ_HEAD(name, type)          \
+struct name {                           \
+        int h, t, s;                    \
+        type * b;                        \
+}
+
+#define MIDIQ_INIT(head, buf, size) do {                \
+        (head).h=(head).t=0;                          \
+        (head).s=size;                                 \
+        (head).b=buf;                                  \
+} while (0)
+
+#define MIDIQ_EMPTY(head)       ((head).h == (head).t )
+
+#define MIDIQ_LENBASE(head)         ((head).h - (head).t < 0 ? \
+                                        (head).h - (head).t + (head).s : \
+                                        (head).h - (head).t)
+
+#define MIDIQ_FULL(head)        ((head).h == -1)
+#define MIDIQ_AVAIL(head)       (MIDIQ_FULL(head) ? 0 : (head).s - MIDIQ_LENBASE(head))
+#define MIDIQ_LEN(head)                ((head).s - MIDIQ_AVAIL(head))
+#define MIDIQ_DEBUG 0
+/*
+ * No protection against overflow, underflow
+ */
+#define MIDIQ_ENQ(head, buf, size) do {                                                                 \
+               if(MIDIQ_DEBUG)\
+                       printf("#1 %p %p bytes copied %jd tran req s %d h %d t %d\n",            \
+                              &(head).b[(head).h], (buf),                                        \
+                              (intmax_t)(sizeof(*(head).b) *                                     \
+                                         MIN( (size), (head).s - (head).h) ),                   \
+                              (size), (head).h, (head).t);               \
+                MIDIQ_MOVE(&(head).b[(head).h], (buf), sizeof(*(head).b) * MIN((size), (head).s - (head).h));                       \
+                if( (head).s - (head).h < (size) ) {                                                    \
+                       if(MIDIQ_DEBUG) \
+                               printf("#2 %p %p bytes copied %jd\n",  (head).b, (buf) + (head).s - (head).h, (intmax_t)sizeof(*(head).b) * ((size) - (head).s + (head).h) );      \
+                        MIDIQ_MOVE((head).b, (buf) + (head).s - (head).h, sizeof(*(head).b) * ((size) - (head).s + (head).h) );      \
+               } \
+                (head).h+=(size);                                                                         \
+                (head).h%=(head).s;                                                                     \
+               if(MIDIQ_EMPTY(head)) (head).h=-1; \
+               if(MIDIQ_DEBUG)\
+                       printf("#E h %d t %d\n", (head).h, (head).t);                       \
+} while (0)
+
+#define MIDIQ_DEQ_I(head, buf, size, move, update) do {                                                                 \
+               if(MIDIQ_FULL(head)) (head).h=(head).t; \
+               if(MIDIQ_DEBUG)\
+                       printf("#1 %p %p bytes copied %jd tran req s %d h %d t %d\n", &(head).b[(head).t], (buf), (intmax_t)sizeof(*(head).b) * MIN((size), (head).s - (head).t), (size), (head).h, (head).t);                       \
+                if (move) MIDIQ_MOVE((buf), &(head).b[(head).t], sizeof(*(head).b) * MIN((size), (head).s - (head).t));                       \
+                if( (head).s - (head).t < (size) ) {                                                    \
+                       if(MIDIQ_DEBUG) \
+                               printf("#2 %p %p bytes copied %jd\n",  (head).b, (buf) + (head).s - (head).t, (intmax_t)sizeof(*(head).b) * ((size) - (head).s + (head).t) );      \
+                        if (move) MIDIQ_MOVE((buf) + (head).s - (head).t, (head).b, sizeof(*(head).b) * ((size) - (head).s + (head).t) );      \
+               } \
+               if (update) { \
+                (head).t+=(size);                                                                         \
+                (head).t%=(head).s;                                                                     \
+               } else { \
+                 if (MIDIQ_EMPTY(head)) (head).h=-1; \
+               } \
+               if(MIDIQ_DEBUG)\
+                       printf("#E h %d t %d\n", (head).h, (head).t);                       \
+} while (0)
+
+#define MIDIQ_SIZE(head) ((head).s)
+#define MIDIQ_CLEAR(head) ((head).h = (head).t = 0)
+#define MIDIQ_BUF(head) ((head).b)
+#define MIDIQ_DEQ(head, buf, size) MIDIQ_DEQ_I(head, buf, size, 1, 1)
+#define MIDIQ_PEEK(head, buf, size) MIDIQ_DEQ_I(head, buf, size, 1, 0)
+#define MIDIQ_POP(head, size) MIDIQ_DEQ_I(head, &head, size, 0, 1)
+
+#endif
diff --git a/sys/dev/sound/midi/mpu401.c b/sys/dev/sound/midi/mpu401.c
new file mode 100644 (file)
index 0000000..e567d15
--- /dev/null
@@ -0,0 +1,298 @@
+/*-
+ * Copyright (c) 2003 Mathew Kanner
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/sound/midi/mpu401.c 193979 2009-06-11 09:06:09Z ariff $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kobj.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>                   /* to get driver_intr_t */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/midi/mpu401.h>
+#include <dev/sound/midi/midi.h>
+
+#include "mpu_if.h"
+#include "mpufoi_if.h"
+
+#ifndef KOBJMETHOD_END
+#define KOBJMETHOD_END { NULL, NULL }
+#endif
+
+#define MPU_DATAPORT   0
+#define MPU_CMDPORT    1
+#define MPU_STATPORT   1
+#define MPU_RESET      0xff
+#define MPU_UART       0x3f
+#define MPU_ACK        0xfe
+#define MPU_STATMASK   0xc0
+#define MPU_OUTPUTBUSY 0x40
+#define MPU_INPUTBUSY  0x80
+#define MPU_TRYDATA 50
+#define MPU_DELAY   2500
+
+#define CMD(m,d)       MPUFOI_WRITE(m, m->cookie, MPU_CMDPORT,d)
+#define STATUS(m)      MPUFOI_READ(m, m->cookie, MPU_STATPORT)
+#define READ(m)                MPUFOI_READ(m, m->cookie, MPU_DATAPORT)
+#define WRITE(m,d)     MPUFOI_WRITE(m, m->cookie, MPU_DATAPORT,d)
+
+struct mpu401 {
+       KOBJ_FIELDS;
+       struct snd_midi *mid;
+       int     flags;
+       driver_intr_t *si;
+       void   *cookie;
+       struct callout timer;
+};
+
+static void mpu401_timeout(void *m);
+static mpu401_intr_t mpu401_intr;
+
+static int mpu401_minit(struct snd_midi *, void *);
+static int mpu401_muninit(struct snd_midi *, void *);
+static int mpu401_minqsize(struct snd_midi *, void *);
+static int mpu401_moutqsize(struct snd_midi *, void *);
+static void mpu401_mcallback(struct snd_midi *, void *, int);
+static void mpu401_mcallbackp(struct snd_midi *, void *, int);
+static const char *mpu401_mdescr(struct snd_midi *, void *, int);
+static const char *mpu401_mprovider(struct snd_midi *, void *);
+
+static kobj_method_t mpu401_methods[] = {
+       KOBJMETHOD(mpu_init, mpu401_minit),
+       KOBJMETHOD(mpu_uninit, mpu401_muninit),
+       KOBJMETHOD(mpu_inqsize, mpu401_minqsize),
+       KOBJMETHOD(mpu_outqsize, mpu401_moutqsize),
+       KOBJMETHOD(mpu_callback, mpu401_mcallback),
+       KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp),
+       KOBJMETHOD(mpu_descr, mpu401_mdescr),
+       KOBJMETHOD(mpu_provider, mpu401_mprovider),
+       KOBJMETHOD_END
+};
+
+DEFINE_CLASS(mpu401, mpu401_methods, 0);
+
+void
+mpu401_timeout(void *a)
+{
+       struct mpu401 *m = (struct mpu401 *)a;
+
+       if (m->si)
+               (m->si)(m->cookie);
+
+}
+static int
+mpu401_intr(struct mpu401 *m)
+{
+#define MPU_INTR_BUF   16
+       MIDI_TYPE b[MPU_INTR_BUF];
+       int i;
+       int s;
+
+/*
+       printf("mpu401_intr\n");
+*/
+#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
+#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
+#if 0
+#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
+#else
+#define D(x,l)
+#endif
+       i = 0;
+       s = STATUS(m);
+       D(s, 1);
+       while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) {
+               b[i] = READ(m);
+/*
+               printf("mpu401_intr in i %d d %d\n", i, b[i]);
+*/
+               i++;
+               s = STATUS(m);
+       }
+       if (i)
+               midi_in(m->mid, b, i);
+       i = 0;
+       while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) {
+               if (midi_out(m->mid, b, 1)) {
+/*
+                       printf("mpu401_intr out i %d d %d\n", i, b[0]);
+*/
+
+                       WRITE(m, *b);
+               } else {
+/*
+                       printf("mpu401_intr write: no output\n");
+*/
+                       return 0;
+               }
+               i++;
+               /* DELAY(100); */
+               s = STATUS(m);
+       }
+
+       if ((m->flags & M_TXEN) && (m->si)) {
+               callout_reset(&m->timer, 1, mpu401_timeout, m);
+       }
+       return (m->flags & M_TXEN) == M_TXEN;
+}
+
+struct mpu401 *
+mpu401_init(kobj_class_t cls, void *cookie, driver_intr_t softintr,
+    mpu401_intr_t ** cb)
+{
+       struct mpu401 *m;
+
+       *cb = NULL;
+       m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
+
+       if (!m)
+               return NULL;
+
+       kobj_init((kobj_t)m, cls);
+
+       callout_init(&m->timer, CALLOUT_MPSAFE);
+
+       m->si = softintr;
+       m->cookie = cookie;
+       m->flags = 0;
+
+       m->mid = midi_init(&mpu401_class, 0, 0, m);
+       if (!m->mid)
+               goto err;
+       *cb = mpu401_intr;
+       return m;
+err:
+       printf("mpu401_init error\n");
+       free(m, M_MIDI);
+       return NULL;
+}
+
+int
+mpu401_uninit(struct mpu401 *m)
+{
+       int retval;
+
+       CMD(m, MPU_RESET);
+       retval = midi_uninit(m->mid);
+       if (retval)
+               return retval;
+       free(m, M_MIDI);
+       return 0;
+}
+
+static int
+mpu401_minit(struct snd_midi *sm, void *arg)
+{
+       struct mpu401 *m = arg;
+       int i;
+
+       CMD(m, MPU_RESET);
+       CMD(m, MPU_UART);
+       return 0;
+       i = 0;
+       while (++i < 2000) {
+               if (RXRDY(m))
+                       if (READ(m) == MPU_ACK)
+                               break;
+       }
+
+       if (i < 2000) {
+               CMD(m, MPU_UART);
+               return 0;
+       }
+       printf("mpu401_minit failed active sensing\n");
+       return 1;
+}
+
+
+int
+mpu401_muninit(struct snd_midi *sm, void *arg)
+{
+       struct mpu401 *m = arg;
+
+       return MPUFOI_UNINIT(m, m->cookie);
+}
+
+int
+mpu401_minqsize(struct snd_midi *sm, void *arg)
+{
+       return 128;
+}
+
+int
+mpu401_moutqsize(struct snd_midi *sm, void *arg)
+{
+       return 128;
+}
+
+static void
+mpu401_mcallback(struct snd_midi *sm, void *arg, int flags)
+{
+       struct mpu401 *m = arg;
+#if 0
+       printf("mpu401_callback %s %s %s %s\n",
+           flags & M_RX ? "M_RX" : "",
+           flags & M_TX ? "M_TX" : "",
+           flags & M_RXEN ? "M_RXEN" : "",
+           flags & M_TXEN ? "M_TXEN" : "");
+#endif
+       if (flags & M_TXEN && m->si) {
+               callout_reset(&m->timer, 1, mpu401_timeout, m);
+       }
+       m->flags = flags;
+}
+
+static void
+mpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags)
+{
+/*     printf("mpu401_callbackp\n"); */
+       mpu401_mcallback(sm, arg, flags);
+}
+
+static const char *
+mpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity)
+{
+
+       return "descr mpu401";
+}
+
+static const char *
+mpu401_mprovider(struct snd_midi *m, void *arg)
+{
+       return "provider mpu401";
+}
similarity index 77%
copy from sys/dev/sound/pcm/dsp.h
copy to sys/dev/sound/midi/mpu401.h
index 0362847..acede43 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
+ * Copyright (c) 2003 Mathew Kanner
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/sound/pcm/dsp.h,v 1.9 2005/01/06 01:43:20 imp Exp $
- * $DragonFly: src/sys/dev/sound/pcm/dsp.h,v 1.4 2007/06/14 21:48:36 corecode Exp $
+ * $FreeBSD: head/sys/dev/sound/midi/mpu401.h 166971 2007-02-25 13:51:52Z netchild $
  */
 
-#include <sys/device.h>
+#ifndef MPU401_H
+#define MPU401_H
 
-extern struct dev_ops dsp_ops;
-extern d_clone_t dsp_clone;
+struct mpu401;
 
-struct snddev_info *dsp_get_info(struct cdev *dev);
+typedef int mpu401_intr_t(struct mpu401 *_obj);
+
+extern struct mpu401 *
+mpu401_init(kobj_class_t _cls, void *cookie, driver_intr_t *_softintr,
+    mpu401_intr_t ** _cb);
+extern int mpu401_uninit(struct mpu401 *_obj);
+
+#endif
similarity index 65%
copy from sys/dev/sound/pcm/mixer_if.m
copy to sys/dev/sound/midi/mpu_if.m
index 5497dd8..979aa6b 100644 (file)
@@ -1,7 +1,5 @@
 #-
-# KOBJ
-#
-# Copyright (c) 2000 Cameron Grant <cg@freebsd.org>
+# Copyright (c) 2003 Mathew Kanner
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $FreeBSD: src/sys/dev/sound/pcm/mixer_if.m,v 1.6 2005/01/06 01:43:21 imp Exp $
-# $DragonFly: src/sys/dev/sound/pcm/mixer_if.m,v 1.4 2007/01/04 21:47:03 corecode Exp $
+# $FreeBSD: head/sys/dev/sound/midi/mpu_if.m 166971 2007-02-25 13:51:52Z netchild $
 #
 
-#include <dev/sound/pcm/sound.h>
-
-INTERFACE mixer;
+#include <dev/sound/midi/midi.h>
 
-CODE {
+INTERFACE mpu;
 
-       static int
-       mixer_noreinit(struct snd_mixer *m)
-       {
-               return 0;
-       }
+METHOD int inqsize {
+       struct snd_midi *_kobj;
+       void   *_cookie;
+};
 
+METHOD int outqsize {
+       struct snd_midi *_kobj;
+       void   *_cookie;
 };
 
 METHOD int init {
-       struct snd_mixer *m;
+       struct snd_midi *_kobj;
+       void   *_cookie;
+};
+
+METHOD void callbackp {
+       struct snd_midi *_kobj;
+       void   *_cookie;
+       int     _flags;
 };
 
-METHOD int reinit {
-       struct snd_mixer *m;
-} DEFAULT mixer_noreinit;
+METHOD void callback {
+       struct snd_midi *_kobj;
+       void   *_cookie;
+       int     _flags;
+};
 
-METHOD int uninit {
-       struct snd_mixer *m;
+METHOD const char * provider {
+       struct snd_midi *_kobj;
+       void   *_cookie;
 };
 
-METHOD int set {
-       struct snd_mixer *m;
-       unsigned dev;
-       unsigned left;
-       unsigned right;
+METHOD const char * descr {
+       struct snd_midi *_kobj;
+       void   *_cookie;
+       int     _verbosity;
 };
 
-METHOD u_int32_t setrecsrc {
-       struct snd_mixer *m;
-       u_int32_t src;
+METHOD int uninit {
+       struct snd_midi *_kobj;
+       void   *_cookie;
 };
similarity index 69%
copy from sys/dev/sound/pcm/ac97_if.m
copy to sys/dev/sound/midi/mpufoi_if.m
index 2edb36b..727bc1e 100644 (file)
@@ -1,7 +1,5 @@
 #-
-# KOBJ
-#
-# Copyright (c) 2000 Cameron Grant <cg@freebsd.org>
+# Copyright (c) 2003 Mathew Kanner
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $FreeBSD: src/sys/dev/sound/pcm/ac97_if.m,v 1.4 2005/01/06 01:43:20 imp Exp $
-# $DragonFly: src/sys/dev/sound/pcm/ac97_if.m,v 1.4 2007/01/04 21:47:03 corecode Exp $
+# $FreeBSD: head/sys/dev/sound/midi/mpufoi_if.m 166971 2007-02-25 13:51:52Z netchild $
 #
 
-#include <dev/sound/pcm/sound.h>
-
-INTERFACE ac97;
+#include <sys/bus.h>
+#include <dev/sound/midi/mpu401.h>
 
-CODE {
-
-       static u_int32_t
-       ac97_noinit(kobj_t obj, void *devinfo)
-       {
-               return 1;
-       }
+INTERFACE mpufoi;
 
+METHOD unsigned char read {
+       struct mpu401 *_kobj;
+       void   *_cookie;
+       int     _reg;
 };
 
-METHOD u_int32_t init {
-       kobj_t obj;
-       void *devinfo;
-} DEFAULT ac97_noinit;
-
-METHOD int read {
-       kobj_t obj;
-       void *devinfo;
-       int regno;
+METHOD void write {
+       struct mpu401 *_kobj;
+       void   *_cookie;
+       int     _reg;
+       unsigned char _d;
 };
 
-METHOD int write {
-       kobj_t obj;
-       void *devinfo;
-       int regno;
-       u_int32_t data;
+METHOD int uninit {
+       struct mpu401 *_kobj;
+       void   *_cookie;
 };
diff --git a/sys/dev/sound/midi/sequencer.c b/sys/dev/sound/midi/sequencer.c
new file mode 100644 (file)
index 0000000..3747a26
--- /dev/null
@@ -0,0 +1,2095 @@
+/*-
+ * Copyright (c) 2003 Mathew Kanner
+ * Copyright (c) 1993 Hannu Savolainen
+ * 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.
+ */
+
+/*
+ * The sequencer personality manager.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/sound/midi/sequencer.c 274035 2014-11-03 11:11:45Z bapt $");
+
+#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/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.h>
+#include <machine/clock.h>             /* for DELAY */
+#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 <sys/kthread.h>
+#include <sys/unistd.h>
+#include <sys/selinfo.h>
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/midi/midi.h>
+#include <dev/sound/midi/midiq.h>
+#include "synth_if.h"
+
+#include <dev/sound/midi/sequencer.h>
+
+#define TMR_TIMERBASE 13
+
+#define SND_DEV_SEQ    1               /* Sequencer output /dev/sequencer (FM
+                                        * synthesizer and MIDI output) */
+#define SND_DEV_MUSIC  8               /* /dev/music, level 2 interface */
+
+/* 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)
+
+#define PCMMKMINOR(u, d, c) \
+           ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
+#define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
+#define MIDIUNIT(y) ((dev2unit(y) >> 4) & 0x0f)
+#define MIDIDEV(y) (dev2unit(y) & 0x0f)
+
+/* 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;
+
+static struct cdevsw seq_cdevsw = {
+       .d_version = D_VERSION,
+       .d_open = seq_open,
+       .d_close = seq_close,
+       .d_read = seq_read,
+       .d_write = seq_write,
+       .d_ioctl = seq_ioctl,
+       .d_poll = seq_poll,
+       .d_name = "sequencer",
+};
+
+struct seq_softc {
+       KOBJ_FIELDS;
+
+       struct mtx seq_lock, q_lock;
+       struct cv empty_cv, reset_cv, in_cv, out_cv, state_cv, th_cv;
+
+       MIDIQ_HEAD(, u_char) in_q, out_q;
+
+       u_long  flags;
+       /* Flags (protected by flag_mtx of mididev_info) */
+       int     fflags;                 /* Access mode */
+       int     music;
+
+       int     out_water;              /* Sequence output threshould */
+       snd_sync_parm sync_parm;        /* AIOSYNC parameter set */
+       struct thread *sync_thread;     /* AIOSYNCing thread */
+       struct selinfo in_sel, out_sel;
+       int     midi_number;
+       struct cdev *seqdev, *musicdev;
+       int     unit;
+       int     maxunits;
+       kobj_t *midis;
+       int    *midi_flags;
+       kobj_t  mapper;
+       void   *mapper_cookie;
+       struct timeval timerstop, timersub;
+       int     timerbase, tempo;
+       int     timerrun;
+       int     done;
+       int     playing;
+       int     recording;
+       int     busy;
+       int     pre_event_timeout;
+       int     waiting;
+};
+
+/*
+ * Module specific stuff, including how many sequecers
+ * we currently own.
+ */
+
+SYSCTL_NODE(_hw_midi, OID_AUTO, seq, CTLFLAG_RD, 0, "Midi sequencer");
+
+int                                    seq_debug;
+/* XXX: should this be moved into debug.midi? */
+SYSCTL_INT(_hw_midi_seq, OID_AUTO, debug, CTLFLAG_RW, &seq_debug, 0, "");
+
+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_SEQ_GETTIME,    "SNDCTL_SEQ_GETTIME"},
+       {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},
+};
+
+midi_cmdtab    cmdtab_seqcv[] = {
+       {MIDI_NOTEOFF,          "MIDI_NOTEOFF"},
+       {MIDI_NOTEON,           "MIDI_NOTEON"},
+       {MIDI_KEY_PRESSURE,     "MIDI_KEY_PRESSURE"},
+       {-1,                    NULL},
+};
+
+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},
+};
+
+#ifndef KOBJMETHOD_END
+#define KOBJMETHOD_END { NULL, NULL }
+#endif
+
+/*
+ * static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
+ */
+
+static kobj_method_t seq_methods[] = {
+       /* KOBJMETHOD(mpu_provider,mpu401_mprovider), */
+       KOBJMETHOD_END
+};
+
+DEFINE_CLASS(sequencer, seq_methods, 0);
+
+/* The followings are the local function. */
+static int seq_convertold(u_char *event, u_char *out);
+
+/*
+ * static void seq_midiinput(struct seq_softc * scp, void *md);
+ */
+static void seq_reset(struct seq_softc *scp);
+static int seq_sync(struct seq_softc *scp);
+
+static int seq_processevent(struct seq_softc *scp, u_char *event);
+
+static int seq_timing(struct seq_softc *scp, u_char *event);
+static int seq_local(struct seq_softc *scp, u_char *event);
+
+static int seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event);
+static int seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event);
+static int seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event);
+
+static int seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md);
+void   seq_copytoinput(struct seq_softc *scp, u_char *event, int len);
+int    seq_modevent(module_t mod, int type, void *data);
+struct seq_softc *seqs[10];
+static struct mtx seqinfo_mtx;
+static u_long nseq = 0;
+
+static void timer_start(struct seq_softc *t);
+static void timer_stop(struct seq_softc *t);
+static void timer_setvals(struct seq_softc *t, int tempo, int timerbase);
+static void timer_wait(struct seq_softc *t, int ticks, int wait_abs);
+static int timer_now(struct seq_softc *t);
+
+
+static void
+timer_start(struct seq_softc *t)
+{
+       t->timerrun = 1;
+       getmicrotime(&t->timersub);
+}
+
+static void
+timer_continue(struct seq_softc *t)
+{
+       struct timeval now;
+
+       if (t->timerrun == 1)
+               return;
+       t->timerrun = 1;
+       getmicrotime(&now);
+       timevalsub(&now, &t->timerstop);
+       timevaladd(&t->timersub, &now);
+}
+
+static void
+timer_stop(struct seq_softc *t)
+{
+       t->timerrun = 0;
+       getmicrotime(&t->timerstop);
+}
+
+static void
+timer_setvals(struct seq_softc *t, int tempo, int timerbase)
+{
+       t->tempo = tempo;
+       t->timerbase = timerbase;
+}
+
+static void
+timer_wait(struct seq_softc *t, int ticks, int wait_abs)
+{
+       struct timeval now, when;
+       int ret;
+       unsigned long long i;
+
+       while (t->timerrun == 0) {
+               SEQ_DEBUG(2, printf("Timer wait when timer isn't running\n"));
+               /*
+                * The old sequencer used timeouts that only increased
+                * the timer when the timer was running.
+                * Hence the sequencer would stick (?) if the
+                * timer was disabled.
+                */
+               cv_wait(&t->reset_cv, &t->seq_lock);
+               if (t->playing == 0)
+                       return;
+       }
+
+       i = ticks * 60ull * 1000000ull / (t->tempo * t->timerbase);
+
+       when.tv_sec = i / 1000000;
+       when.tv_usec = i % 1000000;
+
+#if 0
+       printf("timer_wait tempo %d timerbase %d ticks %d abs %d u_sec %llu\n",
+           t->tempo, t->timerbase, ticks, wait_abs, i);
+#endif
+
+       if (wait_abs != 0) {
+               getmicrotime(&now);
+               timevalsub(&now, &t->timersub);
+               timevalsub(&when, &now);
+       }
+       if (when.tv_sec < 0 || when.tv_usec < 0) {
+               SEQ_DEBUG(3,
+                   printf("seq_timer error negative time %lds.%06lds\n",
+                   (long)when.tv_sec, (long)when.tv_usec));
+               return;
+       }
+       i = when.tv_sec * 1000000ull;
+       i += when.tv_usec;
+       i *= hz;
+       i /= 1000000ull;
+#if 0
+       printf("seq_timer usec %llu ticks %llu\n",
+           when.tv_sec * 1000000ull + when.tv_usec, i);
+#endif
+       t->waiting = 1;
+       ret = cv_timedwait(&t->reset_cv, &t->seq_lock, i + 1);
+       t->waiting = 0;
+
+       if (ret != EWOULDBLOCK)
+               SEQ_DEBUG(3, printf("seq_timer didn't timeout\n"));
+
+}
+
+static int
+timer_now(struct seq_softc *t)
+{
+       struct timeval now;
+       unsigned long long i;
+       int ret;
+
+       if (t->timerrun == 0)
+               now = t->timerstop;
+       else
+               getmicrotime(&now);
+
+       timevalsub(&now, &t->timersub);
+
+       i = now.tv_sec * 1000000ull;
+       i += now.tv_usec;
+       i *= t->timerbase;
+/*     i /= t->tempo; */
+       i /= 1000000ull;
+
+       ret = i;
+       /*
+        * printf("timer_now: %llu %d\n", i, ret);
+        */
+
+       return ret;
+}
+
+static void
+seq_eventthread(void *arg)
+{
+       struct seq_softc *scp = arg;
+       char event[EV_SZ];
+
+       mtx_lock(&scp->seq_lock);
+       SEQ_DEBUG(2, printf("seq_eventthread started\n"));
+       while (scp->done == 0) {
+restart:
+               while (scp->playing == 0) {
+                       cv_wait(&scp->state_cv, &scp->seq_lock);
+                       if (scp->done)
+                               goto done;
+               }
+
+               while (MIDIQ_EMPTY(scp->out_q)) {
+                       cv_broadcast(&scp->empty_cv);
+                       cv_wait(&scp->out_cv, &scp->seq_lock);
+                       if (scp->playing == 0)
+                               goto restart;
+                       if (scp->done)
+                               goto done;
+               }
+
+               MIDIQ_DEQ(scp->out_q, event, EV_SZ);
+
+               if (MIDIQ_AVAIL(scp->out_q) < scp->out_water) {
+                       cv_broadcast(&scp->out_cv);
+                       selwakeup(&scp->out_sel);
+               }
+               seq_processevent(scp, event);
+       }
+
+done:
+       cv_broadcast(&scp->th_cv);
+       mtx_unlock(&scp->seq_lock);
+       SEQ_DEBUG(2, printf("seq_eventthread finished\n"));
+       kproc_exit(0);
+}
+
+/*
+ * seq_processevent:  This maybe called by the event thread or the IOCTL
+ * handler for queued and out of band events respectively.
+ */
+static int
+seq_processevent(struct seq_softc *scp, u_char *event)
+{
+       int ret;
+       kobj_t m;
+
+       ret = 0;
+
+       if (event[0] == EV_SEQ_LOCAL)
+               ret = seq_local(scp, event);
+       else if (event[0] == EV_TIMING)
+               ret = seq_timing(scp, event);
+       else if (event[0] != EV_CHN_VOICE &&
+                   event[0] != EV_CHN_COMMON &&
+                   event[0] != EV_SYSEX &&
+           event[0] != SEQ_MIDIPUTC) {
+               ret = 1;
+               SEQ_DEBUG(2, printf("seq_processevent not known %d\n",
+                   event[0]));
+       } else if (seq_fetch_mid(scp, event[1], &m) != 0) {
+               ret = 1;
+               SEQ_DEBUG(2, printf("seq_processevent midi unit not found %d\n",
+                   event[1]));
+       } else
+               switch (event[0]) {
+               case EV_CHN_VOICE:
+                       ret = seq_chnvoice(scp, m, event);
+                       break;
+               case EV_CHN_COMMON:
+                       ret = seq_chncommon(scp, m, event);
+                       break;
+               case EV_SYSEX:
+                       ret = seq_sysex(scp, m, event);
+                       break;
+               case SEQ_MIDIPUTC:
+                       mtx_unlock(&scp->seq_lock);
+                       ret = SYNTH_WRITERAW(m, &event[2], 1);
+                       mtx_lock(&scp->seq_lock);
+                       break;
+               }
+       return ret;
+}
+
+static int
+seq_addunit(void)
+{
+       struct seq_softc *scp;
+       int ret;
+       u_char *buf;
+
+       /* Allocate the softc. */
+       ret = ENOMEM;
+       scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (scp == NULL) {
+               SEQ_DEBUG(1, printf("seq_addunit: softc allocation failed.\n"));
+               goto err;
+       }
+       kobj_init((kobj_t)scp, &sequencer_class);
+
+       buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO);
+       if (buf == NULL)
+               goto err;
+       MIDIQ_INIT(scp->in_q, buf, EV_SZ * 1024);
+       buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO);
+       if (buf == NULL)
+               goto err;
+       MIDIQ_INIT(scp->out_q, buf, EV_SZ * 1024);
+       ret = EINVAL;
+
+       scp->midis = malloc(sizeof(kobj_t) * 32, M_TEMP, M_NOWAIT | M_ZERO);
+       scp->midi_flags = malloc(sizeof(*scp->midi_flags) * 32, M_TEMP,
+           M_NOWAIT | M_ZERO);
+
+       if (scp->midis == NULL || scp->midi_flags == NULL)
+               goto err;
+
+       scp->flags = 0;
+
+       mtx_init(&scp->seq_lock, "seqflq", NULL, 0);
+       cv_init(&scp->state_cv, "seqstate");
+       cv_init(&scp->empty_cv, "seqempty");
+       cv_init(&scp->reset_cv, "seqtimer");
+       cv_init(&scp->out_cv, "seqqout");
+       cv_init(&scp->in_cv, "seqqin");
+       cv_init(&scp->th_cv, "seqstart");
+
+       /*
+        * Init the damn timer
+        */
+
+       scp->mapper = midimapper_addseq(scp, &scp->unit, &scp->mapper_cookie);
+       if (scp->mapper == NULL)
+               goto err;
+
+       scp->seqdev = make_dev(&seq_cdevsw,
+           MIDIMKMINOR(scp->unit, SND_DEV_SEQ, 0), UID_ROOT,
+           GID_WHEEL, 0666, "sequencer%d", scp->unit);
+
+       scp->musicdev = make_dev(&seq_cdevsw,
+           MIDIMKMINOR(scp->unit, SND_DEV_MUSIC, 0), UID_ROOT,
+           GID_WHEEL, 0666, "music%d", scp->unit);
+
+       if (scp->seqdev == NULL || scp->musicdev == NULL)
+               goto err;
+       /*
+        * TODO: Add to list of sequencers this module provides
+        */
+
+       ret =
+           kproc_create
+           (seq_eventthread, scp, NULL, RFHIGHPID, 0,
+           "sequencer %02d", scp->unit);
+
+       if (ret)
+               goto err;
+
+       scp->seqdev->si_drv1 = scp->musicdev->si_drv1 = scp;
+
+       SEQ_DEBUG(2, printf("sequencer %d created scp %p\n", scp->unit, scp));
+
+       ret = 0;
+
+       mtx_lock(&seqinfo_mtx);
+       seqs[nseq++] = scp;
+       mtx_unlock(&seqinfo_mtx);
+
+       goto ok;
+
+err:
+       if (scp != NULL) {
+               if (scp->seqdev != NULL)
+                       destroy_dev(scp->seqdev);
+               if (scp->musicdev != NULL)
+                       destroy_dev(scp->musicdev);
+               /*
+                * TODO: Destroy mutex and cv
+                */
+               if (scp->midis != NULL)
+                       free(scp->midis, M_TEMP);
+               if (scp->midi_flags != NULL)
+                       free(scp->midi_flags, M_TEMP);
+               if (scp->out_q.b)
+                       free(scp->out_q.b, M_TEMP);
+               if (scp->in_q.b)
+                       free(scp->in_q.b, M_TEMP);
+               free(scp, M_DEVBUF);
+       }
+ok:
+       return ret;
+}
+
+static int
+seq_delunit(int unit)
+{
+       struct seq_softc *scp = seqs[unit];
+       int i;
+
+       //SEQ_DEBUG(4, printf("seq_delunit: %d\n", unit));
+       SEQ_DEBUG(1, printf("seq_delunit: 1 \n"));
+       mtx_lock(&scp->seq_lock);
+
+       scp->playing = 0;
+       scp->done = 1;
+       cv_broadcast(&scp->out_cv);
+       cv_broadcast(&scp->state_cv);
+       cv_broadcast(&scp->reset_cv);
+       SEQ_DEBUG(1, printf("seq_delunit: 2 \n"));
+       cv_wait(&scp->th_cv, &scp->seq_lock);
+       SEQ_DEBUG(1, printf("seq_delunit: 3.0 \n"));
+       mtx_unlock(&scp->seq_lock);
+       SEQ_DEBUG(1, printf("seq_delunit: 3.1 \n"));
+
+       cv_destroy(&scp->state_cv);
+       SEQ_DEBUG(1, printf("seq_delunit: 4 \n"));
+       cv_destroy(&scp->empty_cv);
+       SEQ_DEBUG(1, printf("seq_delunit: 5 \n"));
+       cv_destroy(&scp->reset_cv);
+       SEQ_DEBUG(1, printf("seq_delunit: 6 \n"));
+       cv_destroy(&scp->out_cv);
+       SEQ_DEBUG(1, printf("seq_delunit: 7 \n"));
+       cv_destroy(&scp->in_cv);
+       SEQ_DEBUG(1, printf("seq_delunit: 8 \n"));
+       cv_destroy(&scp->th_cv);
+
+       SEQ_DEBUG(1, printf("seq_delunit: 10 \n"));
+       if (scp->seqdev)
+               destroy_dev(scp->seqdev);
+       SEQ_DEBUG(1, printf("seq_delunit: 11 \n"));
+       if (scp->musicdev)
+               destroy_dev(scp->musicdev);
+       SEQ_DEBUG(1, printf("seq_delunit: 12 \n"));
+       scp->seqdev = scp->musicdev = NULL;
+       if (scp->midis != NULL)
+               free(scp->midis, M_TEMP);
+       SEQ_DEBUG(1, printf("seq_delunit: 13 \n"));
+       if (scp->midi_flags != NULL)
+               free(scp->midi_flags, M_TEMP);
+       SEQ_DEBUG(1, printf("seq_delunit: 14 \n"));
+       free(scp->out_q.b, M_TEMP);
+       SEQ_DEBUG(1, printf("seq_delunit: 15 \n"));
+       free(scp->in_q.b, M_TEMP);
+
+       SEQ_DEBUG(1, printf("seq_delunit: 16 \n"));
+
+       mtx_destroy(&scp->seq_lock);
+       SEQ_DEBUG(1, printf("seq_delunit: 17 \n"));
+       free(scp, M_DEVBUF);
+
+       mtx_lock(&seqinfo_mtx);
+       for (i = unit; i < (nseq - 1); i++)
+               seqs[i] = seqs[i + 1];
+       nseq--;
+       mtx_unlock(&seqinfo_mtx);
+
+       return 0;
+}
+
+int
+seq_modevent(module_t mod, int type, void *data)
+{
+       int retval, r;
+
+       retval = 0;
+
+       switch (type) {
+       case MOD_LOAD:
+               mtx_init(&seqinfo_mtx, "seqmod", NULL, 0);
+               retval = seq_addunit();
+               break;
+
+       case MOD_UNLOAD:
+               while (nseq) {
+                       r = seq_delunit(nseq - 1);
+                       if (r) {
+                               retval = r;
+                               break;
+                       }
+               }
+               if (nseq == 0) {
+                       retval = 0;
+                       mtx_destroy(&seqinfo_mtx);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return retval;
+}
+
+static int
+seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md)
+{
+
+       if (unit > scp->midi_number || unit < 0)
+               return EINVAL;
+
+       *md = scp->midis[unit];
+
+       return 0;
+}
+
+int
+seq_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
+{
+       struct seq_softc *scp = i_dev->si_drv1;
+       int i;
+
+       if (scp == NULL)
+               return ENXIO;
+
+       SEQ_DEBUG(3, printf("seq_open: scp %p unit %d, flags 0x%x.\n",
+           scp, scp->unit, flags));
+
+       /*
+        * Mark this device busy.
+        */
+
+       mtx_lock(&scp->seq_lock);
+       if (scp->busy) {
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(2, printf("seq_open: unit %d is busy.\n", scp->unit));
+               return EBUSY;
+       }
+       scp->fflags = flags;
+       /*
+       if ((scp->fflags & O_NONBLOCK) != 0)
+               scp->flags |= SEQ_F_NBIO;
+               */
+       scp->music = MIDIDEV(i_dev) == SND_DEV_MUSIC;
+
+       /*
+        * Enumerate the available midi devices
+        */
+       scp->midi_number = 0;
+       scp->maxunits = midimapper_open(scp->mapper, &scp->mapper_cookie);
+
+       if (scp->maxunits == 0)
+               SEQ_DEBUG(2, printf("seq_open: no midi devices\n"));
+
+       for (i = 0; i < scp->maxunits; i++) {
+               scp->midis[scp->midi_number] =
+                   midimapper_fetch_synth(scp->mapper, scp->mapper_cookie, i);
+               if (scp->midis[scp->midi_number]) {
+                       if (SYNTH_OPEN(scp->midis[scp->midi_number], scp,
+                               scp->fflags) != 0)
+                               scp->midis[scp->midi_number] = NULL;
+                       else {
+                               scp->midi_flags[scp->midi_number] =
+                                   SYNTH_QUERY(scp->midis[scp->midi_number]);
+                               scp->midi_number++;
+                       }
+               }
+       }
+
+       timer_setvals(scp, 60, 100);
+
+       timer_start(scp);
+       timer_stop(scp);
+       /*
+        * actually, if we're in rdonly mode, we should start the timer
+        */
+       /*
+        * TODO: Handle recording now
+        */
+
+       scp->out_water = MIDIQ_SIZE(scp->out_q) / 2;
+
+       scp->busy = 1;
+       mtx_unlock(&scp->seq_lock);
+
+       SEQ_DEBUG(2, printf("seq_open: opened, mode %s.\n",
+           scp->music ? "music" : "sequencer"));
+       SEQ_DEBUG(2,
+           printf("Sequencer %d %p opened maxunits %d midi_number %d:\n",
+               scp->unit, scp, scp->maxunits, scp->midi_number));
+       for (i = 0; i < scp->midi_number; i++)
+               SEQ_DEBUG(3, printf("  midi %d %p\n", i, scp->midis[i]));
+
+       return 0;
+}
+
+/*
+ * seq_close
+ */
+int
+seq_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
+{
+       int i;
+       struct seq_softc *scp = i_dev->si_drv1;
+       int ret;
+
+       if (scp == NULL)
+               return ENXIO;
+
+       SEQ_DEBUG(2, printf("seq_close: unit %d.\n", scp->unit));
+
+       mtx_lock(&scp->seq_lock);
+
+       ret = ENXIO;
+       if (scp->busy == 0)
+               goto err;
+
+       seq_reset(scp);
+       seq_sync(scp);
+
+       for (i = 0; i < scp->midi_number; i++)
+               if (scp->midis[i])
+                       SYNTH_CLOSE(scp->midis[i]);
+
+       midimapper_close(scp->mapper, scp->mapper_cookie);
+
+       timer_stop(scp);
+
+       scp->busy = 0;
+       ret = 0;
+
+err:
+       SEQ_DEBUG(3, printf("seq_close: closed ret = %d.\n", ret));
+       mtx_unlock(&scp->seq_lock);
+       return ret;
+}
+
+int
+seq_read(struct cdev *i_dev, struct uio *uio, int ioflag)
+{
+       int retval, used;
+       struct seq_softc *scp = i_dev->si_drv1;
+
+#define SEQ_RSIZE 32
+       u_char buf[SEQ_RSIZE];
+
+       if (scp == NULL)
+               return ENXIO;
+
+       SEQ_DEBUG(7, printf("seq_read: unit %d, resid %zd.\n",
+           scp->unit, uio->uio_resid));
+
+       mtx_lock(&scp->seq_lock);
+       if ((scp->fflags & FREAD) == 0) {
+               SEQ_DEBUG(2, printf("seq_read: unit %d is not for reading.\n",
+                   scp->unit));
+               retval = EIO;
+               goto err1;
+       }
+       /*
+        * Begin recording.
+        */
+       /*
+        * if ((scp->flags & SEQ_F_READING) == 0)
+        */
+       /*
+        * TODO, start recording if not alread
+        */
+
+       /*
+        * I think the semantics are to return as soon
+        * as possible.
+        * Second thought, it doens't seem like midimoutain
+        * expects that at all.
+        * TODO: Look up in some sort of spec
+        */
+
+       while (uio->uio_resid > 0) {
+               while (MIDIQ_EMPTY(scp->in_q)) {
+                       retval = EWOULDBLOCK;
+                       /*
+                        * I wish I knew which one to care about
+                        */
+
+                       if (scp->fflags & O_NONBLOCK)
+                               goto err1;
+                       if (ioflag & O_NONBLOCK)
+                               goto err1;
+
+                       retval = cv_wait_sig(&scp->in_cv, &scp->seq_lock);
+                       if (retval == EINTR)
+                               goto err1;
+               }
+
+               used = MIN(MIDIQ_LEN(scp->in_q), uio->uio_resid);
+               used = MIN(used, SEQ_RSIZE);
+
+               SEQ_DEBUG(8, printf("midiread: uiomove cc=%d\n", used));
+               MIDIQ_DEQ(scp->in_q, buf, used);
+               retval = uiomove(buf, used, uio);
+               if (retval)
+                       goto err1;
+       }
+
+       retval = 0;
+err1:
+       mtx_unlock(&scp->seq_lock);
+       SEQ_DEBUG(6, printf("seq_read: ret %d, resid %zd.\n",
+           retval, uio->uio_resid));
+
+       return retval;
+}
+
+int
+seq_write(struct cdev *i_dev, struct uio *uio, int ioflag)
+{
+       u_char event[EV_SZ], newevent[EV_SZ], ev_code;
+       struct seq_softc *scp = i_dev->si_drv1;
+       int retval;
+       int used;
+
+       SEQ_DEBUG(7, printf("seq_write: unit %d, resid %zd.\n",
+           scp->unit, uio->uio_resid));
+
+       if (scp == NULL)
+               return ENXIO;
+
+       mtx_lock(&scp->seq_lock);
+
+       if ((scp->fflags & FWRITE) == 0) {
+               SEQ_DEBUG(2, printf("seq_write: unit %d is not for writing.\n",
+                   scp->unit));
+               retval = EIO;
+               goto err0;
+       }
+       while (uio->uio_resid > 0) {
+               while (MIDIQ_AVAIL(scp->out_q) == 0) {
+                       retval = EWOULDBLOCK;
+                       if (scp->fflags & O_NONBLOCK)
+                               goto err0;
+                       if (ioflag & O_NONBLOCK)
+                               goto err0;
+                       SEQ_DEBUG(8, printf("seq_write cvwait\n"));
+
+                       scp->playing = 1;
+                       cv_broadcast(&scp->out_cv);
+                       cv_broadcast(&scp->state_cv);
+
+                       retval = cv_wait_sig(&scp->out_cv, &scp->seq_lock);
+                       /*
+                        * We slept, maybe things have changed since last
+                        * dying check
+                        */
+                       if (retval == EINTR)
+                               goto err0;
+#if 0
+                       /*
+                        * Useless test
+                        */
+                       if (scp != i_dev->si_drv1)
+                               retval = ENXIO;
+#endif
+               }
+
+               used = MIN(uio->uio_resid, 4);
+
+               SEQ_DEBUG(8, printf("seqout: resid %zd len %jd avail %jd\n",
+                   uio->uio_resid, (intmax_t)MIDIQ_LEN(scp->out_q),
+                   (intmax_t)MIDIQ_AVAIL(scp->out_q)));
+
+               if (used != 4) {
+                       retval = ENXIO;
+                       goto err0;
+               }
+               retval = uiomove(event, used, uio);
+               if (retval)
+                       goto err0;
+
+               ev_code = event[0];
+               SEQ_DEBUG(8, printf("seq_write: unit %d, event %s.\n",
+                   scp->unit, midi_cmdname(ev_code, cmdtab_seqevent)));
+
+               /* Have a look at the event code. */
+               if (ev_code == SEQ_FULLSIZE) {
+
+                       /*
+                        * TODO: restore code for SEQ_FULLSIZE
+                        */
+#if 0
+                       /*
+                        * A long event, these are the patches/samples for a
+                        * synthesizer.
+                        */
+                       midiunit = *(u_short *)&event[2];
+                       mtx_lock(&sd->seq_lock);
+                       ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md);
+                       mtx_unlock(&sd->seq_lock);
+                       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);
+#else
+                       /*
+                        * For now, just flush the darn buffer
+                        */
+                       SEQ_DEBUG(2,
+                          printf("seq_write: SEQ_FULLSIZE flusing buffer.\n"));
+                       while (uio->uio_resid > 0) {
+                               retval = uiomove(event, EV_SZ, uio);
+                               if (retval)
+                                       goto err0;
+
+                       }
+                       retval = 0;
+                       goto err0;
+#endif
+               }
+               retval = EINVAL;
+               if (ev_code >= 128) {
+
+                       /*
+                        * Some sort of an extended event. The size is eight
+                        * bytes. scoop extra info.
+                        */
+                       if (scp->music && ev_code == SEQ_EXTENDED) {
+                               SEQ_DEBUG(2, printf("seq_write: invalid level two event %x.\n", ev_code));
+                               goto err0;
+                       }
+                       if (uiomove((caddr_t)&event[4], 4, uio)) {
+                               SEQ_DEBUG(2,
+                                  printf("seq_write: user memory mangled?\n"));
+                               goto err0;
+                       }
+               } else {
+                       /*
+                        * Size four event.
+                        */
+                       if (scp->music) {
+                               SEQ_DEBUG(2, printf("seq_write: four byte event in music mode.\n"));
+                               goto err0;
+                       }
+               }
+               if (ev_code == SEQ_MIDIPUTC) {
+                       /*
+                        * TODO: event[2] is unit number to receive char.
+                        * Range check it.
+                        */
+               }
+               if (scp->music) {
+#ifdef not_ever_ever
+                       if (event[0] == EV_TIMING &&
+                           (event[1] == TMR_START || event[1] == TMR_STOP)) {
+                               /*
+                                * For now, try to make midimoutain work by
+                                * forcing these events to be processed
+                                * immediatly.
+                                */
+                               seq_processevent(scp, event);
+                       } else
+                               MIDIQ_ENQ(scp->out_q, event, EV_SZ);
+#else
+                       MIDIQ_ENQ(scp->out_q, event, EV_SZ);
+#endif
+               } else {
+                       if (seq_convertold(event, newevent) > 0)
+                               MIDIQ_ENQ(scp->out_q, newevent, EV_SZ);
+#if 0
+                       else
+                               goto err0;
+#endif
+               }
+
+       }
+
+       scp->playing = 1;
+       cv_broadcast(&scp->state_cv);
+       cv_broadcast(&scp->out_cv);
+
+       retval = 0;
+
+err0:
+       SEQ_DEBUG(6,
+           printf("seq_write done: leftover buffer length %zd retval %d\n",
+           uio->uio_resid, retval));
+       mtx_unlock(&scp->seq_lock);
+       return retval;
+}
+
+int
+seq_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
+    struct thread *td)
+{
+       int midiunit, ret, tmp;
+       struct seq_softc *scp = i_dev->si_drv1;
+       struct synth_info *synthinfo;
+       struct midi_info *midiinfo;
+       u_char event[EV_SZ];
+       u_char newevent[EV_SZ];
+
+       kobj_t md;
+
+       /*
+        * struct snd_size *sndsize;
+        */
+
+       if (scp == NULL)
+               return ENXIO;
+
+       SEQ_DEBUG(6, printf("seq_ioctl: unit %d, cmd %s.\n",
+           scp->unit, midi_cmdname(cmd, cmdtab_seqioctl)));
+
+       ret = 0;
+
+       switch (cmd) {
+       case SNDCTL_SEQ_GETTIME:
+               /*
+                * ioctl needed by libtse
+                */
+               mtx_lock(&scp->seq_lock);
+               *(int *)arg = timer_now(scp);
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(6, printf("seq_ioctl: gettime %d.\n", *(int *)arg));
+               ret = 0;
+               break;
+       case SNDCTL_TMR_METRONOME:
+               /* fallthrough */
+       case SNDCTL_TMR_SOURCE:
+               /*
+                * Not implemented
+                */
+               ret = 0;
+               break;
+       case SNDCTL_TMR_TEMPO:
+               event[1] = TMR_TEMPO;
+               event[4] = *(int *)arg & 0xFF;
+               event[5] = (*(int *)arg >> 8) & 0xFF;
+               event[6] = (*(int *)arg >> 16) & 0xFF;
+               event[7] = (*(int *)arg >> 24) & 0xFF;
+               goto timerevent;
+       case SNDCTL_TMR_TIMEBASE:
+               event[1] = TMR_TIMERBASE;
+               event[4] = *(int *)arg & 0xFF;
+               event[5] = (*(int *)arg >> 8) & 0xFF;
+               event[6] = (*(int *)arg >> 16) & 0xFF;
+               event[7] = (*(int *)arg >> 24) & 0xFF;
+               goto timerevent;
+       case SNDCTL_TMR_START:
+               event[1] = TMR_START;
+               goto timerevent;
+       case SNDCTL_TMR_STOP:
+               event[1] = TMR_STOP;
+               goto timerevent;
+       case SNDCTL_TMR_CONTINUE:
+               event[1] = TMR_CONTINUE;
+timerevent:
+               event[0] = EV_TIMING;
+               mtx_lock(&scp->seq_lock);
+               if (!scp->music) {
+                       ret = EINVAL;
+                       mtx_unlock(&scp->seq_lock);
+                       break;
+               }
+               seq_processevent(scp, event);
+               mtx_unlock(&scp->seq_lock);
+               break;
+       case SNDCTL_TMR_SELECT:
+               SEQ_DEBUG(2,
+                   printf("seq_ioctl: SNDCTL_TMR_SELECT not supported\n"));
+               ret = EINVAL;
+               break;
+       case SNDCTL_SEQ_SYNC:
+               if (mode == O_RDONLY) {
+                       ret = 0;
+                       break;
+               }
+               mtx_lock(&scp->seq_lock);
+               ret = seq_sync(scp);
+               mtx_unlock(&scp->seq_lock);
+               break;
+       case SNDCTL_SEQ_PANIC:
+               /* fallthrough */
+       case SNDCTL_SEQ_RESET:
+               /*
+                * SNDCTL_SEQ_PANIC == SNDCTL_SEQ_RESET
+                */
+               mtx_lock(&scp->seq_lock);
+               seq_reset(scp);
+               mtx_unlock(&scp->seq_lock);
+               ret = 0;
+               break;
+       case SNDCTL_SEQ_TESTMIDI:
+               mtx_lock(&scp->seq_lock);
+               /*
+                * TODO: SNDCTL_SEQ_TESTMIDI now means "can I write to the
+                * device?".
+                */
+               mtx_unlock(&scp->seq_lock);
+               break;
+#if 0
+       case SNDCTL_SEQ_GETINCOUNT:
+               if (mode == O_WRONLY)
+                       *(int *)arg = 0;
+               else {
+                       mtx_lock(&scp->seq_lock);
+                       *(int *)arg = scp->in_q.rl;
+                       mtx_unlock(&scp->seq_lock);
+                       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(&scp->seq_lock);
+                       *(int *)arg = scp->out_q.fl;
+                       mtx_unlock(&scp->seq_lock);
+                       SEQ_DEBUG(printf("seq_ioctl: outcount %d.\n",
+                           *(int *)arg));
+               }
+               ret = 0;
+               break;
+#endif
+       case SNDCTL_SEQ_CTRLRATE:
+               if (*(int *)arg != 0) {
+                       ret = EINVAL;
+                       break;
+               }
+               mtx_lock(&scp->seq_lock);
+               *(int *)arg = scp->timerbase;
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(3, printf("seq_ioctl: ctrlrate %d.\n", *(int *)arg));
+               ret = 0;
+               break;
+               /*
+                * TODO: ioctl SNDCTL_SEQ_RESETSAMPLES
+                */
+#if 0
+       case SNDCTL_SEQ_RESETSAMPLES:
+               mtx_lock(&scp->seq_lock);
+               ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md);
+               mtx_unlock(&scp->seq_lock);
+               if (ret != 0)
+                       break;
+               ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg,
+                   SND_DEV_MIDIN), cmd, arg, mode, td);
+               break;
+#endif
+       case SNDCTL_SEQ_NRSYNTHS:
+               mtx_lock(&scp->seq_lock);
+               *(int *)arg = scp->midi_number;
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(3, printf("seq_ioctl: synths %d.\n", *(int *)arg));
+               ret = 0;
+               break;
+       case SNDCTL_SEQ_NRMIDIS:
+               mtx_lock(&scp->seq_lock);
+               if (scp->music)
+                       *(int *)arg = 0;
+               else {
+                       /*
+                        * TODO: count the numbder of devices that can WRITERAW
+                        */
+                       *(int *)arg = scp->midi_number;
+               }
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(3, printf("seq_ioctl: midis %d.\n", *(int *)arg));
+               ret = 0;
+               break;
+               /*
+                * TODO: ioctl SNDCTL_SYNTH_MEMAVL
+                */
+#if 0
+       case SNDCTL_SYNTH_MEMAVL:
+               mtx_lock(&scp->seq_lock);
+               ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md);
+               mtx_unlock(&scp->seq_lock);
+               if (ret != 0)
+                       break;
+               ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg,
+                   SND_DEV_MIDIN), cmd, arg, mode, td);
+               break;
+#endif
+       case SNDCTL_SEQ_OUTOFBAND:
+               for (ret = 0; ret < EV_SZ; ret++)
+                       event[ret] = (u_char)arg[0];
+
+               mtx_lock(&scp->seq_lock);
+               if (scp->music)
+                       ret = seq_processevent(scp, event);
+               else {
+                       if (seq_convertold(event, newevent) > 0)
+                               ret = seq_processevent(scp, newevent);
+                       else
+                               ret = EINVAL;
+               }
+               mtx_unlock(&scp->seq_lock);
+               break;
+       case SNDCTL_SYNTH_INFO:
+               synthinfo = (struct synth_info *)arg;
+               midiunit = synthinfo->device;
+               mtx_lock(&scp->seq_lock);
+               if (seq_fetch_mid(scp, midiunit, &md) == 0) {
+                       bzero(synthinfo, sizeof(*synthinfo));
+                       synthinfo->name[0] = 'f';
+                       synthinfo->name[1] = 'a';
+                       synthinfo->name[2] = 'k';
+                       synthinfo->name[3] = 'e';
+                       synthinfo->name[4] = 's';
+                       synthinfo->name[5] = 'y';
+                       synthinfo->name[6] = 'n';
+                       synthinfo->name[7] = 't';
+                       synthinfo->name[8] = 'h';
+                       synthinfo->device = midiunit;
+                       synthinfo->synth_type = SYNTH_TYPE_MIDI;
+                       synthinfo->capabilities = scp->midi_flags[midiunit];
+                       ret = 0;
+               } else
+                       ret = EINVAL;
+               mtx_unlock(&scp->seq_lock);
+               break;
+       case SNDCTL_MIDI_INFO:
+               midiinfo = (struct midi_info *)arg;
+               midiunit = midiinfo->device;
+               mtx_lock(&scp->seq_lock);
+               if (seq_fetch_mid(scp, midiunit, &md) == 0) {
+                       bzero(midiinfo, sizeof(*midiinfo));
+                       midiinfo->name[0] = 'f';
+                       midiinfo->name[1] = 'a';
+                       midiinfo->name[2] = 'k';
+                       midiinfo->name[3] = 'e';
+                       midiinfo->name[4] = 'm';
+                       midiinfo->name[5] = 'i';
+                       midiinfo->name[6] = 'd';
+                       midiinfo->name[7] = 'i';
+                       midiinfo->device = midiunit;
+                       midiinfo->capabilities = scp->midi_flags[midiunit];
+                       /*
+                        * TODO: What devtype?
+                        */
+                       midiinfo->dev_type = 0x01;
+                       ret = 0;
+               } else
+                       ret = EINVAL;
+               mtx_unlock(&scp->seq_lock);
+               break;
+       case SNDCTL_SEQ_THRESHOLD:
+               mtx_lock(&scp->seq_lock);
+               RANGE(*(int *)arg, 1, MIDIQ_SIZE(scp->out_q) - 1);
+               scp->out_water = *(int *)arg;
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(3, printf("seq_ioctl: water %d.\n", *(int *)arg));
+               ret = 0;
+               break;
+       case SNDCTL_MIDI_PRETIME:
+               tmp = *(int *)arg;
+               if (tmp < 0)
+                       tmp = 0;
+               mtx_lock(&scp->seq_lock);
+               scp->pre_event_timeout = (hz * tmp) / 10;
+               *(int *)arg = scp->pre_event_timeout;
+               mtx_unlock(&scp->seq_lock);
+               SEQ_DEBUG(3, printf("seq_ioctl: pretime %d.\n", *(int *)arg));
+               ret = 0;
+               break;
+       case SNDCTL_FM_4OP_ENABLE:
+       case SNDCTL_PMGR_IFACE:
+       case SNDCTL_PMGR_ACCESS:
+               /*
+                * Patch manager and fm are ded, ded, ded.
+                */
+               /* fallthrough */
+       default:
+               /*
+                * TODO: Consider ioctl default case.
+                * Old code used to
+                * if ((scp->fflags & O_ACCMODE) == FREAD) {
+                *      ret = EIO;
+                *      break;
+                * }
+                * Then pass on the ioctl to device 0
+                */
+               SEQ_DEBUG(2,
+                   printf("seq_ioctl: unsupported IOCTL %ld.\n", cmd));
+               ret = EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+int
+seq_poll(struct cdev *i_dev, int events, struct thread *td)
+{
+       int ret, lim;
+       struct seq_softc *scp = i_dev->si_drv1;
+
+       SEQ_DEBUG(3, printf("seq_poll: unit %d.\n", scp->unit));
+       SEQ_DEBUG(1, printf("seq_poll: unit %d.\n", scp->unit));
+
+       mtx_lock(&scp->seq_lock);
+
+       ret = 0;
+
+       /* Look up the apropriate queue and select it. */
+       if ((events & (POLLOUT | POLLWRNORM)) != 0) {
+               /* Start playing. */
+               scp->playing = 1;
+               cv_broadcast(&scp->state_cv);
+               cv_broadcast(&scp->out_cv);
+
+               lim = scp->out_water;
+
+               if (MIDIQ_AVAIL(scp->out_q) < lim)
+                       /* No enough space, record select. */
+                       selrecord(td, &scp->out_sel);
+               else
+                       /* We can write now. */
+                       ret |= events & (POLLOUT | POLLWRNORM);
+       }
+       if ((events & (POLLIN | POLLRDNORM)) != 0) {
+               /* TODO: Start recording. */
+
+               /* Find out the boundary. */
+               lim = 1;
+               if (MIDIQ_LEN(scp->in_q) < lim)
+                       /* No data ready, record select. */
+                       selrecord(td, &scp->in_sel);
+               else
+                       /* We can read now. */
+                       ret |= events & (POLLIN | POLLRDNORM);
+       }
+       mtx_unlock(&scp->seq_lock);
+
+       return (ret);
+}
+
+#if 0
+static void
+sein_qtr(void *p, void /* mididev_info */ *md)
+{
+       struct seq_softc *scp;
+
+       scp = (struct seq_softc *)p;
+
+       mtx_lock(&scp->seq_lock);
+
+       /* Restart playing if we have the data to output. */
+       if (scp->queueout_pending)
+               seq_callback(scp, SEQ_CB_START | SEQ_CB_WR);
+       /* Check the midi device if we are reading. */
+       if ((scp->flags & SEQ_F_READING) != 0)
+               seq_midiinput(scp, md);
+
+       mtx_unlock(&scp->seq_lock);
+}
+
+#endif
+/*
+ * seq_convertold
+ * Was the old playevent.  Use this to convert and old
+ * style /dev/sequencer event to a /dev/music event
+ */
+static int
+seq_convertold(u_char *event, u_char *out)
+{
+       int used;
+       u_char dev, chn, note, vel;
+
+       out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] =
+           out[7] = 0;
+
+       dev = 0;
+       chn = event[1];
+       note = event[2];
+       vel = event[3];
+
+       used = 0;
+
+restart:
+       /*
+        * TODO: Debug statement
+        */
+       switch (event[0]) {
+       case EV_TIMING:
+       case EV_CHN_VOICE:
+       case EV_CHN_COMMON:
+       case EV_SYSEX:
+       case EV_SEQ_LOCAL:
+               out[0] = event[0];
+               out[1] = event[1];
+               out[2] = event[2];
+               out[3] = event[3];
+               out[4] = event[4];
+               out[5] = event[5];
+               out[6] = event[6];
+               out[7] = event[7];
+               used += 8;
+               break;
+       case SEQ_NOTEOFF:
+               out[0] = EV_CHN_VOICE;
+               out[1] = dev;
+               out[2] = MIDI_NOTEOFF;
+               out[3] = chn;
+               out[4] = note;
+               out[5] = 255;
+               used += 4;
+               break;
+
+       case SEQ_NOTEON:
+               out[0] = EV_CHN_VOICE;
+               out[1] = dev;
+               out[2] = MIDI_NOTEON;
+               out[3] = chn;
+               out[4] = note;
+               out[5] = vel;
+               used += 4;
+               break;
+
+               /*
+                * wait delay = (event[2] << 16) + (event[3] << 8) + event[4]
+                */
+
+       case SEQ_PGMCHANGE:
+               out[0] = EV_CHN_COMMON;
+               out[1] = dev;
+               out[2] = MIDI_PGM_CHANGE;
+               out[3] = chn;
+               out[4] = note;
+               out[5] = vel;
+               used += 4;
+               break;
+/*
+               out[0] = EV_TIMING;
+               out[1] = dev;
+               out[2] = MIDI_PGM_CHANGE;
+               out[3] = chn;
+               out[4] = note;
+               out[5] = vel;
+               SEQ_DEBUG(4,printf("seq_playevent: synctimer\n"));
+               break;
+*/
+
+       case SEQ_MIDIPUTC:
+               SEQ_DEBUG(4,
+                   printf("seq_playevent: put data 0x%02x, unit %d.\n",
+                   event[1], event[2]));
+               /*
+                * Pass through to the midi device.
+                * device = event[2]
+                * data = event[1]
+                */
+               out[0] = SEQ_MIDIPUTC;
+               out[1] = dev;
+               out[2] = chn;
+               used += 4;
+               break;
+#ifdef notyet
+       case SEQ_ECHO:
+               /*
+                * This isn't handled here yet because I don't know if I can
+                * just use four bytes events.  There might be consequences
+                * in the _read routing
+                */
+               if (seq_copytoinput(scp, event, 4) == EAGAIN) {
+                       ret = QUEUEFULL;
+                       break;
+               }
+               ret = MORE;
+               break;
+#endif
+       case SEQ_EXTENDED:
+               switch (event[1]) {
+               case SEQ_NOTEOFF:
+               case SEQ_NOTEON:
+               case SEQ_PGMCHANGE:
+                       event++;
+                       used = 4;
+                       goto restart;
+                       break;
+               case SEQ_AFTERTOUCH:
+                       /*
+                        * SYNTH_AFTERTOUCH(md, event[3], event[4])
+                        */
+               case SEQ_BALANCE:
+                       /*
+                        * SYNTH_PANNING(md, event[3], (char)event[4])
+                        */
+               case SEQ_CONTROLLER:
+                       /*
+                        * SYNTH_CONTROLLER(md, event[3], event[4], *(short *)&event[5])
+                        */
+               case SEQ_VOLMODE:
+                       /*
+                        * SYNTH_VOLUMEMETHOD(md, event[3])
+                        */
+               default:
+                       SEQ_DEBUG(2,
+                           printf("seq_convertold: SEQ_EXTENDED type %d"
+                           "not handled\n", event[1]));
+                       break;
+               }
+               break;
+       case SEQ_WAIT:
+               out[0] = EV_TIMING;
+               out[1] = TMR_WAIT_REL;
+               out[4] = event[2];
+               out[5] = event[3];
+               out[6] = event[4];
+
+               SEQ_DEBUG(5, printf("SEQ_WAIT %d",
+                   event[2] + (event[3] << 8) + (event[4] << 24)));
+
+               used += 4;
+               break;
+
+       case SEQ_ECHO:
+       case SEQ_SYNCTIMER:
+       case SEQ_PRIVATE:
+       default:
+               SEQ_DEBUG(2,
+                 printf("seq_convertold: event type %d not handled %d %d %d\n",
+                   event[0], event[1], event[2], event[3]));
+               break;
+       }
+       return used;
+}
+
+/*
+ * Writting to the sequencer buffer never blocks and drops
+ * input which cannot be queued
+ */
+void
+seq_copytoinput(struct seq_softc *scp, u_char *event, int len)
+{
+
+       mtx_assert(&scp->seq_lock, MA_OWNED);
+
+       if (MIDIQ_AVAIL(scp->in_q) < len) {
+               /*
+                * ENOROOM?  EINPUTDROPPED? ETOUGHLUCK?
+                */
+               SEQ_DEBUG(2, printf("seq_copytoinput: queue full\n"));
+       } else {
+               MIDIQ_ENQ(scp->in_q, event, len);
+               selwakeup(&scp->in_sel);
+               cv_broadcast(&scp->in_cv);
+       }
+
+}
+
+static int
+seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event)
+{
+       int ret, voice;
+       u_char cmd, chn, note, parm;
+
+       ret = 0;
+       cmd = event[2];
+       chn = event[3];
+       note = event[4];
+       parm = event[5];
+
+       mtx_assert(&scp->seq_lock, MA_OWNED);
+
+       SEQ_DEBUG(5, printf("seq_chnvoice: unit %d, dev %d, cmd %s,"
+           " chn %d, note %d, parm %d.\n", scp->unit, event[1],
+           midi_cmdname(cmd, cmdtab_seqcv), chn, note, parm));
+
+       voice = SYNTH_ALLOC(md, chn, note);
+
+       mtx_unlock(&scp->seq_lock);
+
+       switch (cmd) {
+       case MIDI_NOTEON:
+               if (note < 128 || note == 255) {
+#if 0
+                       if (scp->music && chn == 9) {
+                               /*
+                                * This channel is a percussion. The note
+                                * number is the patch number.
+                                */
+                               /*
+                               mtx_unlock(&scp->seq_lock);
+                               if (SYNTH_SETINSTR(md, voice, 128 + note)
+                                   == EAGAIN) {
+                                       mtx_lock(&scp->seq_lock);
+                                       return (QUEUEFULL);
+                               }
+                               mtx_lock(&scp->seq_lock);
+                               */
+                               note = 60;      /* Middle C. */
+                       }
+#endif
+                       if (scp->music) {
+                               /*
+                               mtx_unlock(&scp->seq_lock);
+                               if (SYNTH_SETUPVOICE(md, voice, chn)
+                                   == EAGAIN) {
+                                       mtx_lock(&scp->seq_lock);
+                                       return (QUEUEFULL);
+                               }
+                               mtx_lock(&scp->seq_lock);
+                               */
+                       }
+                       SYNTH_STARTNOTE(md, voice, note, parm);
+               }
+               break;
+       case MIDI_NOTEOFF:
+               SYNTH_KILLNOTE(md, voice, note, parm);
+               break;
+       case MIDI_KEY_PRESSURE:
+               SYNTH_AFTERTOUCH(md, voice, parm);
+               break;
+       default:
+               ret = 1;
+               SEQ_DEBUG(2, printf("seq_chnvoice event type %d not handled\n",
+                   event[1]));
+               break;
+       }
+
+       mtx_lock(&scp->seq_lock);
+       return ret;
+}
+
+static int
+seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event)
+{
+       int ret;
+       u_short w14;
+       u_char cmd, chn, p1;
+
+       ret = 0;
+       cmd = event[2];
+       chn = event[3];
+       p1 = event[4];
+       w14 = *(u_short *)&event[6];
+
+       SEQ_DEBUG(5, printf("seq_chncommon: unit %d, dev %d, cmd %s, chn %d,"
+           " p1 %d, w14 %d.\n", scp->unit, event[1],
+           midi_cmdname(cmd, cmdtab_seqccmn), chn, p1, w14));
+       mtx_unlock(&scp->seq_lock);
+       switch (cmd) {
+       case MIDI_PGM_CHANGE:
+               SEQ_DEBUG(4, printf("seq_chncommon pgmchn chn %d pg %d\n",
+                   chn, p1));
+               SYNTH_SETINSTR(md, chn, p1);
+               break;
+       case MIDI_CTL_CHANGE:
+               SEQ_DEBUG(4, printf("seq_chncommon ctlch chn %d pg %d %d\n",
+                   chn, p1, w14));
+               SYNTH_CONTROLLER(md, chn, p1, w14);
+               break;
+       case MIDI_PITCH_BEND:
+               if (scp->music) {
+                       /*
+                        * TODO: MIDI_PITCH_BEND
+                        */
+#if 0
+                       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(&scp->seq_lock);
+                                               if (md->synth.bender(md, i, w14) == EAGAIN) {
+                                                       mtx_lock(&scp->seq_lock);
+                                                       return (QUEUEFULL);
+                                               }
+                                               mtx_lock(&scp->seq_lock);
+                                       }
+                       } else {
+                               mtx_unlock(&md->synth.vc_mtx);
+                               mtx_unlock(&scp->seq_lock);
+                               if (md->synth.bender(md, chn, w14) == EAGAIN) {
+                                       mtx_lock(&scp->seq_lock);
+                                       return (QUEUEFULL);
+                               }
+                               mtx_lock(&scp->seq_lock);
+                       }
+#endif
+               } else
+                       SYNTH_BENDER(md, chn, w14);
+               break;
+       default:
+               ret = 1;
+               SEQ_DEBUG(2,
+                   printf("seq_chncommon event type %d not handled.\n",
+                   event[1]));
+               break;
+
+       }
+       mtx_lock(&scp->seq_lock);
+       return ret;
+}
+
+static int
+seq_timing(struct seq_softc *scp, u_char *event)
+{
+       int param;
+       int ret;
+
+       ret = 0;
+       param = event[4] + (event[5] << 8) +
+           (event[6] << 16) + (event[7] << 24);
+
+       SEQ_DEBUG(5, printf("seq_timing: unit %d, cmd %d, param %d.\n",
+           scp->unit, event[1], param));
+       switch (event[1]) {
+       case TMR_WAIT_REL:
+               timer_wait(scp, param, 0);
+               break;
+       case TMR_WAIT_ABS:
+               timer_wait(scp, param, 1);
+               break;
+       case TMR_START:
+               timer_start(scp);
+               cv_broadcast(&scp->reset_cv);
+               break;
+       case TMR_STOP:
+               timer_stop(scp);
+               /*
+                * The following cv_broadcast isn't needed since we only
+                * wait for 0->1 transitions.  It probably won't hurt
+                */
+               cv_broadcast(&scp->reset_cv);
+               break;
+       case TMR_CONTINUE:
+               timer_continue(scp);
+               cv_broadcast(&scp->reset_cv);
+               break;
+       case TMR_TEMPO:
+               if (param < 8)
+                       param = 8;
+               if (param > 360)
+                       param = 360;
+               SEQ_DEBUG(4, printf("Timer set tempo %d\n", param));
+               timer_setvals(scp, param, scp->timerbase);
+               break;
+       case TMR_TIMERBASE:
+               if (param < 1)
+                       param = 1;
+               if (param > 1000)
+                       param = 1000;
+               SEQ_DEBUG(4, printf("Timer set timerbase %d\n", param));
+               timer_setvals(scp, scp->tempo, param);
+               break;
+       case TMR_ECHO:
+               /*
+                * TODO: Consider making 4-byte events for /dev/sequencer
+                * PRO: Maybe needed by legacy apps
+                * CON: soundcard.h has been warning for a while many years
+                * to expect 8 byte events.
+                */
+#if 0
+               if (scp->music)
+                       seq_copytoinput(scp, event, 8);
+               else {
+                       param = (param << 8 | SEQ_ECHO);
+                       seq_copytoinput(scp, (u_char *)&param, 4);
+               }
+#else
+               seq_copytoinput(scp, event, 8);
+#endif
+               break;
+       default:
+               SEQ_DEBUG(2, printf("seq_timing event type %d not handled.\n",
+                   event[1]));
+               ret = 1;
+               break;
+       }
+       return ret;
+}
+
+static int
+seq_local(struct seq_softc *scp, u_char *event)
+{
+       int ret;
+
+       ret = 0;
+       mtx_assert(&scp->seq_lock, MA_OWNED);
+
+       SEQ_DEBUG(5, printf("seq_local: unit %d, cmd %d\n", scp->unit,
+           event[1]));
+       switch (event[1]) {
+       default:
+               SEQ_DEBUG(1, printf("seq_local event type %d not handled\n",
+                   event[1]));
+               ret = 1;
+               break;
+       }
+       return ret;
+}
+
+static int
+seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event)
+{
+       int i, l;
+
+       mtx_assert(&scp->seq_lock, MA_OWNED);
+       SEQ_DEBUG(5, printf("seq_sysex: unit %d device %d\n", scp->unit,
+           event[1]));
+       l = 0;
+       for (i = 0; i < 6 && event[i + 2] != 0xff; i++)
+               l = i + 1;
+       if (l > 0) {
+               mtx_unlock(&scp->seq_lock);
+               if (SYNTH_SENDSYSEX(md, &event[2], l) == EAGAIN) {
+                       mtx_lock(&scp->seq_lock);
+                       return 1;
+               }
+               mtx_lock(&scp->seq_lock);
+       }
+       return 0;
+}
+
+/*
+ * Reset no longer closes the raw devices nor seq_sync's
+ * Callers are IOCTL and seq_close
+ */
+static void
+seq_reset(struct seq_softc *scp)
+{
+       int chn, i;
+       kobj_t m;
+
+       mtx_assert(&scp->seq_lock, MA_OWNED);
+
+       SEQ_DEBUG(5, printf("seq_reset: unit %d.\n", scp->unit));
+
+       /*
+        * Stop reading and writing.
+        */
+
+       /* scp->recording = 0; */
+       scp->playing = 0;
+       cv_broadcast(&scp->state_cv);
+       cv_broadcast(&scp->out_cv);
+       cv_broadcast(&scp->reset_cv);
+
+       /*
+        * For now, don't reset the timers.
+        */
+       MIDIQ_CLEAR(scp->in_q);
+       MIDIQ_CLEAR(scp->out_q);
+
+       for (i = 0; i < scp->midi_number; i++) {
+               m = scp->midis[i];
+               mtx_unlock(&scp->seq_lock);
+               SYNTH_RESET(m);
+               for (chn = 0; chn < 16; chn++) {
+                       SYNTH_CONTROLLER(m, chn, 123, 0);
+                       SYNTH_CONTROLLER(m, chn, 121, 0);
+                       SYNTH_BENDER(m, chn, 1 << 13);
+               }
+               mtx_lock(&scp->seq_lock);
+       }
+}
+
+/*
+ * seq_sync
+ * *really* flush the output queue
+ * flush the event queue, then flush the synthsisers.
+ * Callers are IOCTL and close
+ */
+
+#define SEQ_SYNC_TIMEOUT 8
+static int
+seq_sync(struct seq_softc *scp)
+{
+       int i, rl, sync[16], done;
+
+       mtx_assert(&scp->seq_lock, MA_OWNED);
+
+       SEQ_DEBUG(4, printf("seq_sync: unit %d.\n", scp->unit));
+
+       /*
+        * Wait until output queue is empty.  Check every so often to see if
+        * the queue is moving along.  If it isn't just abort.
+        */
+       while (!MIDIQ_EMPTY(scp->out_q)) {
+
+               if (!scp->playing) {
+                       scp->playing = 1;
+                       cv_broadcast(&scp->state_cv);
+                       cv_broadcast(&scp->out_cv);
+               }
+               rl = MIDIQ_LEN(scp->out_q);
+
+               i = cv_timedwait_sig(&scp->out_cv,
+                   &scp->seq_lock, SEQ_SYNC_TIMEOUT * hz);
+
+               if (i == EINTR || i == ERESTART) {
+                       if (i == EINTR) {
+                               /*
+                                * XXX: I don't know why we stop playing
+                                */
+                               scp->playing = 0;
+                               cv_broadcast(&scp->out_cv);
+                       }
+                       return i;
+               }
+               if (i == EWOULDBLOCK && rl == MIDIQ_LEN(scp->out_q) &&
+                   scp->waiting == 0) {
+                       /*
+                        * A queue seems to be stuck up. Give up and clear
+                        * queues.
+                        */
+                       MIDIQ_CLEAR(scp->out_q);
+                       scp->playing = 0;
+                       cv_broadcast(&scp->state_cv);
+                       cv_broadcast(&scp->out_cv);
+                       cv_broadcast(&scp->reset_cv);
+
+                       /*
+                        * TODO: Consider if the raw devices need to be flushed
+                        */
+
+                       SEQ_DEBUG(1, printf("seq_sync queue stuck, aborting\n"));
+
+                       return i;
+               }
+       }
+
+       scp->playing = 0;
+       /*
+        * Since syncing a midi device might block, unlock scp->seq_lock.
+        */
+
+       mtx_unlock(&scp->seq_lock);
+       for (i = 0; i < scp->midi_number; i++)
+               sync[i] = 1;
+
+       do {
+               done = 1;
+               for (i = 0; i < scp->midi_number; i++)
+                       if (sync[i]) {
+                               if (SYNTH_INSYNC(scp->midis[i]) == 0)
+                                       sync[i] = 0;
+                               else
+                                       done = 0;
+                       }
+               if (!done)
+                       DELAY(5000);
+
+       } while (!done);
+
+       mtx_lock(&scp->seq_lock);
+       return 0;
+}
+
+char   *
+midi_cmdname(int cmd, midi_cmdtab *tab)
+{
+       while (tab->name != NULL) {
+               if (cmd == tab->cmd)
+                       return (tab->name);
+               tab++;
+       }
+
+       return ("unknown");
+}
similarity index 55%
copy from sys/dev/sound/chip.h
copy to sys/dev/sound/midi/sequencer.h
index 43af963..797e9da 100644 (file)
@@ -1,4 +1,5 @@
 /*-
+ * Copyright (c) 2003 Mathew Kanner
  * Copyright (c) 1999 Seigo Tanimura
  * All rights reserved.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/sound/chip.h,v 1.2 2000/01/03 02:51:14 tanimura Exp $
- * $DragonFly: src/sys/dev/sound/chip.h,v 1.2 2003/06/17 04:28:30 dillon Exp $
+ * $FreeBSD: head/sys/dev/sound/midi/sequencer.h 193640 2009-06-07 19:12:08Z ariff $
  */
 
 /*
- * These are the function codes assigned to the children of
- * sound cards.
+ * Include file for the midi sequence driver.
  */
-enum {
-       SCF_PCM,
-       SCF_MIDI,
-       SCF_SYNTH,
-};
+
+#ifndef _SEQUENCER_H_
+#define _SEQUENCER_H_
+
+
+#define NSEQ_MAX       16
 
 /*
- * This is the device information struct, used by
- * a bridge device to pass the device function code
- * to the children.
+ * many variables should be reduced to a range. Here define a macro
  */
-struct sndcard_func {
-       int func;       /* The function code. */
-       void *varinfo;  /* Bridge-specific information. */
+
+#define RANGE(var, low, high) (var) = \
+((var)<(low)?(low) : (var)>(high)?(high) : (var))
+
+#ifdef _KERNEL
+
+void   seq_timer(void *arg);
+
+SYSCTL_DECL(_hw_midi_seq);
+
+extern int seq_debug;
+
+#define SEQ_DEBUG(y, x)                        \
+       do {                            \
+               if (seq_debug >= y) {   \
+                       (x);            \
+               }                       \
+       } while (0)
+
+SYSCTL_DECL(_hw_midi);
+
+#endif                                 /* _KERNEL */
+
+#define SYNTHPROP_MIDI         1
+#define SYNTHPROP_SYNTH                2
+#define SYNTHPROP_RX           4
+#define SYNTHPROP_TX           8
+
+struct _midi_cmdtab {
+       int     cmd;
+       char   *name;
 };
+typedef struct _midi_cmdtab midi_cmdtab;
+extern midi_cmdtab cmdtab_seqevent[];
+extern midi_cmdtab cmdtab_seqioctl[];
+extern midi_cmdtab cmdtab_timer[];
+extern midi_cmdtab cmdtab_seqcv[];
+extern midi_cmdtab cmdtab_seqccmn[];
+
+char   *midi_cmdname(int cmd, midi_cmdtab * tab);
+
+enum {
+       MORE,
+       TIMERARMED,
+       QUEUEFULL
+};
+
+#endif
diff --git a/sys/dev/sound/midi/synth_if.m b/sys/dev/sound/midi/synth_if.m
new file mode 100644 (file)
index 0000000..faef209
--- /dev/null
@@ -0,0 +1,313 @@
+#-
+# Copyright (c) 2003 Mathew Kanner
+# 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: head/sys/dev/sound/midi/synth_if.m 166971 2007-02-25 13:51:52Z netchild $
+#
+
+INTERFACE synth;
+
+#include <sys/systm.h>
+
+CODE {
+
+synth_killnote_t nokillnote;
+synth_startnote_t nostartnote;
+synth_setinstr_t nosetinstr;
+synth_hwcontrol_t nohwcontrol;
+synth_aftertouch_t noaftertouch;
+synth_panning_t nopanning;
+synth_controller_t nocontroller;
+synth_volumemethod_t novolumemethod;
+synth_bender_t nobender;
+synth_setupvoice_t nosetupvoice;
+synth_sendsysex_t nosendsysex;
+synth_allocvoice_t noallocvoice;
+synth_writeraw_t nowriteraw;
+synth_reset_t noreset;
+synth_shortname_t noshortname;
+synth_open_t noopen;
+synth_close_t noclose;
+synth_query_t noquery;
+synth_insync_t noinsync;
+synth_alloc_t noalloc;
+
+    int
+       nokillnote(void *_kobj, uint8_t _chn, uint8_t _note, uint8_t _vel)
+       {
+           printf("nokillnote\n");
+           return 0;
+       }
+
+    int
+       noopen(void *_kobj, void *_arg, int mode)
+       {
+           printf("noopen\n");
+           return 0;
+       }
+
+    int
+       noquery(void *_kboj)
+       {
+           printf("noquery\n");
+           return 0;
+       }
+
+    int
+       nostartnote(void *_kb, uint8_t _voice, uint8_t _note, uint8_t _parm)
+       {
+           printf("nostartnote\n");
+           return 0;
+       }
+
+    int
+       nosetinstr(void *_kb, uint8_t _chn, uint16_t _patchno)
+       {
+           printf("nosetinstr\n");
+           return 0;
+       }
+
+    int
+       nohwcontrol(void *_kb, uint8_t *_event)
+       {
+           printf("nohwcontrol\n");
+           return 0;
+       }
+
+    int 
+       noaftertouch ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2)
+       {
+           printf("noaftertouch\n");
+           return 0;
+       }
+
+    int
+       nopanning ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2)
+       {
+           printf("nopanning\n");
+           return 0;
+       }
+
+    int 
+       nocontroller ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2, uint16_t _x3)
+       {
+           printf("nocontroller\n");
+           return 0;
+       }
+
+    int 
+       novolumemethod (
+               void /* X */ * _kobj,
+               uint8_t _x1)
+       {
+           printf("novolumemethod\n");
+           return 0;
+       }
+
+    int 
+       nobender ( void /* X */ * _kobj, uint8_t _voice, uint16_t _bend)
+       {
+           printf("nobender\n");
+           return 0;
+       }
+
+    int 
+       nosetupvoice ( void /* X */ * _kobj, uint8_t _voice, uint8_t _chn)
+       {
+
+           printf("nosetupvoice\n");
+           return 0;
+       }
+
+    int 
+       nosendsysex ( void /* X */ * _kobj, void * _buf, size_t _len)
+       {
+           printf("nosendsysex\n");
+           return 0;
+       }
+
+    int 
+       noallocvoice ( void /* X */ * _kobj, uint8_t _chn, uint8_t _note, void *_x)
+       {
+           printf("noallocvoice\n");
+           return 0;
+       }
+
+    int 
+       nowriteraw ( void /* X */ * _kobjt, uint8_t * _buf, size_t _len)
+       {
+           printf("nowriteraw\n");
+           return 1;
+       }
+
+    int 
+       noreset ( void /* X */ * _kobjt)
+       {
+
+           printf("noreset\n");
+           return 0;
+       }
+
+    char *
+       noshortname (void /* X */ * _kobjt)
+       {
+           printf("noshortname\n");
+           return "noshortname";
+       }
+
+    int 
+       noclose ( void /* X */ * _kobjt)
+       {
+
+           printf("noclose\n");
+           return 0;
+       }
+
+    int
+       noinsync (void /* X */ * _kobjt)
+       {
+
+           printf("noinsync\n");
+           return 0;
+       }
+
+    int 
+       noalloc ( void /* x */ * _kbojt, uint8_t _chn, uint8_t _note)
+       {
+           printf("noalloc\n");
+           return 0;
+       }
+}
+
+METHOD int killnote {
+       void /* X */ *_kobj;
+       uint8_t _chan;
+       uint8_t _note;
+       uint8_t _vel;
+} DEFAULT nokillnote;
+
+METHOD int startnote {
+       void /* X */ *_kobj;
+       uint8_t _voice;
+       uint8_t _note;
+       uint8_t _parm;
+} DEFAULT nostartnote;
+
+METHOD int setinstr {
+       void /* X */ *_kobj;
+       uint8_t _chn;
+       uint16_t _patchno;
+} DEFAULT nosetinstr;
+
+METHOD int hwcontrol {
+       void /* X */ *_kobj;
+       uint8_t *_event;
+} DEFAULT nohwcontrol;
+
+METHOD int aftertouch {
+       void /* X */ *_kobj;
+       uint8_t _x1;
+       uint8_t _x2;
+} DEFAULT noaftertouch;
+
+METHOD int panning {
+       void /* X */ *_kobj;
+       uint8_t _x1;
+       uint8_t _x2;
+} DEFAULT nopanning;
+
+METHOD int controller {
+       void /* X */ *_kobj;
+       uint8_t _x1;
+       uint8_t _x2;
+       uint16_t _x3;
+} DEFAULT nocontroller;
+
+METHOD int volumemethod {
+       void /* X */ *_kobj;
+       uint8_t _x1;
+} DEFAULT novolumemethod;
+
+METHOD int bender {
+       void /* X */ *_kobj;
+       uint8_t _voice;
+       uint16_t _bend;
+} DEFAULT nobender;
+
+METHOD int setupvoice {
+       void /* X */ *_kobj;
+       uint8_t _voice;
+       uint8_t _chn;
+} DEFAULT nosetupvoice;
+
+METHOD int sendsysex {
+       void /* X */ *_kobj;
+       void   *_buf;
+       size_t  _len;
+} DEFAULT nosendsysex;
+
+METHOD int allocvoice {
+       void /* X */ *_kobj;
+       uint8_t _chn;
+       uint8_t _note;
+       void   *_x;
+} DEFAULT noallocvoice;
+
+METHOD int writeraw {
+       void /* X */ *_kobjt;
+       uint8_t *_buf;
+       size_t  _len;
+} DEFAULT nowriteraw;
+
+METHOD int reset {
+       void /* X */ *_kobjt;
+} DEFAULT noreset;
+
+METHOD char * shortname {
+       void /* X */ *_kobjt;
+} DEFAULT noshortname;
+
+METHOD int open {
+       void /* X */ *_kobjt;
+       void   *_sythn;
+       int     _mode;
+} DEFAULT noopen;
+
+METHOD int close {
+       void /* X */ *_kobjt;
+} DEFAULT noclose;
+
+METHOD int query {
+       void /* X */ *_kobjt;
+} DEFAULT noquery;
+
+METHOD int insync {
+       void /* X */ *_kobjt;
+} DEFAULT noinsync;
+
+METHOD int alloc {
+       void /* x */ *_kbojt;
+       uint8_t _chn;
+       uint8_t _note;
+} DEFAULT noalloc;
diff --git a/sys/dev/sound/pci/allegro_code.h b/sys/dev/sound/pci/allegro_code.h
new file mode 100644 (file)
index 0000000..030721e
--- /dev/null
@@ -0,0 +1,218 @@
+/* $FreeBSD: head/sys/dev/sound/pci/allegro_code.h 230401 2012-01-20 22:37:10Z pfg $ */
+/*-
+ * Copyright (C) 1996-2008, 4Front Technologies
+ * Copyright (C) 1997-1999 ESS Technology, Inc
+ * 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.
+ *
+ */
+
+/*---------------------------------------------------------------------------
+ * This source code, its compiled object code, and its associated data sets
+ * are copyright (C) 1997-1999 ESS Technology, Inc. This source code and its
+ * associated data sets are trade secrets of ESS Technology, Inc.
+ *---------------------------------------------------------------------------
+ * DESCRIPTION: DSP binaries
+ *---------------------------------------------------------------------------
+ * AUTHOR:  Henry Tang / Hong Kim / Alger Yeung/Don Kim
+ *---------------------------------------------------------------------------
+ * For practical purposes we only include what is necessary for current
+ *  Maestro3 driver. Files used in this header include:
+ *    kernel.dat
+ *    400m_src.dat
+ *    mini_src_lpf from srcmgr.h
+ *---------------------------------------------------------------------------
+ */
+#ifndef _DEV_SOUND_PCI_ALLEGRO_CODE_H
+#define _DEV_SOUND_PCI_ALLEGRO_CODE_H
+
+/*
+ * Kernel
+ */
+
+uint16_t gaw_kernel_vect_code[] = {
+    0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980,
+    0x00DD, 0x7980, 0x03B4, 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4,
+    0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x031A, 0x7980,
+    0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
+    0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980,
+    0x03B4, 0x7980, 0x03B4, 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20,
+    0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08, 0x0053, 0x695A, 0xEB08,
+    0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909,
+    0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40,
+    0x7980, 0x0038, 0xBE41, 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A,
+    0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308, 0x005E, 0x903A, 0xEF00,
+    0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910,
+    0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00,
+    0x690E, 0x660D, 0xEF00, 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939,
+    0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026, 0x8B88, 0x6980, 0xE388,
+    0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0,
+    0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005,
+    0x100A, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B,
+    0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A, 0x0C10, 0x4005, 0x100E,
+    0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000, 
+    0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012,
+    0x0C12, 0x4001, 0x0C05, 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF,
+    0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26, 0x1028, 0x6970, 0xBFD0,
+    0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300, 
+    0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801,
+    0x907F, 0x0056, 0x8B88, 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200,
+    0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008, 0x8056, 0x7980, 0x03A1,
+    0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80,
+    0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01,
+    0xE308, 0x010C, 0xAE71, 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A,
+    0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A, 0x0560, 0xF500, 0xBF0A,
+    0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100,
+    0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538,
+    0xBF0D, 0x053C, 0x6900, 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0,
+    0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903, 0x8809, 0xBEC6, 0x013E,
+    0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309,
+    0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B,
+    0x0578, 0xF500, 0xBF0B, 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB,
+    0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540, 0xF500, 0xAE72, 0x0500,
+    0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C,
+    0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380,
+    0x733E, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814,
+    0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340, 0x7A80, 0x0380, 0x6975,
+    0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041,
+    0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500,
+    0x7C40, 0x0814, 0xBA18, 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80,
+    0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA24, 0x8812,
+    0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9,
+    0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6,
+    0x697A, 0xE388, 0x01D8, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814,
+    0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A, 0x7A80, 0x0380, 0x8B8C,
+    0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80,
+    0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A,
+    0x0560, 0xE500, 0x7C40, 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C,
+    0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80, 0x034A, 0x8B8A, 0xBF0A,
+    0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A, 
+    0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03,
+    0x98A0, 0x1F20, 0x2F1F, 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933,
+    0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1, 0x9033, 0xBF00, 0x6951,
+    0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034,
+    0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80,
+    0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980,
+    0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977, 0xE388, 0x024E, 0xAE61,
+    0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B,
+    0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009,
+    0x0810, 0x660C, 0xE388, 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1,
+    0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xE100, 0x0266, 0x697C,
+    0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473,
+    0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90,
+    0x0524, 0x9073, 0x0473, 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A,
+    0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880, 0xBC21, 0x7326, 0x548B,
+    0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80,
+    0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0,
+    0x0C00, 0xE388, 0x02B6, 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0,
+    0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909, 0x900B, 0x7980, 0x02A5,
+    0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED,
+    0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980,
+    0x02B8, 0xAF0B, 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED,
+    0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02E7, 0xBFA0, 0x0800,
+    0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4,
+    0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902,
+    0x9006, 0x4311, 0xE100, 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980,
+    0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10, 0x4005, 0xAF05, 0x4003,
+    0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070,
+    0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372,
+    0x7804, 0x9071, 0x0D71, 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309,
+    0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A, 0xE344, 0x030F, 0x0009,
+    0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061,
+    0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034,
+    0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500,
+    0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6, 0x7980, 0x03A1, 0x7A80,
+    0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A,
+    0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61,
+    0x105C, 0x7A80, 0x02F6, 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88,
+    0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358, 0x690E, 0x6610, 0x620F,
+    0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6,
+    0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD,
+    0x98A9, 0x6A8C, 0x61A9, 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04,
+    0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379, 0x040D, 0x8410, 0xBC21,
+    0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6,
+    0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809,
+    0x906B, 0x080A, 0x906C, 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063,
+    0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166, 0x8267, 0x8368, 0x8469,
+    0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B,
+    0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267,
+    0x0368, 0x0469, 0x056A, 0xBE3A,
+};
+
+/*
+ * MINI Sample Rate Conversion
+ */
+
+uint16_t gaw_minisrc_code_0400[] = {
+    0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F,
+    0x6900, 0xEB08, 0x0412, 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403,
+    0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, 0x7A80, 0x002A, 0xBE40,
+    0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907,
+    0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009,
+    0x881A, 0x100A, 0xBA01, 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D,
+    0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904, 0x9027, 0x6918, 0xE308,
+    0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D,
+    0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6,
+    0x0453, 0x10A9, 0x90AD, 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460,
+    0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22, 0x90AD, 0x7980, 0x047C,
+    0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0,
+    0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22,
+    0x90A0, 0x90AD, 0x10A9, 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308,
+    0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89, 0x022C, 0x108A, 0x7C04,
+    0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0,
+    0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89,
+    0x99AF, 0x7B99, 0x0484, 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0,
+    0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80, 0x051A, 0x6927, 0xBA01,
+    0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624,
+    0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80,
+    0x051A, 0x7980, 0x04B4, 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80,
+    0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027, 0xE308, 0x04B4, 0x0124,
+    0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903,
+    0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901,
+    0x8818, 0xB907, 0x8809, 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F,
+    0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46, 0xBEC6, 0x04FA, 0x17A0,
+    0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47,
+    0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7,
+    0xFF00, 0xBE1E, 0x1EA0, 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080,
+    0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516, 0x0D07, 0x8510, 0xBE59,
+    0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E,
+    0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03,
+    0x9825, 0x1025, 0x201C, 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880,
+    0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0, 0x101F,
+    0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E,
+    0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07,
+    0x6180, 0x9880, 0x8BA0, 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0,
+    0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0, 0xBEC6, 0x056B, 0xBE59,
+    0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0, 
+    0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090,
+    0x8BD0, 0x8BD8, 0xBE1F, 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+uint16_t minisrc_lpf[10] = {
+       0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
+       0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
+};
+
+#endif /* !_DEV_SOUND_PCI_ALLEGRO_CODE_H */
similarity index 76%
rename from sys/gnu/dev/sound/pci/maestro3_reg.h
rename to sys/dev/sound/pci/allegro_reg.h
index 0422197..addaf5f 100644 (file)
@@ -1,26 +1,49 @@
-/* $FreeBSD: src/sys/gnu/dev/sound/pci/maestro3_reg.h,v 1.5 2005/01/06 18:27:30 imp Exp $ */
+/* $FreeBSD: head/sys/dev/sound/pci/allegro_reg.h 230401 2012-01-20 22:37:10Z pfg $ */
 /*-
- *      ESS Technology allegro audio driver.
+ * Copyright (c) 1996-2008, 4Front Technologies
+ * Copyright (C) 1992-2000  Don Kim (don.kim@esstech.com)
+ * All rights reserved.
  *
- *      Copyright (C) 1992-2000  Don Kim (don.kim@esstech.com)
+ * 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 program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
+ * 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, WHETHERIN 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.
  *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *      Hacked for the maestro3 driver by zab
  */
 
+/*---------------------------------------------------------------------------
+ *              Copyright (C) 1997-1999, ESS Technology, Inc.
+ * This source code, its compiled object code, and its associated data sets
+ * are copyright (C) 1997-1999 ESS Technology, Inc.
+ *---------------------------------------------------------------------------
+ * This header contains data structures and registers taken from the
+ * 4Front OSS Allegro BSD licensed driver (in the Attic/ directory).
+ *  Files used for this header include:
+ *    hardware.h
+ *    kernel.h and hckernel.h
+ *    srcmgr.h
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef _DEV_SOUND_PCI_ALLEGRO_REG_H
+#define _DEV_SOUND_PCI_ALLEGRO_REG_H
+
 /* Allegro PCI configuration registers */
 #define PCI_LEGACY_AUDIO_CTRL   0x40
 #define SOUND_BLASTER_ENABLE    0x00000001
 #define HV_CTRL_TO_PME          0x0400
 #define SOFTWARE_RESET_ENABLE   0x8000
 
-/*
- * should be using the above defines, probably.
- */
-#define REGB_ENABLE_RESET       0x01
-#define REGB_STOP_CLOCK         0x10
-
 #define HOST_INT_STATUS         0x1A
 #define SB_INT_PENDING          0x01
 #define MPU401_INT_PENDING      0x02
 
 #define CODEC_DATA              0x32
 
+/* AC97 registers */
+#ifndef M3_MODEL
+#define AC97_RESET              0x00
+#endif
+
+#define AC97_VOL_MUTE_B         0x8000
+#define AC97_VOL_M              0x1F
+#define AC97_LEFT_VOL_S         8
+
+#define AC97_MASTER_VOL         0x02
+#define AC97_LINE_LEVEL_VOL     0x04
+#define AC97_MASTER_MONO_VOL    0x06
+#define AC97_PC_BEEP_VOL        0x0A
+#define AC97_PC_BEEP_VOL_M      0x0F
+#define AC97_SROUND_MASTER_VOL  0x38
+#define AC97_PC_BEEP_VOL_S      1
+
+#ifndef M3_MODEL
+#define AC97_PHONE_VOL          0x0C
+#define AC97_MIC_VOL            0x0E
+#endif
+#define AC97_MIC_20DB_ENABLE    0x40
+
+#ifndef M3_MODEL
+#define AC97_LINEIN_VOL         0x10
+#define AC97_CD_VOL             0x12
+#define AC97_VIDEO_VOL          0x14
+#define AC97_AUX_VOL            0x16
+#endif
+#define AC97_PCM_OUT_VOL        0x18
+#ifndef M3_MODEL
+#define AC97_RECORD_SELECT      0x1A
+#endif
+#define AC97_RECORD_MIC         0x00
+#define AC97_RECORD_CD          0x01
+#define AC97_RECORD_VIDEO       0x02
+#define AC97_RECORD_AUX         0x03
+#define AC97_RECORD_MONO_MUX    0x02
+#define AC97_RECORD_DIGITAL     0x03
+#define AC97_RECORD_LINE        0x04
+#define AC97_RECORD_STEREO      0x05
+#define AC97_RECORD_MONO        0x06
+#define AC97_RECORD_PHONE       0x07
+
+#ifndef M3_MODEL
+#define AC97_RECORD_GAIN        0x1C
+#endif
+#define AC97_RECORD_VOL_M       0x0F
+
+#ifndef M3_MODEL
+#define AC97_GENERAL_PURPOSE    0x20
+#endif
+#define AC97_POWER_DOWN_CTRL    0x26
+#define AC97_ADC_READY          0x0001
+#define AC97_DAC_READY          0x0002
+#define AC97_ANALOG_READY       0x0004
+#define AC97_VREF_ON            0x0008
+#define AC97_PR0                0x0100
+#define AC97_PR1                0x0200
+#define AC97_PR2                0x0400
+#define AC97_PR3                0x0800
+#define AC97_PR4                0x1000
+
+#define AC97_RESERVED1          0x28
+
+#define AC97_VENDOR_TEST        0x5A
+
+#define AC97_CLOCK_DELAY        0x5C
+#define AC97_LINEOUT_MUX_SEL    0x0001
+#define AC97_MONO_MUX_SEL       0x0002
+#define AC97_CLOCK_DELAY_SEL    0x1F
+#define AC97_DAC_CDS_SHIFT      6
+#define AC97_ADC_CDS_SHIFT      11
+
+#define AC97_MULTI_CHANNEL_SEL  0x74
+
+#ifndef M3_MODEL
+#define AC97_VENDOR_ID1         0x7C
+#define AC97_VENDOR_ID2         0x7E
+#endif
+
 #define RING_BUS_CTRL_A         0x36
 #define RAC_PME_ENABLE          0x0100
 #define RAC_SDFS_ENABLE         0x0200
 #define DSP2HOST_REQ_I2SRATE    0x02
 #define DSP2HOST_REQ_TIMER      0x04
 
-/* AC97 registers */
-/* XXX fix this crap up */
-/*#define AC97_RESET              0x00*/
-
-#define AC97_VOL_MUTE_B         0x8000
-#define AC97_VOL_M              0x1F
-#define AC97_LEFT_VOL_S         8
-
-#define AC97_MASTER_VOL         0x02
-#define AC97_LINE_LEVEL_VOL     0x04
-#define AC97_MASTER_MONO_VOL    0x06
-#define AC97_PC_BEEP_VOL        0x0A
-#define AC97_PC_BEEP_VOL_M      0x0F
-#define AC97_SROUND_MASTER_VOL  0x38
-#define AC97_PC_BEEP_VOL_S      1
-
-/*#define AC97_PHONE_VOL          0x0C
-#define AC97_MIC_VOL            0x0E*/
-#define AC97_MIC_20DB_ENABLE    0x40
-
-/*#define AC97_LINEIN_VOL         0x10
-#define AC97_CD_VOL             0x12
-#define AC97_VIDEO_VOL          0x14
-#define AC97_AUX_VOL            0x16*/
-#define AC97_PCM_OUT_VOL        0x18
-/*#define AC97_RECORD_SELECT      0x1A*/
-#define AC97_RECORD_MIC         0x00
-#define AC97_RECORD_CD          0x01
-#define AC97_RECORD_VIDEO       0x02
-#define AC97_RECORD_AUX         0x03
-#define AC97_RECORD_MONO_MUX    0x02
-#define AC97_RECORD_DIGITAL     0x03
-#define AC97_RECORD_LINE        0x04
-#define AC97_RECORD_STEREO      0x05
-#define AC97_RECORD_MONO        0x06
-#define AC97_RECORD_PHONE       0x07
-
-/*#define AC97_RECORD_GAIN        0x1C*/
-#define AC97_RECORD_VOL_M       0x0F
-
-/*#define AC97_GENERAL_PURPOSE    0x20*/
-#define AC97_POWER_DOWN_CTRL    0x26
-#define AC97_ADC_READY          0x0001
-#define AC97_DAC_READY          0x0002
-#define AC97_ANALOG_READY       0x0004
-#define AC97_VREF_ON            0x0008
-#define AC97_PR0                0x0100
-#define AC97_PR1                0x0200
-#define AC97_PR2                0x0400
-#define AC97_PR3                0x0800
-#define AC97_PR4                0x1000
-
-#define AC97_RESERVED1          0x28
-
-#define AC97_VENDOR_TEST        0x5A
-
-#define AC97_CLOCK_DELAY        0x5C
-#define AC97_LINEOUT_MUX_SEL    0x0001
-#define AC97_MONO_MUX_SEL       0x0002
-#define AC97_CLOCK_DELAY_SEL    0x1F
-#define AC97_DAC_CDS_SHIFT      6
-#define AC97_ADC_CDS_SHIFT      11
-
-#define AC97_MULTI_CHANNEL_SEL  0x74
-
-/*#define AC97_VENDOR_ID1         0x7C
-#define AC97_VENDOR_ID2         0x7E*/
-
 /*
- * ASSP control regs
+ * DSP memory map
  */
-#define DSP_PORT_TIMER_COUNT    0x06
-
-#define DSP_PORT_MEMORY_INDEX   0x80
-
-#define DSP_PORT_MEMORY_TYPE    0x82
-#define MEMTYPE_INTERNAL_CODE   0x0002
-#define MEMTYPE_INTERNAL_DATA   0x0003
-#define MEMTYPE_MASK            0x0003
-
-#define DSP_PORT_MEMORY_DATA    0x84
-
-#define DSP_PORT_CONTROL_REG_A  0xA2
-#define DSP_PORT_CONTROL_REG_B  0xA4
-#define DSP_PORT_CONTROL_REG_C  0xA6
 
 #define REV_A_CODE_MEMORY_BEGIN         0x0000
 #define REV_A_CODE_MEMORY_END           0x0FFF
 #define REV_B_CODE_MEMORY_UNIT_LENGTH   0x0040
 #define REV_B_CODE_MEMORY_LENGTH        (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
 
+#if (REV_A_CODE_MEMORY_LENGTH % REV_A_CODE_MEMORY_UNIT_LENGTH)
+#error Assumption about code memory unit length failed.
+#endif
+#if (REV_B_CODE_MEMORY_LENGTH % REV_B_CODE_MEMORY_UNIT_LENGTH)
+#error Assumption about code memory unit length failed.
+#endif
+
 #define REV_A_DATA_MEMORY_BEGIN         0x1000
 #define REV_A_DATA_MEMORY_END           0x2FFF
 #define REV_A_DATA_MEMORY_UNIT_LENGTH   0x0080
 #define REV_A_DATA_MEMORY_LENGTH        (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
 
 #define REV_B_DATA_MEMORY_BEGIN         0x1000
+/*#define REV_B_DATA_MEMORY_END           0x23FF */
 #define REV_B_DATA_MEMORY_END           0x2BFF
 #define REV_B_DATA_MEMORY_UNIT_LENGTH   0x0080
 #define REV_B_DATA_MEMORY_LENGTH        (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
 
+#if (REV_A_DATA_MEMORY_LENGTH % REV_A_DATA_MEMORY_UNIT_LENGTH)
+#error Assumption about data memory unit length failed.
+#endif
+#if (REV_B_DATA_MEMORY_LENGTH % REV_B_DATA_MEMORY_UNIT_LENGTH)
+#error Assumption about data memory unit length failed.
+#endif
+
+#define CODE_MEMORY_MAP_LENGTH          (64 + 1)
+#define DATA_MEMORY_MAP_LENGTH          (64 + 1)
+
+#if (CODE_MEMORY_MAP_LENGTH < ((REV_A_CODE_MEMORY_LENGTH / REV_A_CODE_MEMORY_UNIT_LENGTH) + 1))
+#error Code memory map length too short.
+#endif
+#if (DATA_MEMORY_MAP_LENGTH < ((REV_A_DATA_MEMORY_LENGTH / REV_A_DATA_MEMORY_UNIT_LENGTH) + 1))
+#error Data memory map length too short.
+#endif
+#if (CODE_MEMORY_MAP_LENGTH < ((REV_B_CODE_MEMORY_LENGTH / REV_B_CODE_MEMORY_UNIT_LENGTH) + 1))
+#error Code memory map length too short.
+#endif
+#if (DATA_MEMORY_MAP_LENGTH < ((REV_B_DATA_MEMORY_LENGTH / REV_B_DATA_MEMORY_UNIT_LENGTH) + 1))
+#error Data memory map length too short.
+#endif
 
-#define NUM_UNITS_KERNEL_CODE          16
-#define NUM_UNITS_KERNEL_DATA           2
-
-#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
-#define NUM_UNITS_KERNEL_DATA_WITH_HSP  5
 
 /*
- * Kernel data layout
+ * Kernel code memory definition
  */
 
-#define DP_SHIFT_COUNT                  7
+#define KCODE_VECTORS_BEGIN             0x0000
+#define KCODE_VECTORS_END               0x002F
+#define KCODE_VECTORS_UNIT_LENGTH       0x0002
+#define KCODE_VECTORS_LENGTH            (KCODE_VECTORS_END - KCODE_VECTORS_BEGIN + 1)
+
+
+/*
+ * Kernel data memory definition
+ */
 
 #define KDATA_BASE_ADDR                 0x1000
 #define KDATA_BASE_ADDR2                0x1080
 
 #define KDATA_ADC1_XFER0                (KDATA_BASE_ADDR + 0x003B)
 #define KDATA_ADC1_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x003C)
-#define KDATA_ADC1_LEFT_VOLUME                 (KDATA_BASE_ADDR + 0x003D)
-#define KDATA_ADC1_RIGHT_VOLUME                (KDATA_BASE_ADDR + 0x003E)
-#define KDATA_ADC1_LEFT_SUR_VOL                        (KDATA_BASE_ADDR + 0x003F)
-#define KDATA_ADC1_RIGHT_SUR_VOL               (KDATA_BASE_ADDR + 0x0040)
+#define KDATA_ADC1_LEFT_VOLUME         (KDATA_BASE_ADDR + 0x003D)
+#define KDATA_ADC1_RIGHT_VOLUME        (KDATA_BASE_ADDR + 0x003E)
+#define KDATA_ADC1_LEFT_SUR_VOL                (KDATA_BASE_ADDR + 0x003F)
+#define KDATA_ADC1_RIGHT_SUR_VOL       (KDATA_BASE_ADDR + 0x0040)
 
 #define KDATA_ADC2_XFER0                (KDATA_BASE_ADDR + 0x0041)
 #define KDATA_ADC2_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x0042)
-#define KDATA_ADC2_LEFT_VOLUME                 (KDATA_BASE_ADDR + 0x0043)
-#define KDATA_ADC2_RIGHT_VOLUME                        (KDATA_BASE_ADDR + 0x0044)
-#define KDATA_ADC2_LEFT_SUR_VOL                        (KDATA_BASE_ADDR + 0x0045)
-#define KDATA_ADC2_RIGHT_SUR_VOL               (KDATA_BASE_ADDR + 0x0046)
-
-#define KDATA_CD_XFER0                                 (KDATA_BASE_ADDR + 0x0047)
-#define KDATA_CD_XFER_ENDMARK                  (KDATA_BASE_ADDR + 0x0048)
-#define KDATA_CD_LEFT_VOLUME                   (KDATA_BASE_ADDR + 0x0049)
-#define KDATA_CD_RIGHT_VOLUME                  (KDATA_BASE_ADDR + 0x004A)
-#define KDATA_CD_LEFT_SUR_VOL                  (KDATA_BASE_ADDR + 0x004B)
-#define KDATA_CD_RIGHT_SUR_VOL                 (KDATA_BASE_ADDR + 0x004C)
-
-#define KDATA_MIC_XFER0                                        (KDATA_BASE_ADDR + 0x004D)
-#define KDATA_MIC_XFER_ENDMARK                 (KDATA_BASE_ADDR + 0x004E)
-#define KDATA_MIC_VOLUME                               (KDATA_BASE_ADDR + 0x004F)
-#define KDATA_MIC_SUR_VOL                              (KDATA_BASE_ADDR + 0x0050)
+#define KDATA_ADC2_LEFT_VOLUME         (KDATA_BASE_ADDR + 0x0043)
+#define KDATA_ADC2_RIGHT_VOLUME                (KDATA_BASE_ADDR + 0x0044)
+#define KDATA_ADC2_LEFT_SUR_VOL                (KDATA_BASE_ADDR + 0x0045)
+#define KDATA_ADC2_RIGHT_SUR_VOL       (KDATA_BASE_ADDR + 0x0046)
+
+#define KDATA_CD_XFER0                 (KDATA_BASE_ADDR + 0x0047)
+#define KDATA_CD_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0048)
+#define KDATA_CD_LEFT_VOLUME           (KDATA_BASE_ADDR + 0x0049)
+#define KDATA_CD_RIGHT_VOLUME          (KDATA_BASE_ADDR + 0x004A)
+#define KDATA_CD_LEFT_SUR_VOL          (KDATA_BASE_ADDR + 0x004B)
+#define KDATA_CD_RIGHT_SUR_VOL         (KDATA_BASE_ADDR + 0x004C)
+
+#define KDATA_MIC_XFER0                        (KDATA_BASE_ADDR + 0x004D)
+#define KDATA_MIC_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x004E)
+#define KDATA_MIC_VOLUME               (KDATA_BASE_ADDR + 0x004F)
+#define KDATA_MIC_SUR_VOL              (KDATA_BASE_ADDR + 0x0050)
 
 #define KDATA_I2S_XFER0                 (KDATA_BASE_ADDR + 0x0051)
 #define KDATA_I2S_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0052)
 #define KDATA_SPDIF_REQUEST             (KDATA_BASE_ADDR + 0x005A)
 #define KDATA_SPDIF_TEMP                (KDATA_BASE_ADDR + 0x005B)
 
+/*AY SPDIF IN */
 #define KDATA_SPDIFIN_XFER0             (KDATA_BASE_ADDR + 0x005C)
 #define KDATA_SPDIFIN_XFER_ENDMARK      (KDATA_BASE_ADDR + 0x005D)
 #define KDATA_SPDIFIN_INT_METER         (KDATA_BASE_ADDR + 0x005E)
 
 #define KDATA_ADC1_REQUEST              (KDATA_BASE_ADDR + 0x0074)
 #define KDATA_ADC2_REQUEST              (KDATA_BASE_ADDR + 0x0075)
-#define KDATA_CD_REQUEST                               (KDATA_BASE_ADDR + 0x0076)
-#define KDATA_MIC_REQUEST                              (KDATA_BASE_ADDR + 0x0077)
+#define KDATA_CD_REQUEST               (KDATA_BASE_ADDR + 0x0076)
+#define KDATA_MIC_REQUEST              (KDATA_BASE_ADDR + 0x0077)
 
 #define KDATA_ADC1_MIXER_REQUEST        (KDATA_BASE_ADDR + 0x0078)
 #define KDATA_ADC2_MIXER_REQUEST        (KDATA_BASE_ADDR + 0x0079)
-#define KDATA_CD_MIXER_REQUEST                 (KDATA_BASE_ADDR + 0x007A)
-#define KDATA_MIC_MIXER_REQUEST                        (KDATA_BASE_ADDR + 0x007B)
-#define KDATA_MIC_SYNC_COUNTER                 (KDATA_BASE_ADDR + 0x007C)
+#define KDATA_CD_MIXER_REQUEST         (KDATA_BASE_ADDR + 0x007A)
+#define KDATA_MIC_MIXER_REQUEST                (KDATA_BASE_ADDR + 0x007B)
+#define KDATA_MIC_SYNC_COUNTER         (KDATA_BASE_ADDR + 0x007C)
 
 /*
- * second 'segment' (?) reserved for mixer
- * buffers..
+ * second segment
  */
 
+/* smart mixer buffer */
+
 #define KDATA_MIXER_WORD0               (KDATA_BASE_ADDR2 + 0x0000)
 #define KDATA_MIXER_WORD1               (KDATA_BASE_ADDR2 + 0x0001)
 #define KDATA_MIXER_WORD2               (KDATA_BASE_ADDR2 + 0x0002)
 #define KDATA_DAC_LEFT_VOLUME          (KDATA_BASE_ADDR2 + 0x001F)
 #define KDATA_DAC_RIGHT_VOLUME          (KDATA_BASE_ADDR2 + 0x0020)
 
-#define MAX_INSTANCE_MINISRC            (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
-#define MAX_VIRTUAL_DMA_CHANNELS        (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
-#define MAX_VIRTUAL_MIXER_CHANNELS      (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
-#define MAX_VIRTUAL_ADC1_CHANNELS       (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
-
 /*
- * client data area offsets
+ * Client data memory definition
  */
+
 #define CDATA_INSTANCE_READY            0x00
 
 #define CDATA_HOST_SRC_ADDRL            0x01
 #define CDATA_IN_BUF_END_PLUS_1         0x0A
 #define CDATA_IN_BUF_HEAD               0x0B
 #define CDATA_IN_BUF_TAIL               0x0C
+
 #define CDATA_OUT_BUF_BEGIN             0x0D
 #define CDATA_OUT_BUF_END_PLUS_1        0x0E
 #define CDATA_OUT_BUF_HEAD              0x0F
 #define CDATA_LEFT_SUR_VOL              0x16
 #define CDATA_RIGHT_SUR_VOL             0x17
 
+/* These are from Allegro hckernel.h */
 #define CDATA_HEADER_LEN                0x18
-
 #define SRC3_DIRECTION_OFFSET           CDATA_HEADER_LEN
-#define SRC3_MODE_OFFSET                (CDATA_HEADER_LEN + 1)
-#define SRC3_WORD_LENGTH_OFFSET         (CDATA_HEADER_LEN + 2)
-#define SRC3_PARAMETER_OFFSET           (CDATA_HEADER_LEN + 3)
-#define SRC3_COEFF_ADDR_OFFSET          (CDATA_HEADER_LEN + 8)
-#define SRC3_FILTAP_ADDR_OFFSET         (CDATA_HEADER_LEN + 10)
-#define SRC3_TEMP_INBUF_ADDR_OFFSET     (CDATA_HEADER_LEN + 16)
-#define SRC3_TEMP_OUTBUF_ADDR_OFFSET    (CDATA_HEADER_LEN + 17)
+#define SRC3_MODE_OFFSET                CDATA_HEADER_LEN + 1
+#define SRC3_WORD_LENGTH_OFFSET         CDATA_HEADER_LEN + 2
+#define SRC3_PARAMETER_OFFSET           CDATA_HEADER_LEN + 3
+#define SRC3_COEFF_ADDR_OFFSET          CDATA_HEADER_LEN + 8
+#define SRC3_FILTAP_ADDR_OFFSET         CDATA_HEADER_LEN + 10
+#define SRC3_TEMP_INBUF_ADDR_OFFSET     CDATA_HEADER_LEN + 16
+#define SRC3_TEMP_OUTBUF_ADDR_OFFSET    CDATA_HEADER_LEN + 17
+#define FOR_FUTURE_USE                  10     /* for storing temporary variable in future */
 
-#define MINISRC_IN_BUFFER_SIZE   ( 0x50 * 2 )
-#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
-#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
-#define MINISRC_TMP_BUFFER_SIZE  ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
-#define MINISRC_BIQUAD_STAGE    2
-#define MINISRC_COEF_LOC          0X175
+/*
+ * DMA control definition
+ */
 
 #define DMACONTROL_BLOCK_MASK           0x000F
 #define  DMAC_BLOCK0_SELECTOR           0x0000
 #define DMACONTROL_AUTOREPEAT           0x1000
 #define DMACONTROL_STOPPED              0x2000
 #define DMACONTROL_DIRECTION            0x0100
+
+/*
+ * Kernel/client memory allocation
+ */
+
+#define NUM_UNITS_KERNEL_CODE          16
+#define NUM_UNITS_KERNEL_DATA           2
+
+#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
+#ifdef M3_MODEL
+#define NUM_UNITS_KERNEL_DATA_WITH_HSP  5
+#else
+#define NUM_UNITS_KERNEL_DATA_WITH_HSP  4
+#endif
+
+#define NUM_UNITS( BYTES, UNITLEN )    ((((BYTES+1)>>1) + (UNITLEN-1)) / UNITLEN)
+
+/*
+ * DSP hardware
+ */
+
+#define DSP_PORT_TIMER_COUNT            0x06
+#define DSP_PORT_MEMORY_INDEX           0x80
+#define DSP_PORT_MEMORY_TYPE            0x82
+#define DSP_PORT_MEMORY_DATA            0x84
+#define DSP_PORT_CONTROL_REG_A          0xA2
+#define DSP_PORT_CONTROL_REG_B          0xA4
+#define DSP_PORT_CONTROL_REG_C          0xA6
+
+#define MEMTYPE_INTERNAL_CODE           0x0002
+#define MEMTYPE_INTERNAL_DATA           0x0003
+#define MEMTYPE_MASK                    0x0003
+
+#define REGB_ENABLE_RESET               0x01
+#define REGB_STOP_CLOCK                 0x10
+
+#define REGC_DISABLE_FM_MAPPING         0x02
+
+#define DP_SHIFT_COUNT                  7
+
+#define DMA_BLOCK_LENGTH                32
+
+/* These are from Allegro srcmgr.h */
+#define MINISRC_BIQUAD_STAGE    2
+#define MINISRC_IN_BUFFER_SIZE   ( 0x50 * 2 )
+#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
+#define MINISRC_TMP_BUFFER_SIZE  ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
+#define MINISRC_BIQUAD_STAGE    2
+/* M. SRC LPF coefficient could be changed in the DSP code */
+#define MINISRC_COEF_LOC          0X175
+
+#endif /* !_DEV_SOUND_PCI_ALLEGRO_REG_H */
index 406f5df..6d5333f 100644 (file)
@@ -22,8 +22,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/dev/sound/pci/als4000.c,v 1.18.2.1 2005/12/30 19:55:53 netchild Exp $
  */
 
 /*
  * SB16 register descriptions.
  */
 
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
 #include <dev/sound/pcm/sound.h>
 #include <dev/sound/pci/sb.h>
 #include <dev/sound/pci/als4000.h>
 
-#include <bus/pci/pcireg.h>
-#include <bus/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
 
 #include "mixer_if.h"
 
+SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/als4000.c 274035 2014-11-03 11:11:45Z bapt $");
+
 /* Debugging macro's */
 #undef DEB
 #ifndef DEB
@@ -75,7 +79,7 @@ struct sc_info {
        struct resource         *reg, *irq;
        int                     regid, irqid;
        void                    *ih;
-       sndlock_t               lock;
+       struct mtx              *lock;
 
        unsigned int            bufsz;
        struct sc_chinfo        pch, rch;
@@ -84,10 +88,10 @@ struct sc_info {
 /* Channel caps */
 
 static u_int32_t als_format[] = {
-        AFMT_U8,
-        AFMT_STEREO | AFMT_U8,
-        AFMT_S16_LE,
-        AFMT_STEREO | AFMT_S16_LE,
+        SND_FORMAT(AFMT_U8, 1, 0),
+        SND_FORMAT(AFMT_U8, 2, 0),
+        SND_FORMAT(AFMT_S16_LE, 1, 0),
+        SND_FORMAT(AFMT_S16_LE, 2, 0),
         0
 };
 
@@ -216,12 +220,12 @@ alschan_init(kobj_t obj, void *devinfo,
        ch->parent = sc;
        ch->channel = c;
        ch->bps = 1;
-       ch->format = AFMT_U8;
+       ch->format = SND_FORMAT(AFMT_U8, 1, 0);
        ch->speed = DSP_DEFAULT_SPEED;
        ch->buffer = b;
        snd_mtxunlock(sc->lock);
 
-       if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0)
+       if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0)
                return NULL;
 
        return ch;
@@ -236,7 +240,7 @@ alschan_setformat(kobj_t obj, void *data, u_int32_t format)
        return 0;
 }
 
-static int
+static u_int32_t
 alschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
 {
        struct  sc_chinfo *ch = data, *other;
@@ -254,7 +258,7 @@ alschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
        return speed;
 }
 
-static int
+static u_int32_t
 alschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
 {
        struct  sc_chinfo *ch = data;
@@ -267,7 +271,7 @@ alschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
        return blocksize;
 }
 
-static int
+static u_int32_t
 alschan_getptr(kobj_t obj, void *data)
 {
        struct sc_chinfo *ch = data;
@@ -299,7 +303,7 @@ als_set_speed(struct sc_chinfo *ch)
                als_esp_wr(sc, ch->speed >> 8);
                als_esp_wr(sc, ch->speed & 0xff);
        } else {
-               DEB(kprintf("speed locked at %d (tried %d)\n",
+               DEB(printf("speed locked at %d (tried %d)\n",
                           other->speed, ch->speed));
        }
 }
@@ -310,16 +314,16 @@ als_set_speed(struct sc_chinfo *ch)
 #define ALS_8BIT_CMD(x, y)  { (x), (y), DSP_DMA8,  DSP_CMD_DMAPAUSE_8  }
 #define ALS_16BIT_CMD(x, y) { (x), (y),        DSP_DMA16, DSP_CMD_DMAPAUSE_16 }
 
-static const struct playback_command {
+struct playback_command {
        u_int32_t pcm_format;   /* newpcm format */
        u_int8_t  format_val;   /* sb16 format value */
        u_int8_t  dma_prog;     /* sb16 dma program */
        u_int8_t  dma_stop;     /* sb16 stop register */
-} playback_cmds[] = {
-       ALS_8BIT_CMD(AFMT_U8, DSP_MODE_U8MONO),
-       ALS_8BIT_CMD(AFMT_U8 | AFMT_STEREO, DSP_MODE_U8STEREO),
-       ALS_16BIT_CMD(AFMT_S16_LE, DSP_MODE_S16MONO),
-       ALS_16BIT_CMD(AFMT_S16_LE | AFMT_STEREO, DSP_MODE_S16STEREO),
+} static const playback_cmds[] = {
+       ALS_8BIT_CMD(SND_FORMAT(AFMT_U8, 1, 0), DSP_MODE_U8MONO),
+       ALS_8BIT_CMD(SND_FORMAT(AFMT_U8, 2, 0), DSP_MODE_U8STEREO),
+       ALS_16BIT_CMD(SND_FORMAT(AFMT_S16_LE, 1, 0), DSP_MODE_S16MONO),
+       ALS_16BIT_CMD(SND_FORMAT(AFMT_S16_LE, 2, 0), DSP_MODE_S16STEREO),
 };
 
 static const struct playback_command*
@@ -327,13 +331,13 @@ als_get_playback_command(u_int32_t format)
 {
        u_int32_t i, n;
 
-       n = NELEM(playback_cmds);
+       n = sizeof(playback_cmds) / sizeof(playback_cmds[0]);
        for (i = 0; i < n; i++) {
                if (playback_cmds[i].pcm_format == format) {
                        return &playback_cmds[i];
                }
        }
-       DEB(kprintf("als_get_playback_command: invalid format 0x%08x\n",
+       DEB(printf("als_get_playback_command: invalid format 0x%08x\n",
                   format));
        return &playback_cmds[0];
 }
@@ -391,14 +395,20 @@ alspchan_trigger(kobj_t obj, void *data, int go)
        struct  sc_chinfo *ch = data;
        struct sc_info *sc = ch->parent;
 
+       if (!PCMTRIG_COMMON(go))
+               return 0;