diff --git a/Makefile b/Makefile
index b622897b6678..b2613b68b645 100644
--- a/Makefile
+++ b/Makefile
@@ -96,7 +96,7 @@
#
# Once you have installed the necessary cross toolchain, simply pass
# CROSS_TOOLCHAIN=${TARGET_ARCH}-gccN while building with the above steps,
-# e.g., `make buildworld CROSS_TOOLCHAIN=amd64-gcc6`.
+# e.g., `make buildworld CROSS_TOOLCHAIN=amd64-gcc13`.
#
# The ${TARGET_ARCH}-gccN packages are provided as flavors of the
# devel/freebsd-gccN ports.
diff --git a/contrib/wpa/src/drivers/driver_bsd.c b/contrib/wpa/src/drivers/driver_bsd.c
index d5ff51cee456..14c19eb1246c 100644
--- a/contrib/wpa/src/drivers/driver_bsd.c
+++ b/contrib/wpa/src/drivers/driver_bsd.c
@@ -1557,17 +1557,6 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
if (devcaps.dc_drivercaps & IEEE80211_C_WPA2)
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-#ifdef __FreeBSD__
- drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
- WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP |
- WPA_DRIVER_CAPA_ENC_CCMP;
-#else
- /*
- * XXX
- * FreeBSD exports hardware cryptocaps. These have no meaning for wpa
- * since net80211 performs software crypto.
- */
if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
@@ -1576,7 +1565,6 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-#endif
if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 6da3b6969107..479b96123012 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -1336,22 +1336,20 @@ static struct snl_field_parser fp_getrules[] = {
SNL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, fp_getrules, ap_getrules);
int
-pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t ruleset,
+pfctl_get_rules_info_h(struct pfctl_handle *h, struct pfctl_rules_info *rules, uint32_t ruleset,
const char *path)
{
- struct snl_state ss = {};
struct snl_errmsg_data e = {};
struct nlmsghdr *hdr;
struct snl_writer nw;
uint32_t seq_id;
int family_id;
- snl_init(&ss, NETLINK_GENERIC);
- family_id = snl_get_genl_family(&ss, PFNL_FAMILY_NAME);
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
if (family_id == 0)
return (ENOTSUP);
- snl_init_writer(&ss, &nw);
+ snl_init_writer(&h->ss, &nw);
hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETRULES);
hdr->nlmsg_flags |= NLM_F_DUMP;
@@ -1363,17 +1361,33 @@ pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t
return (ENOMEM);
seq_id = hdr->nlmsg_seq;
- if (! snl_send_message(&ss, hdr))
+ if (! snl_send_message(&h->ss, hdr))
return (ENXIO);
- while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) {
- if (! snl_parse_nlmsg(&ss, hdr, &getrules_parser, rules))
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (! snl_parse_nlmsg(&h->ss, hdr, &getrules_parser, rules))
continue;
}
return (e.error);
}
+int
+pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t ruleset,
+ const char *path)
+{
+ struct pfctl_handle *h;
+ int error;
+
+ h = pfctl_open(PF_DEVICE);
+ if (h == NULL)
+ return (ENOTSUP);
+ error = pfctl_get_rules_info_h(h, rules, ruleset, path);
+ pfctl_close(h);
+
+ return (error);
+}
+
int
pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor,
uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call)
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index 2937a36a8a47..73282eb3cc3d 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -412,6 +412,9 @@ int pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
char *anchor_call);
int pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r,
const char *anchor, const char *anchor_call, uint32_t ticket);
+int pfctl_get_rules_info_h(struct pfctl_handle *h,
+ struct pfctl_rules_info *rules, uint32_t ruleset,
+ const char *path);
int pfctl_get_rules_info(int dev, struct pfctl_rules_info *rules,
uint32_t ruleset, const char *path);
int pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket,
diff --git a/release/Makefile.vm b/release/Makefile.vm
index 1124680e3191..548b4c1cca3b 100644
--- a/release/Makefile.vm
+++ b/release/Makefile.vm
@@ -223,14 +223,16 @@ vm-install:
${DESTDIR}/vmimages/CHECKSUM.SHA256
.endif
-vm-release:
.if defined(WITH_VMIMAGES) && !empty(WITH_VMIMAGES)
- ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${VMTARGETS}
+vm-release: ${VMTARGETS}
+.else
+vm-release:
.endif
-cloudware-release:
.if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE)
- ${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} ${CLOUDTARGETS}
+cloudware-release: ${CLOUDTARGETS}
+.else
+cloudware-release:
.endif
.include "${.CURDIR}/Makefile.azure"
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 17901b04a130..19d05c415f02 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1283,14 +1283,14 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
}
if (opts & PF_OPT_SHOWALL) {
- ret = pfctl_get_rules_info(dev, &ri, PF_PASS, path);
+ ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path);
if (ret != 0) {
warn("DIOCGETRULES");
goto error;
}
header++;
}
- ret = pfctl_get_rules_info(dev, &ri, PF_SCRUB, path);
+ ret = pfctl_get_rules_info_h(pfh, &ri, PF_SCRUB, path);
if (ret != 0) {
warn("DIOCGETRULES");
goto error;
@@ -1328,7 +1328,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
}
pfctl_clear_pool(&rule.rpool);
}
- ret = pfctl_get_rules_info(dev, &ri, PF_PASS, path);
+ ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path);
if (ret != 0) {
warn("DIOCGETRULES");
goto error;
@@ -1435,7 +1435,7 @@ pfctl_show_nat(int dev, char *path, int opts, char *anchorname, int depth)
snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
for (i = 0; i < 3; i++) {
- ret = pfctl_get_rules_info(dev, &ri, nattype[i], path);
+ ret = pfctl_get_rules_info_h(pfh, &ri, nattype[i], path);
if (ret != 0) {
warn("DIOCGETRULES");
return (-1);
@@ -2130,6 +2130,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
ERRX("pfctl_rules: strlcpy");
pf.dev = dev;
+ pf.h = pfh;
pf.opts = opts;
pf.optimize = optimize;
pf.loadopt = loadopt;
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index 95292999c50a..9b43a840c06f 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -889,7 +889,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
TAILQ_INIT(&queue);
TAILQ_INIT(&prof_superblocks);
- if (pfctl_get_rules_info(pf->dev, &rules, PF_PASS, "")) {
+ if (pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) {
warn("DIOCGETRULES");
return (1);
}
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index d0f3bc3c303c..6534baa9a7dd 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -75,6 +75,7 @@ struct pfr_buffer; /* forward definition */
struct pfctl {
int dev;
+ struct pfctl_handle *h;
int opts;
int optimize;
int loadopt;
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 595da069f73c..c5ba7e46deb8 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -519,6 +519,7 @@ MAN= aac.4 \
snd_es137x.4 \
snd_fm801.4 \
snd_hda.4 \
+ snd_hdsp.4 \
snd_hdspe.4 \
snd_ich.4 \
snd_maestro3.4 \
diff --git a/share/man/man4/pcm.4 b/share/man/man4/pcm.4
index e406bd2c8343..5fcaca7220b9 100644
--- a/share/man/man4/pcm.4
+++ b/share/man/man4/pcm.4
@@ -101,6 +101,8 @@ The following bridge device drivers are available:
.It
.Xr snd_hda 4 (enabled by default on amd64, i386)
.It
+.Xr snd_hdsp 4
+.It
.Xr snd_hdspe 4
.It
.Xr snd_ich 4 (enabled by default on amd64, i386)
@@ -609,6 +611,7 @@ A device node is not created properly.
.Xr snd_es137x 4 ,
.Xr snd_fm801 4 ,
.Xr snd_hda 4 ,
+.Xr snd_hdsp 4 ,
.Xr snd_hdspe 4 ,
.Xr snd_ich 4 ,
.Xr snd_maestro3 4 ,
diff --git a/share/man/man4/snd_hdsp.4 b/share/man/man4/snd_hdsp.4
new file mode 100644
index 000000000000..23eb98a3ccc2
--- /dev/null
+++ b/share/man/man4/snd_hdsp.4
@@ -0,0 +1,154 @@
+.\" Copyright (c) 2012 Ruslan Bukin
+.\" Copyright (c) 2024 Florian Walpen
+.\" 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.
+.\"
+.Dd May 1, 2024
+.Dt SND_HDSP 4
+.Os
+.Sh NAME
+.Nm snd_hdsp
+.Nd "RME HDSP 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 sound"
+.Cd "device snd_hdsp"
+.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_hdsp_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+bridge driver allows the generic audio driver
+.Xr sound 4
+to attach to RME HDSP audio devices.
+.Sh HARDWARE
+The
+.Nm
+driver supports the following audio devices:
+.Pp
+.Bl -bullet -compact
+.It
+RME HDSP 9632
+.It
+RME HDSP 9652
+.El
+.Pp
+By default, each
+.Xr pcm 4
+device corresponds to a physical port on the sound card.
+For ADAT ports, 8 channel, 4 channel and 2 channel formats are supported.
+The effective number of ADAT channels is 8 channels at single speed
+(32kHz-48kHz) and 4 channels at double speed (64kHz-96kHz).
+Only the HDSP 9632 can operate at quad speed (128kHz-192kHz), ADAT is
+disabled in this mode.
+Depending on sample rate and channel format selected, not all pcm channels can
+be mapped to ADAT channels and vice versa.
+.Sh LOADER TUNABLES
+These settings can be entered at the
+.Xr loader 8
+prompt or in
+.Xr loader.conf 5 .
+.Bl -tag -width indent
+.It Va hw.hdsp.unified_pcm
+If set to 1, all physical ports are combined into one unified pcm device.
+When opened in multi-channel audio software, this makes all ports available
+at the same time, and fully synchronized.
+For resulting channel numbers consult the following table:
+.El
+.Bl -column "Sound Card" "Single Speed" "Double Speed" "Quad Speed"
+.Sy "Sound Card" Ta Sy "Single Speed" Ta Sy "Double Speed" Ta Sy "Quad Speed"
+.It "" Ta "Play | Rec" Ta "Play | Rec" Ta "Play | Rec"
+.It HDSP 9632 Ta " 12 | 12" Ta " 8 | 8" Ta " 4 | 4"
+.It HDSP 9652 Ta " 26 | 26" Ta " 14 | 14" Ta " - | -"
+.El
+.Sh SYSCTL TUNABLES
+These settings and informational values can be accessed at runtime with the
+.Xr sysctl 8
+command.
+If multiple RME HDSP sound cards are installed, each device has a separate
+configuration.
+To adjust the following sysctl identifiers for a specific sound card, insert
+the respective device number in place of
+.Ql 0 .
+.Bl -tag -width indent
+.It Va dev.hdsp.0.sample_rate
+Set a fixed sample rate from 32000, 44100, 48000, up to 192000.
+This is usually required for digital connections (AES, S/PDIF, ADAT).
+The default value of 0 adjusts the sample rate according to pcm device settings.
+.It Va dev.hdsp.0.period
+The number of samples processed per interrupt, from 32, 64, 128, up to 4096.
+Setting a lower value here results in less latency, but increases system load
+due to frequent interrupt processing.
+Extreme values may cause audio gaps and glitches.
+.It Va dev.hdsp.0.clock_list
+Lists possible clock sources to sync with, depending on the hardware model.
+This includes internal and external master clocks as well as incoming digital
+audio signals like AES, S/PDIF and ADAT.
+.It Va dev.hdsp.0.clock_preference
+Select a preferred clock source from the clock list.
+HDSP cards will sync to this clock source when available, but fall back to
+auto-sync with any other digital clock signal they receive.
+Set this to
+.Ql internal
+if the HDSP card should act as master clock.
+.It Va dev.hdsp.0.clock_source
+Shows the actual clock source in use (read only).
+This differs from what is set as clock preference when in auto-sync mode.
+.It Va dev.hdsp.0.sync_status
+Display the current sync status of all external clock sources.
+Status indications are
+.Ql none
+for no signal at all,
+.Ql lock
+for when a valid signal is present, and
+.Ql sync
+for accurately synchronized signals (required for recording digital
+audio).
+.El
+.Pp
+Where appropriate these sysctl values are modeled after official RME software on
+other platforms, and adopt their terminology.
+Consult the RME user manuals for additional information.
+.Sh SEE ALSO
+.Xr sound 4
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+.An -nosplit
+Based on
+.Xr snd_hdspe 4
+originally written by
+.An Ruslan Bukin
.
+All adaptation to HDSP cards by
+.An Florian Walpen .
diff --git a/share/man/man9/ieee80211.9 b/share/man/man9/ieee80211.9
index 100b4e7540a5..40c8c243a77c 100644
--- a/share/man/man9/ieee80211.9
+++ b/share/man/man9/ieee80211.9
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 26, 2021
+.Dd April 24, 2024
.Dt IEEE80211 9
.Os
.Sh NAME
@@ -514,6 +514,8 @@ General capabilities are specified by
.Vt ic_caps .
Hardware cryptographic capabilities are specified by
.Vt ic_cryptocaps .
+Software cryptographic capabilities are specified by
+.Vt ic_sw_cryptocaps .
802.11n capabilities, if any, are specified by
.Vt ic_htcaps .
The
diff --git a/sys/arm/arm/pmu.c b/sys/arm/arm/pmu.c
index 98d8cdcf2df8..050121934447 100644
--- a/sys/arm/arm/pmu.c
+++ b/sys/arm/arm/pmu.c
@@ -46,6 +46,7 @@
#include
#include
#include
+#include
#include
#include
@@ -65,9 +66,6 @@ uint32_t ccnt_hi[MAXCPU];
static int
pmu_intr(void *arg)
{
-#ifdef HWPMC_HOOKS
- struct trapframe *tf;
-#endif
uint32_t r;
#if defined(__arm__) && (__ARM_ARCH > 6)
u_int cpu;
@@ -87,10 +85,8 @@ pmu_intr(void *arg)
#ifdef HWPMC_HOOKS
/* Only call into the HWPMC framework if we know there is work. */
- if (r != 0 && pmc_intr) {
- tf = arg;
- (*pmc_intr)(tf);
- }
+ if (r != 0 && pmc_intr)
+ (*pmc_intr)(curthread->td_intr_frame);
#endif
return (FILTER_HANDLED);
diff --git a/sys/arm/include/atomic.h b/sys/arm/include/atomic.h
index 2cf97017b04a..88b5bd7acbc5 100644
--- a/sys/arm/include/atomic.h
+++ b/sys/arm/include/atomic.h
@@ -1052,6 +1052,12 @@ atomic_thread_fence_seq_cst(void)
dmb();
}
+#define atomic_add_ptr atomic_add_32
+#define atomic_add_acq_ptr atomic_add_acq_32
+#define atomic_add_rel_ptr atomic_add_rel_32
+#define atomic_subtract_ptr atomic_subtract_32
+#define atomic_subtract_acq_ptr atomic_subtract_acq_32
+#define atomic_subtract_rel_ptr atomic_subtract_rel_32
#define atomic_clear_ptr atomic_clear_32
#define atomic_clear_acq_ptr atomic_clear_acq_32
#define atomic_clear_rel_ptr atomic_clear_rel_32
@@ -1059,15 +1065,16 @@ atomic_thread_fence_seq_cst(void)
#define atomic_set_acq_ptr atomic_set_acq_32
#define atomic_set_rel_ptr atomic_set_rel_32
#define atomic_fcmpset_ptr atomic_fcmpset_32
-#define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_32
#define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_32
+#define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_32
#define atomic_cmpset_ptr atomic_cmpset_32
#define atomic_cmpset_acq_ptr atomic_cmpset_acq_32
#define atomic_cmpset_rel_ptr atomic_cmpset_rel_32
+#define atomic_fetchadd_ptr atomic_fetchadd_32
+#define atomic_readandclear_ptr atomic_readandclear_32
#define atomic_load_acq_ptr atomic_load_acq_32
#define atomic_store_rel_ptr atomic_store_rel_32
#define atomic_swap_ptr atomic_swap_32
-#define atomic_readandclear_ptr atomic_readandclear_32
#define atomic_add_int atomic_add_32
#define atomic_add_acq_int atomic_add_acq_32
diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h
index d5f9a0ae7a47..dfd9816da8be 100644
--- a/sys/compat/linuxkpi/common/include/linux/interrupt.h
+++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h
@@ -133,7 +133,7 @@ irq_set_affinity_hint(int vector, const cpumask_t *mask)
int error;
if (mask != NULL)
- error = intr_setaffinity(vector, CPU_WHICH_IRQ, __DECONST(cpumask_t *, mask));
+ error = intr_setaffinity(vector, CPU_WHICH_IRQ, mask);
else
error = intr_setaffinity(vector, CPU_WHICH_IRQ, cpuset_root);
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index f0b8cbce2827..df27e67f849c 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2096,6 +2096,7 @@ device sound
# snd_fm801: Forte Media FM801 PCI.
# snd_hda: Intel High Definition Audio (Controller) and
# compatible.
+# snd_hdsp: RME HDSP 9632 and HDSP 9652
# snd_hdspe: RME HDSPe AIO and RayDAT.
# snd_ich: Intel ICH AC'97 and some more audio controllers
# embedded in a chipset, for example nVidia
@@ -2123,6 +2124,7 @@ device snd_envy24ht
device snd_es137x
device snd_fm801
device snd_hda
+device snd_hdsp
device snd_hdspe
device snd_ich
device snd_maestro3
diff --git a/sys/conf/files b/sys/conf/files
index c8323f33e8e3..2da62ac6b11c 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3115,6 +3115,8 @@ 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/hdsp.c optional snd_hdsp pci
+dev/sound/pci/hdsp-pcm.c optional snd_hdsp pci
dev/sound/pci/hdspe.c optional snd_hdspe pci
dev/sound/pci/hdspe-pcm.c optional snd_hdspe pci
dev/sound/pcm/ac97.c optional sound
diff --git a/sys/dev/etherswitch/ip17x/ip17x.c b/sys/dev/etherswitch/ip17x/ip17x.c
index 218c0c293662..65e548ba293b 100644
--- a/sys/dev/etherswitch/ip17x/ip17x.c
+++ b/sys/dev/etherswitch/ip17x/ip17x.c
@@ -556,7 +556,7 @@ ip17x_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
static int
ip17x_readreg(device_t dev, int addr)
{
- struct ip17x_softc *sc;
+ struct ip17x_softc *sc __diagused;
sc = device_get_softc(dev);
IP17X_LOCK_ASSERT(sc, MA_OWNED);
@@ -568,7 +568,7 @@ ip17x_readreg(device_t dev, int addr)
static int
ip17x_writereg(device_t dev, int addr, int value)
{
- struct ip17x_softc *sc;
+ struct ip17x_softc *sc __diagused;
sc = device_get_softc(dev);
IP17X_LOCK_ASSERT(sc, MA_OWNED);
diff --git a/sys/dev/sound/driver.c b/sys/dev/sound/driver.c
index 927941ab3d01..6bfe6c51fa3e 100644
--- a/sys/dev/sound/driver.c
+++ b/sys/dev/sound/driver.c
@@ -67,6 +67,7 @@ MODULE_DEPEND(snd_driver, snd_envy24ht, 1, 1, 1);
MODULE_DEPEND(snd_driver, snd_es137x, 1, 1, 1);
MODULE_DEPEND(snd_driver, snd_fm801, 1, 1, 1);
MODULE_DEPEND(snd_driver, snd_hda, 1, 1, 1);
+MODULE_DEPEND(snd_driver, snd_hdsp, 1, 1, 1);
MODULE_DEPEND(snd_driver, snd_hdspe, 1, 1, 1);
MODULE_DEPEND(snd_driver, snd_ich, 1, 1, 1);
MODULE_DEPEND(snd_driver, snd_maestro3, 1, 1, 1);
diff --git a/sys/dev/sound/pci/hdsp-pcm.c b/sys/dev/sound/pci/hdsp-pcm.c
new file mode 100644
index 000000000000..9ba0e5e345d0
--- /dev/null
+++ b/sys/dev/sound/pci/hdsp-pcm.c
@@ -0,0 +1,1134 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2012-2021 Ruslan Bukin
+ * Copyright (c) 2023-2024 Florian Walpen
+ * 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.
+ */
+
+/*
+ * RME HDSP driver for FreeBSD (pcm-part).
+ * Supported cards: HDSP 9632, HDSP 9652.
+ */
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+#define HDSP_MATRIX_MAX 8
+
+struct hdsp_latency {
+ uint32_t n;
+ uint32_t period;
+ float ms;
+};
+
+static struct hdsp_latency latency_map[] = {
+ { 7, 32, 0.7 },
+ { 0, 64, 1.5 },
+ { 1, 128, 3 },
+ { 2, 256, 6 },
+ { 3, 512, 12 },
+ { 4, 1024, 23 },
+ { 5, 2048, 46 },
+ { 6, 4096, 93 },
+
+ { 0, 0, 0 },
+};
+
+struct hdsp_rate {
+ uint32_t speed;
+ uint32_t reg;
+};
+
+static struct hdsp_rate rate_map[] = {
+ { 32000, (HDSP_FREQ_32000) },
+ { 44100, (HDSP_FREQ_44100) },
+ { 48000, (HDSP_FREQ_48000) },
+ { 64000, (HDSP_FREQ_32000 | HDSP_FREQ_DOUBLE) },
+ { 88200, (HDSP_FREQ_44100 | HDSP_FREQ_DOUBLE) },
+ { 96000, (HDSP_FREQ_48000 | HDSP_FREQ_DOUBLE) },
+ { 128000, (HDSP_FREQ_32000 | HDSP_FREQ_QUAD) },
+ { 176400, (HDSP_FREQ_44100 | HDSP_FREQ_QUAD) },
+ { 192000, (HDSP_FREQ_48000 | HDSP_FREQ_QUAD) },
+
+ { 0, 0 },
+};
+
+static uint32_t
+hdsp_adat_slot_map(uint32_t speed)
+{
+ /* ADAT slot bitmap depends on sample rate. */
+ if (speed <= 48000)
+ return (0x000000ff); /* 8 channels single speed. */
+ else if (speed <= 96000)
+ return (0x000000aa); /* 4 channels (1,3,5,7) double speed. */
+ else
+ return (0x00000000); /* ADAT disabled at quad speed. */
+}
+
+static uint32_t
+hdsp_port_slot_map(uint32_t ports, uint32_t speed)
+{
+ uint32_t slot_map = 0;
+
+ if (ports & HDSP_CHAN_9632_ALL) {
+ /* Map HDSP 9632 ports to slot bitmap. */
+ if (ports & HDSP_CHAN_9632_ADAT)
+ slot_map |= (hdsp_adat_slot_map(speed) << 0);
+ if (ports & HDSP_CHAN_9632_SPDIF)
+ slot_map |= (0x03 << 8); /* 2 channels SPDIF. */
+ if (ports & HDSP_CHAN_9632_LINE)
+ slot_map |= (0x03 << 10); /* 2 channels line. */
+ if (ports & HDSP_CHAN_9632_EXT_BOARD)
+ slot_map |= (0x0f << 12); /* 4 channels extension. */
+ } else if ((ports & HDSP_CHAN_9652_ALL) && (speed <= 96000)) {
+ /* Map HDSP 9652 ports to slot bitmap, no quad speed. */
+ if (ports & HDSP_CHAN_9652_ADAT1)
+ slot_map |= (hdsp_adat_slot_map(speed) << 0);
+ if (ports & HDSP_CHAN_9652_ADAT2)
+ slot_map |= (hdsp_adat_slot_map(speed) << 8);
+ if (ports & HDSP_CHAN_9652_ADAT3)
+ slot_map |= (hdsp_adat_slot_map(speed) << 16);
+ if (ports & HDSP_CHAN_9652_SPDIF)
+ slot_map |= (0x03 << 24); /* 2 channels SPDIF. */
+ }
+
+ return (slot_map);
+}
+
+static uint32_t
+hdsp_slot_first(uint32_t slots)
+{
+ return (slots & (~(slots - 1))); /* Extract first bit set. */
+}
+
+static uint32_t
+hdsp_slot_first_row(uint32_t slots)
+{
+ uint32_t ends;
+
+ /* Ends of slot rows are followed by a slot which is not in the set. */
+ ends = slots & (~(slots >> 1));
+ /* First row of contiguous slots ends in the first row end. */
+ return (slots & (ends ^ (ends - 1)));
+}
+
+static uint32_t
+hdsp_slot_first_n(uint32_t slots, unsigned int n)
+{
+ /* Clear all but the first n slots. */
+ for (uint32_t slot = 1; slot != 0; slot <<= 1) {
+ if ((slots & slot) && n > 0)
+ --n;
+ else
+ slots &= ~slot;
+ }
+ return (slots);
+}
+
+static unsigned int
+hdsp_slot_count(uint32_t slots)
+{
+ return (bitcount32(slots));
+}
+
+static unsigned int
+hdsp_slot_offset(uint32_t slots)
+{
+ return (hdsp_slot_count(hdsp_slot_first(slots) - 1));
+}
+
+static unsigned int
+hdsp_slot_channel_offset(uint32_t subset, uint32_t slots)
+{
+ uint32_t preceding;
+
+ /* Make sure we have a subset of slots. */
+ subset &= slots;
+ /* Include all slots preceding the first one of the subset. */
+ preceding = slots & (hdsp_slot_first(subset) - 1);
+
+ return (hdsp_slot_count(preceding));
+}
+
+static uint32_t
+hdsp_port_first(uint32_t ports)
+{
+ return (ports & (~(ports - 1))); /* Extract first bit set. */
+}
+
+static unsigned int
+hdsp_port_slot_count(uint32_t ports, uint32_t speed)
+{
+ return (hdsp_slot_count(hdsp_port_slot_map(ports, speed)));
+}
+
+static unsigned int
+hdsp_port_slot_count_max(uint32_t ports)
+{
+ return (hdsp_slot_count(hdsp_port_slot_map(ports, 48000)));
+}
+
+static uint32_t
+hdsp_channel_play_ports(struct hdsp_channel *hc)
+{
+ return (hc->ports & (HDSP_CHAN_9632_ALL | HDSP_CHAN_9652_ALL));
+}
+
+static uint32_t
+hdsp_channel_rec_ports(struct hdsp_channel *hc)
+{
+ return (hc->ports & (HDSP_CHAN_9632_ALL | HDSP_CHAN_9652_ALL));
+}
+
+static int
+hdsp_hw_mixer(struct sc_chinfo *ch, unsigned int dst,
+ unsigned int src, unsigned short data)
+{
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ uint32_t value;
+ int offset;
+
+ scp = ch->parent;
+ sc = scp->sc;
+
+ offset = 0;
+ value = (HDSP_MIN_GAIN << 16) | (uint16_t) data;
+
+ if (ch->dir != PCMDIR_PLAY)
+ return (0);
+
+ switch (sc->type) {
+ case HDSP_9632:
+ /* Mixer is 2 rows of sources (inputs, playback) per output. */
+ offset = dst * (2 * HDSP_MIX_SLOTS_9632);
+ /* Source index in the second row (playback). */
+ offset += HDSP_MIX_SLOTS_9632 + src;
+ break;
+ case HDSP_9652:
+ /* Mixer is 2 rows of sources (inputs, playback) per output. */
+ offset = dst * (2 * HDSP_MIX_SLOTS_9652);
+ /* Source index in the second row (playback). */
+ offset += HDSP_MIX_SLOTS_9652 + src;
+ break;
+ default:
+ return (0);
+ }
+
+ /*
+ * We have to write mixer matrix values in pairs, with the second
+ * (odd) value in the upper 16 bits of the 32 bit value.
+ * Make value offset even and shift value accordingly.
+ * Assume the paired value to be silenced, since we only set gain
+ * on the diagonal where src and dst are the same.
+ */
+ if (offset % 2) {
+ offset -= 1;
+ value = (value << 16) | HDSP_MIN_GAIN;
+ }
+
+ hdsp_write_4(sc, HDSP_MIXER_BASE + offset * sizeof(uint16_t), value);
+
+ return (0);
+};
+
+static int
+hdspchan_setgain(struct sc_chinfo *ch)
+{
+ uint32_t port, ports;
+ uint32_t slot, slots;
+ unsigned int offset;
+ unsigned short volume;
+
+ /* Iterate through all physical ports of the channel. */
+ ports = ch->ports;
+ port = hdsp_port_first(ports);
+ while (port != 0) {
+ /*
+ * Get slot map from physical port.
+ * Unlike DMA buffers, the hardware mixer's channel mapping
+ * does not change with double or quad speed sample rates.
+ */
+ slots = hdsp_port_slot_map(port, 48000);
+ slot = hdsp_slot_first(slots);
+
+ /* Treat first slot as left channel. */
+ volume = ch->lvol * HDSP_MAX_GAIN / 100;
+ while (slot != 0) {
+ offset = hdsp_slot_offset(slot);
+ hdsp_hw_mixer(ch, offset, offset, volume);
+
+ slots &= ~slot;
+ slot = hdsp_slot_first(slots);
+
+ /* Subsequent slots all get the right channel volume. */
+ volume = ch->rvol * HDSP_MAX_GAIN / 100;
+ }
+
+ ports &= ~port;
+ port = hdsp_port_first(ports);
+ }
+
+ return (0);
+}
+
+static int
+hdspmixer_init(struct snd_mixer *m)
+{
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ int mask;
+
+ scp = mix_getdevinfo(m);
+ sc = scp->sc;
+ if (sc == NULL)
+ return (-1);
+
+ mask = SOUND_MASK_PCM;
+
+ if (hdsp_channel_play_ports(scp->hc))
+ mask |= SOUND_MASK_VOLUME;
+
+ if (hdsp_channel_rec_ports(scp->hc))
+ mask |= SOUND_MASK_RECLEV;
+
+ snd_mtxlock(sc->lock);
+ pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL);
+ mix_setdevs(m, mask);
+ snd_mtxunlock(sc->lock);
+
+ return (0);
+}
+
+static int
+hdspmixer_set(struct snd_mixer *m, unsigned dev,
+ unsigned left, unsigned right)
+{
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ int i;
+
+ scp = mix_getdevinfo(m);
+
+#if 0
+ device_printf(scp->dev, "hdspmixer_set() %d %d\n",
+ left, right);
+#endif
+
+ for (i = 0; i < scp->chnum; i++) {
+ ch = &scp->chan[i];
+ if ((dev == SOUND_MIXER_VOLUME && ch->dir == PCMDIR_PLAY) ||
+ (dev == SOUND_MIXER_RECLEV && ch->dir == PCMDIR_REC)) {
+ ch->lvol = left;
+ ch->rvol = right;
+ if (ch->run)
+ hdspchan_setgain(ch);
+ }
+ }
+
+ return (0);
+}
+
+static kobj_method_t hdspmixer_methods[] = {
+ KOBJMETHOD(mixer_init, hdspmixer_init),
+ KOBJMETHOD(mixer_set, hdspmixer_set),
+ KOBJMETHOD_END
+};
+MIXER_DECLARE(hdspmixer);
+
+static void
+hdspchan_enable(struct sc_chinfo *ch, int value)
+{
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ uint32_t slot, slots;
+ unsigned int offset;
+ int reg;
+
+ scp = ch->parent;
+ sc = scp->sc;
+
+ if (ch->dir == PCMDIR_PLAY)
+ reg = HDSP_OUT_ENABLE_BASE;
+ else
+ reg = HDSP_IN_ENABLE_BASE;
+
+ ch->run = value;
+
+ /* Iterate through all slots of the channel's physical ports. */
+ slots = hdsp_port_slot_map(ch->ports, sc->speed);
+ slot = hdsp_slot_first(slots);
+ while (slot != 0) {
+ /* Set register to enable or disable slot. */
+ offset = hdsp_slot_offset(slot);
+ hdsp_write_1(sc, reg + (4 * offset), value);
+
+ slots &= ~slot;
+ slot = hdsp_slot_first(slots);
+ }
+}
+
+static int
+hdsp_running(struct sc_info *sc)
+{
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ device_t *devlist;
+ int devcount;
+ int i, j;
+ int running;
+
+ running = 0;
+
+ devlist = NULL;
+ devcount = 0;
+
+ if (device_get_children(sc->dev, &devlist, &devcount) != 0)
+ running = 1; /* On error, avoid channel config changes. */
+
+ for (i = 0; running == 0 && i < devcount; i++) {
+ scp = device_get_ivars(devlist[i]);
+ for (j = 0; j < scp->chnum; j++) {
+ ch = &scp->chan[j];
+ if (ch->run) {
+ running = 1;
+ break;
+ }
+ }
+ }
+
+#if 0
+ if (running == 1)
+ device_printf(sc->dev, "hdsp is running\n");
+#endif
+
+ free(devlist, M_TEMP);
+
+ return (running);
+}
+
+static void
+hdsp_start_audio(struct sc_info *sc)
+{
+
+ sc->ctrl_register |= (HDSP_AUDIO_INT_ENABLE | HDSP_ENABLE);
+ hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
+}
+
+static void
+hdsp_stop_audio(struct sc_info *sc)
+{
+
+ if (hdsp_running(sc) == 1)
+ return;
+
+ sc->ctrl_register &= ~(HDSP_AUDIO_INT_ENABLE | HDSP_ENABLE);
+ hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
+}
+
+static void
+buffer_mux_write(uint32_t *dma, uint32_t *pcm, unsigned int pos,
+ unsigned int pos_end, unsigned int width, unsigned int channels)
+{
+ unsigned int slot;
+
+ for (; pos < pos_end; ++pos) {
+ for (slot = 0; slot < width; slot++) {
+ dma[slot * HDSP_CHANBUF_SAMPLES + pos] =
+ pcm[pos * channels + slot];
+ }
+ }
+}
+
+static void
+buffer_mux_port(uint32_t *dma, uint32_t *pcm, uint32_t subset, uint32_t slots,
+ unsigned int pos, unsigned int samples, unsigned int channels)
+{
+ unsigned int slot_offset, width;
+ unsigned int chan_pos;
+
+ /* Translate DMA slot offset to DMA buffer offset. */
+ slot_offset = hdsp_slot_offset(subset);
+ dma += slot_offset * HDSP_CHANBUF_SAMPLES;
+
+ /* Channel position of the slot subset. */
+ chan_pos = hdsp_slot_channel_offset(subset, slots);
+ pcm += chan_pos;
+
+ /* Only copy channels supported by both hardware and pcm format. */
+ width = hdsp_slot_count(subset);
+
+ /* Let the compiler inline and loop unroll common cases. */
+ if (width == 1)
+ buffer_mux_write(dma, pcm, pos, pos + samples, 1, channels);
+ else if (width == 2)
+ buffer_mux_write(dma, pcm, pos, pos + samples, 2, channels);
+ else if (width == 4)
+ buffer_mux_write(dma, pcm, pos, pos + samples, 4, channels);
+ else if (width == 8)
+ buffer_mux_write(dma, pcm, pos, pos + samples, 8, channels);
+ else
+ buffer_mux_write(dma, pcm, pos, pos + samples, width, channels);
+}
+
+static void
+buffer_demux_read(uint32_t *dma, uint32_t *pcm, unsigned int pos,
+ unsigned int pos_end, unsigned int width, unsigned int channels)
+{
+ unsigned int slot;
+
+ for (; pos < pos_end; ++pos) {
+ for (slot = 0; slot < width; slot++) {
+ pcm[pos * channels + slot] =
+ dma[slot * HDSP_CHANBUF_SAMPLES + pos];
+ }
+ }
+}
+
+static void
+buffer_demux_port(uint32_t *dma, uint32_t *pcm, uint32_t subset, uint32_t slots,
+ unsigned int pos, unsigned int samples, unsigned int channels)
+{
+ unsigned int slot_offset, width;
+ unsigned int chan_pos;
+
+ /* Translate DMA slot offset to DMA buffer offset. */
+ slot_offset = hdsp_slot_offset(subset);
+ dma += slot_offset * HDSP_CHANBUF_SAMPLES;
+
+ /* Channel position of the slot subset. */
+ chan_pos = hdsp_slot_channel_offset(subset, slots);
+ pcm += chan_pos;
+
+ /* Only copy channels supported by both hardware and pcm format. */
+ width = hdsp_slot_count(subset);
+
+ /* Let the compiler inline and loop unroll common cases. */
+ if (width == 1)
+ buffer_demux_read(dma, pcm, pos, pos + samples, 1, channels);
+ else if (width == 2)
+ buffer_demux_read(dma, pcm, pos, pos + samples, 2, channels);
+ else if (width == 4)
+ buffer_demux_read(dma, pcm, pos, pos + samples, 4, channels);
+ else if (width == 8)
+ buffer_demux_read(dma, pcm, pos, pos + samples, 8, channels);
+ else
+ buffer_demux_read(dma, pcm, pos, pos + samples, width, channels);
+}
+
+
+/* Copy data between DMA and PCM buffers. */
+static void
+buffer_copy(struct sc_chinfo *ch)
+{
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ uint32_t row, slots;
+ uint32_t dma_pos;
+ unsigned int pos, length, remainder, offset, buffer_size;
+ unsigned int channels;
+
+ scp = ch->parent;
+ sc = scp->sc;
+
+ channels = AFMT_CHANNEL(ch->format); /* Number of PCM channels. */
+
+ /* HDSP cards read / write a double buffer, twice the latency period. */
+ buffer_size = 2 * sc->period * sizeof(uint32_t);
+
+ /* Derive buffer position and length to be copied. */
+ if (ch->dir == PCMDIR_PLAY) {
+ /* Buffer position scaled down to a single channel. */
+ pos = sndbuf_getreadyptr(ch->buffer) / channels;
+ length = sndbuf_getready(ch->buffer) / channels;
+ /* Copy no more than 2 periods in advance. */
+ if (length > buffer_size)
+ length = buffer_size;
+ /* Skip what was already copied last time. */
+ offset = (ch->position + buffer_size) - pos;
+ offset %= buffer_size;
+ if (offset <= length) {
+ pos = (pos + offset) % buffer_size;
+ length -= offset;
+ }
+ } else {
+ /* Buffer position scaled down to a single channel. */
+ pos = sndbuf_getfreeptr(ch->buffer) / channels;
+ /* Get DMA buffer write position. */
+ dma_pos = hdsp_read_2(sc, HDSP_STATUS_REG);
+ dma_pos &= HDSP_BUF_POSITION_MASK;
+ dma_pos %= buffer_size;
+ /* Copy what is newly available. */
+ length = (dma_pos + buffer_size) - pos;
+ length %= buffer_size;
+ }
+
+ /* Position and length in samples (4 bytes). */
+ pos /= 4;
+ length /= 4;
+ buffer_size /= sizeof(uint32_t);
+
+ /* Split copy length to wrap around at buffer end. */
+ remainder = 0;
+ if (pos + length > buffer_size)
+ remainder = (pos + length) - buffer_size;
+
+ /* Iterate through rows of contiguous slots. */
+ slots = hdsp_port_slot_map(ch->ports, sc->speed);
+ slots = hdsp_slot_first_n(slots, channels);
+ row = hdsp_slot_first_row(slots);
+
+ while (row != 0) {
+ if (ch->dir == PCMDIR_PLAY) {
+ buffer_mux_port(sc->pbuf, ch->data, row, slots, pos,
+ length - remainder, channels);
+ buffer_mux_port(sc->pbuf, ch->data, row, slots, 0,
+ remainder, channels);
+ } else {
+ buffer_demux_port(sc->rbuf, ch->data, row, slots, pos,
+ length - remainder, channels);
+ buffer_demux_port(sc->rbuf, ch->data, row, slots, 0,
+ remainder, channels);
+ }
+
+ slots &= ~row;
+ row = hdsp_slot_first_row(slots);
+ }
+
+ ch->position = ((pos + length) * 4) % buffer_size;
+}
+
+static int
+clean(struct sc_chinfo *ch)
+{
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ uint32_t *buf;
+ uint32_t slot, slots;
+ unsigned int offset;
+
+ scp = ch->parent;
+ sc = scp->sc;
+ buf = sc->rbuf;
+
+ if (ch->dir == PCMDIR_PLAY)
+ buf = sc->pbuf;
+
+ /* Iterate through all of the channel's slots. */
+ slots = hdsp_port_slot_map(ch->ports, sc->speed);
+ slot = hdsp_slot_first(slots);
+ while (slot != 0) {
+ /* Clear the slot's buffer. */
+ offset = hdsp_slot_offset(slot);
+ bzero(buf + offset * HDSP_CHANBUF_SAMPLES, HDSP_CHANBUF_SIZE);
+
+ slots &= ~slot;
+ slot = hdsp_slot_first(slots);
+ }
+
+ ch->position = 0;
+
+ return (0);
+}
+
+/* Channel interface. */
+static void *
+hdspchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
+ struct pcm_channel *c, int dir)
+{
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+ int num;
+
+ scp = devinfo;
+ sc = scp->sc;
+
+ snd_mtxlock(sc->lock);
+ num = scp->chnum;
+
+ ch = &scp->chan[num];
+
+ if (dir == PCMDIR_PLAY)
+ ch->ports = hdsp_channel_play_ports(scp->hc);
+ else
+ ch->ports = hdsp_channel_rec_ports(scp->hc);
+
+ ch->run = 0;
+ ch->lvol = 0;
+ ch->rvol = 0;
+
+ /* Support all possible ADAT widths as channel formats. */
+ ch->cap_fmts[0] =
+ SND_FORMAT(AFMT_S32_LE, hdsp_port_slot_count(ch->ports, 48000), 0);
+ ch->cap_fmts[1] =
+ SND_FORMAT(AFMT_S32_LE, hdsp_port_slot_count(ch->ports, 96000), 0);
+ ch->cap_fmts[2] =
+ SND_FORMAT(AFMT_S32_LE, hdsp_port_slot_count(ch->ports, 192000), 0);
+ ch->cap_fmts[3] = 0;
+
+ ch->caps = malloc(sizeof(struct pcmchan_caps), M_HDSP, M_NOWAIT);
+ *(ch->caps) = (struct pcmchan_caps) {32000, 192000, ch->cap_fmts, 0};
+
+ /* HDSP 9652 does not support quad speed sample rates. */
+ if (sc->type == HDSP_9652) {
+ ch->cap_fmts[2] = SND_FORMAT(AFMT_S32_LE, 2, 0);
+ ch->caps->maxspeed = 96000;
+ }
+
+ /* Allocate maximum buffer size. */
+ ch->size = HDSP_CHANBUF_SIZE * hdsp_port_slot_count_max(ch->ports);
+ ch->data = malloc(ch->size, M_HDSP, M_NOWAIT);
+ ch->position = 0;
+
+ ch->buffer = b;
+ ch->channel = c;
+ ch->parent = scp;
+
+ ch->dir = dir;
+
+ snd_mtxunlock(sc->lock);
+
+ if (sndbuf_setup(ch->buffer, ch->data, ch->size) != 0) {
+ device_printf(scp->dev, "Can't setup sndbuf.\n");
+ return (NULL);
+ }
+
+ return (ch);
+}
+
+static int
+hdspchan_trigger(kobj_t obj, void *data, int go)
+{
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+
+ ch = data;
+ scp = ch->parent;
+ sc = scp->sc;
+
+ snd_mtxlock(sc->lock);
+ switch (go) {
+ case PCMTRIG_START:
+#if 0
+ device_printf(scp->dev, "hdspchan_trigger(): start\n");
+#endif
+ hdspchan_enable(ch, 1);
+ hdspchan_setgain(ch);
+ hdsp_start_audio(sc);
+ break;
+
+ case PCMTRIG_STOP:
+ case PCMTRIG_ABORT:
+#if 0
+ device_printf(scp->dev, "hdspchan_trigger(): stop or abort\n");
+#endif
+ clean(ch);
+ hdspchan_enable(ch, 0);
+ hdsp_stop_audio(sc);
+ break;
+
+ case PCMTRIG_EMLDMAWR:
+ case PCMTRIG_EMLDMARD:
+ if(ch->run)
+ buffer_copy(ch);
+ break;
+ }
+
+ snd_mtxunlock(sc->lock);
+
+ return (0);
+}
+
+static uint32_t
+hdspchan_getptr(kobj_t obj, void *data)
+{
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+ uint32_t ret, pos;
+
+ ch = data;
+ scp = ch->parent;
+ sc = scp->sc;
+
+ snd_mtxlock(sc->lock);
+ ret = hdsp_read_2(sc, HDSP_STATUS_REG);
+ snd_mtxunlock(sc->lock);
+
+ pos = ret & HDSP_BUF_POSITION_MASK;
+ pos %= (2 * sc->period * sizeof(uint32_t)); /* Double buffer. */
+ pos *= AFMT_CHANNEL(ch->format); /* Hardbuf with multiple channels. */
+
+ return (pos);
+}
+
+static int
+hdspchan_free(kobj_t obj, void *data)
+{
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+
+ ch = data;
+ scp = ch->parent;
+ sc = scp->sc;
+
+#if 0
+ device_printf(scp->dev, "hdspchan_free()\n");
+#endif
+
+ snd_mtxlock(sc->lock);
+ if (ch->data != NULL) {
+ free(ch->data, M_HDSP);
+ ch->data = NULL;
+ }
+ if (ch->caps != NULL) {
+ free(ch->caps, M_HDSP);
+ ch->caps = NULL;
+ }
+ snd_mtxunlock(sc->lock);
+
+ return (0);
+}
+
+static int
+hdspchan_setformat(kobj_t obj, void *data, uint32_t format)
+{
+ struct sc_chinfo *ch;
+
+ ch = data;
+
+#if 0
+ struct sc_pcminfo *scp = ch->parent;
+ device_printf(scp->dev, "hdspchan_setformat(%d)\n", format);
+#endif
+
+ ch->format = format;
+
+ return (0);
+}
+
+static uint32_t
+hdspchan_setspeed(kobj_t obj, void *data, uint32_t speed)
+{
+ struct sc_pcminfo *scp;
+ struct hdsp_rate *hr;
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+ int threshold;
+ int i;
+
+ ch = data;
+ scp = ch->parent;
+ sc = scp->sc;
+ hr = NULL;
+
+#if 0
+ device_printf(scp->dev, "hdspchan_setspeed(%d)\n", speed);
+#endif
+
+ if (hdsp_running(sc) == 1)
+ goto end;
+
+ /* HDSP 9652 only supports sample rates up to 96kHz. */
+ if (sc->type == HDSP_9652 && speed > 96000)
+ speed = 96000;
+
+ if (sc->force_speed > 0)
+ speed = sc->force_speed;
+
+ /* First look for equal frequency. */
+ for (i = 0; rate_map[i].speed != 0; i++) {
+ if (rate_map[i].speed == speed)
+ hr = &rate_map[i];
+ }
+
+ /* If no match, just find nearest. */
+ if (hr == NULL) {
+ for (i = 0; rate_map[i].speed != 0; i++) {
+ hr = &rate_map[i];
+ threshold = hr->speed + ((rate_map[i + 1].speed != 0) ?
+ ((rate_map[i + 1].speed - hr->speed) >> 1) : 0);
+ if (speed < threshold)
+ break;
+ }
+ }
+
+ /* Write frequency on the device. */
+ sc->ctrl_register &= ~HDSP_FREQ_MASK;
+ sc->ctrl_register |= hr->reg;
+ hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
+
+ if (sc->type == HDSP_9632) {
+ /* Set DDS value. */
+ hdsp_write_4(sc, HDSP_FREQ_REG, hdsp_freq_reg_value(hr->speed));
+ }
+
+ sc->speed = hr->speed;
+end:
+
+ return (sc->speed);
+}
+
+static uint32_t
+hdspchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
+{
+ struct hdsp_latency *hl;
+ struct sc_pcminfo *scp;
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+ int threshold;
+ int i;
+
+ ch = data;
+ scp = ch->parent;
+ sc = scp->sc;
+ hl = NULL;
+
+#if 0
+ device_printf(scp->dev, "hdspchan_setblocksize(%d)\n", blocksize);
+#endif
+
+ if (hdsp_running(sc) == 1)
+ goto end;
+
+ if (blocksize > HDSP_LAT_BYTES_MAX)
+ blocksize = HDSP_LAT_BYTES_MAX;
+ else if (blocksize < HDSP_LAT_BYTES_MIN)
+ blocksize = HDSP_LAT_BYTES_MIN;
+
+ blocksize /= 4 /* samples */;
+
+ if (sc->force_period > 0)
+ blocksize = sc->force_period;
+
+ /* First look for equal latency. */
+ for (i = 0; latency_map[i].period != 0; i++) {
+ if (latency_map[i].period == blocksize)
+ hl = &latency_map[i];
+ }
+
+ /* If no match, just find nearest. */
+ if (hl == NULL) {
+ for (i = 0; latency_map[i].period != 0; i++) {
+ hl = &latency_map[i];
+ threshold = hl->period + ((latency_map[i + 1].period != 0) ?
+ ((latency_map[i + 1].period - hl->period) >> 1) : 0);
+ if (blocksize < threshold)
+ break;
+ }
+ }
+
+ snd_mtxlock(sc->lock);
+ sc->ctrl_register &= ~HDSP_LAT_MASK;
+ sc->ctrl_register |= hdsp_encode_latency(hl->n);
+ hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
+ sc->period = hl->period;
+ snd_mtxunlock(sc->lock);
+
+#if 0
+ device_printf(scp->dev, "New period=%d\n", sc->period);
+#endif
+
+ sndbuf_resize(ch->buffer, 2,
+ (sc->period * AFMT_CHANNEL(ch->format) * sizeof(uint32_t)));
+
+ /* Reset pointer, rewrite frequency (same register) for 9632. */
+ hdsp_write_4(sc, HDSP_RESET_POINTER, 0);
+ if (sc->type == HDSP_9632)
+ hdsp_write_4(sc, HDSP_FREQ_REG, hdsp_freq_reg_value(sc->speed));
+end:
+
+ return (sndbuf_getblksz(ch->buffer));
+}
+
+static uint32_t hdsp_bkp_fmt[] = {
+ SND_FORMAT(AFMT_S32_LE, 2, 0),
+ 0
+};
+
+/* Capabilities fallback, no quad speed for HDSP 9652 compatibility. */
+static struct pcmchan_caps hdsp_bkp_caps = {32000, 96000, hdsp_bkp_fmt, 0};
+
+static struct pcmchan_caps *
+hdspchan_getcaps(kobj_t obj, void *data)
+{
+ struct sc_chinfo *ch;
+
+ ch = data;
+
+#if 0
+ device_printf(ch->parent->dev, "hdspchan_getcaps()\n");
+#endif
+
+ if (ch->caps != NULL)
+ return (ch->caps);
+
+ return (&hdsp_bkp_caps);
+}
+
+static kobj_method_t hdspchan_methods[] = {
+ KOBJMETHOD(channel_init, hdspchan_init),
+ KOBJMETHOD(channel_free, hdspchan_free),
+ KOBJMETHOD(channel_setformat, hdspchan_setformat),
+ KOBJMETHOD(channel_setspeed, hdspchan_setspeed),
+ KOBJMETHOD(channel_setblocksize, hdspchan_setblocksize),
+ KOBJMETHOD(channel_trigger, hdspchan_trigger),
+ KOBJMETHOD(channel_getptr, hdspchan_getptr),
+ KOBJMETHOD(channel_getcaps, hdspchan_getcaps),
+ KOBJMETHOD_END
+};
+CHANNEL_DECLARE(hdspchan);
+
+static int
+hdsp_pcm_probe(device_t dev)
+{
+
+#if 0
+ device_printf(dev,"hdsp_pcm_probe()\n");
+#endif
+
+ return (0);
+}
+
+static uint32_t
+hdsp_pcm_intr(struct sc_pcminfo *scp)
+{
+ struct sc_chinfo *ch;
+ struct sc_info *sc;
+ int i;
+
+ sc = scp->sc;
+
+ for (i = 0; i < scp->chnum; i++) {
+ ch = &scp->chan[i];
+ snd_mtxunlock(sc->lock);
+ chn_intr(ch->channel);
+ snd_mtxlock(sc->lock);
+ }
+
+ return (0);
+}
+
+static int
+hdsp_pcm_attach(device_t dev)
+{
+ char status[SND_STATUSLEN];
+ struct sc_pcminfo *scp;
+ const char *buf;
+ uint32_t pcm_flags;
+ int err;
+ int play, rec;
+
+ scp = device_get_ivars(dev);
+ scp->ih = &hdsp_pcm_intr;
+
+ if (scp->hc->ports & HDSP_CHAN_9632_ALL)
+ buf = "9632";
+ else if (scp->hc->ports & HDSP_CHAN_9652_ALL)
+ buf = "9652";
+ else
+ buf = "?";
+ device_set_descf(dev, "HDSP %s [%s]", buf, scp->hc->descr);
+
+ /*
+ * We don't register interrupt handler with snd_setup_intr
+ * in pcm device. Mark pcm device as MPSAFE manually.
+ */
+ pcm_flags = pcm_getflags(dev) | SD_F_MPSAFE;
+ if (hdsp_port_slot_count_max(scp->hc->ports) > HDSP_MATRIX_MAX)
+ /* Disable vchan conversion, too many channels. */
+ pcm_flags |= SD_F_BITPERFECT;
+ pcm_setflags(dev, pcm_flags);
+
+ play = (hdsp_channel_play_ports(scp->hc)) ? 1 : 0;
+ rec = (hdsp_channel_rec_ports(scp->hc)) ? 1 : 0;
+ err = pcm_register(dev, scp, play, rec);
+ if (err) {
+ device_printf(dev, "Can't register pcm.\n");
+ return (ENXIO);
+ }
+
+ scp->chnum = 0;
+ if (play) {
+ pcm_addchan(dev, PCMDIR_PLAY, &hdspchan_class, scp);
+ scp->chnum++;
+ }
+
+ if (rec) {
+ pcm_addchan(dev, PCMDIR_REC, &hdspchan_class, scp);
+ scp->chnum++;
+ }
+
+ snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s",
+ rman_get_start(scp->sc->cs),
+ rman_get_start(scp->sc->irq),
+ device_get_nameunit(device_get_parent(dev)));
+ pcm_setstatus(dev, status);
+
+ mixer_init(dev, &hdspmixer_class, scp);
+
+ return (0);
+}
+
+static int
+hdsp_pcm_detach(device_t dev)
+{
+ int err;
+
+ err = pcm_unregister(dev);
+ if (err) {
+ device_printf(dev, "Can't unregister device.\n");
+ return (err);
+ }
+
+ return (0);
+}
+
+static device_method_t hdsp_pcm_methods[] = {
+ DEVMETHOD(device_probe, hdsp_pcm_probe),
+ DEVMETHOD(device_attach, hdsp_pcm_attach),
+ DEVMETHOD(device_detach, hdsp_pcm_detach),
+ { 0, 0 }
+};
+
+static driver_t hdsp_pcm_driver = {
+ "pcm",
+ hdsp_pcm_methods,
+ PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(snd_hdsp_pcm, hdsp, hdsp_pcm_driver, 0, 0);
+MODULE_DEPEND(snd_hdsp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
+MODULE_VERSION(snd_hdsp, 1);
diff --git a/sys/dev/sound/pci/hdsp.c b/sys/dev/sound/pci/hdsp.c
new file mode 100644
index 000000000000..769615cb1f4b
--- /dev/null
+++ b/sys/dev/sound/pci/hdsp.c
@@ -0,0 +1,793 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2012-2016 Ruslan Bukin
+ * Copyright (c) 2023-2024 Florian Walpen
+ * 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.
+ */
+
+/*
+ * RME HDSP driver for FreeBSD.
+ * Supported cards: HDSP 9632, HDSP 9652.
+ */
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+static bool hdsp_unified_pcm = false;
+
+static SYSCTL_NODE(_hw, OID_AUTO, hdsp, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "PCI HDSP");
+
+SYSCTL_BOOL(_hw_hdsp, OID_AUTO, unified_pcm, CTLFLAG_RWTUN,
+ &hdsp_unified_pcm, 0, "Combine physical ports in one unified pcm device");
+
+static struct hdsp_clock_source hdsp_clock_source_table_9632[] = {
+ { "internal", HDSP_CLOCK_INTERNAL },
+ { "adat", HDSP_CLOCK_ADAT1 },
+ { "spdif", HDSP_CLOCK_SPDIF },
+ { "word", HDSP_CLOCK_WORD },
+ { NULL, HDSP_CLOCK_INTERNAL }
+};
+
+static struct hdsp_clock_source hdsp_clock_source_table_9652[] = {
+ { "internal", HDSP_CLOCK_INTERNAL },
+ { "adat1", HDSP_CLOCK_ADAT1 },
+ { "adat2", HDSP_CLOCK_ADAT2 },
+ { "adat3", HDSP_CLOCK_ADAT3 },
+ { "spdif", HDSP_CLOCK_SPDIF },
+ { "word", HDSP_CLOCK_WORD },
+ { "adat_sync", HDSP_CLOCK_ADAT_SYNC },
+ { NULL, HDSP_CLOCK_INTERNAL }
+};
+
+static struct hdsp_channel chan_map_9632[] = {
+ { HDSP_CHAN_9632_ADAT, "adat" },
+ { HDSP_CHAN_9632_SPDIF, "s/pdif" },
+ { HDSP_CHAN_9632_LINE, "line" },
+ { 0, NULL },
+};
+
+static struct hdsp_channel chan_map_9632_uni[] = {
+ { HDSP_CHAN_9632_ALL, "all" },
+ { 0, NULL },
+};
+
+static struct hdsp_channel chan_map_9652[] = {
+ { HDSP_CHAN_9652_ADAT1, "adat1" },
+ { HDSP_CHAN_9652_ADAT2, "adat2" },
+ { HDSP_CHAN_9652_ADAT3, "adat3" },
+ { HDSP_CHAN_9652_SPDIF, "s/pdif" },
+ { 0, NULL },
+};
+
+static struct hdsp_channel chan_map_9652_uni[] = {
+ { HDSP_CHAN_9652_ALL, "all" },
+ { 0, NULL },
+};
+
+static void
+hdsp_intr(void *p)
+{
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ device_t *devlist;
+ int devcount;
+ int status;
+ int err;
+ int i;
+
+ sc = (struct sc_info *)p;
+
+ snd_mtxlock(sc->lock);
+
+ status = hdsp_read_1(sc, HDSP_STATUS_REG);
+ if (status & HDSP_AUDIO_IRQ_PENDING) {
+ if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
+ return;
+
+ for (i = 0; i < devcount; i++) {
+ scp = device_get_ivars(devlist[i]);
+ if (scp->ih != NULL)
+ scp->ih(scp);
+ }
+
+ hdsp_write_1(sc, HDSP_INTERRUPT_ACK, 0);
+ free(devlist, M_TEMP);
+ }
+
+ snd_mtxunlock(sc->lock);
+}
+
+static void
+hdsp_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+#if 0
+ device_printf(sc->dev, "hdsp_dmapsetmap()\n");
+#endif
+}
+
+static int
+hdsp_alloc_resources(struct sc_info *sc)
+{
+
+ /* Allocate resource. */
+ sc->csid = PCIR_BAR(0);
+ sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
+ &sc->csid, RF_ACTIVE);
+
+ if (!sc->cs) {
+ device_printf(sc->dev, "Unable to map SYS_RES_MEMORY.\n");
+ return (ENXIO);
+ }
+
+ sc->cst = rman_get_bustag(sc->cs);
+ sc->csh = rman_get_bushandle(sc->cs);
+
+ /* Allocate interrupt resource. */
+ sc->irqid = 0;
+ sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ if (!sc->irq ||
+ bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV,
+ NULL, hdsp_intr, sc, &sc->ih)) {
+ device_printf(sc->dev, "Unable to alloc interrupt resource.\n");
+ return (ENXIO);
+ }
+
+ /* Allocate DMA resources. */
+ if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
+ /*alignment*/4,
+ /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL,
+ /*filterarg*/NULL,
+ /*maxsize*/2 * HDSP_DMASEGSIZE,
+ /*nsegments*/2,
+ /*maxsegsz*/HDSP_DMASEGSIZE,
+ /*flags*/0,
+ /*lockfunc*/NULL,
+ /*lockarg*/NULL,
+ /*dmatag*/&sc->dmat) != 0) {
+ device_printf(sc->dev, "Unable to create dma tag.\n");
+ return (ENXIO);
+ }
+
+ sc->bufsize = HDSP_DMASEGSIZE;
+
+ /* pbuf (play buffer). */
+ if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_WAITOK,
+ &sc->pmap)) {
+ device_printf(sc->dev, "Can't alloc pbuf.\n");
+ return (ENXIO);
+ }
+
+ if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize,
+ hdsp_dmapsetmap, sc, BUS_DMA_NOWAIT)) {
+ device_printf(sc->dev, "Can't load pbuf.\n");
+ return (ENXIO);
+ }
+
+ /* rbuf (rec buffer). */
+ if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_WAITOK,
+ &sc->rmap)) {
+ device_printf(sc->dev, "Can't alloc rbuf.\n");
+ return (ENXIO);
+ }
+
+ if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize,
+ hdsp_dmapsetmap, sc, BUS_DMA_NOWAIT)) {
+ device_printf(sc->dev, "Can't load rbuf.\n");
+ return (ENXIO);
+ }
+
+ bzero(sc->pbuf, sc->bufsize);
+ bzero(sc->rbuf, sc->bufsize);
+
+ return (0);
+}
+
+static void
+hdsp_map_dmabuf(struct sc_info *sc)
+{
+ uint32_t paddr, raddr;
+
+ paddr = vtophys(sc->pbuf);
+ raddr = vtophys(sc->rbuf);
+
+ hdsp_write_4(sc, HDSP_PAGE_ADDR_BUF_OUT, paddr);
+ hdsp_write_4(sc, HDSP_PAGE_ADDR_BUF_IN, raddr);
+}
+
+static int
+hdsp_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc = oidp->oid_arg1;
+ int error;
+ unsigned int speed, multiplier;
+
+ speed = sc->force_speed;
+
+ /* Process sysctl (unsigned) integer request. */
+ error = sysctl_handle_int(oidp, &speed, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Speed from 32000 to 192000, 0 falls back to pcm speed setting. */
+ sc->force_speed = 0;
+ if (speed > 0) {
+ multiplier = 1;
+ if ((speed > (96000 + 128000) / 2) && sc->type == HDSP_9632)
+ multiplier = 4;
+ else if (speed > (48000 + 64000) / 2)
+ multiplier = 2;
+
+ if (speed < ((32000 + 44100) / 2) * multiplier)
+ sc->force_speed = 32000 * multiplier;
+ else if (speed < ((44100 + 48000) / 2) * multiplier)
+ sc->force_speed = 44100 * multiplier;
+ else
+ sc->force_speed = 48000 * multiplier;
+ }
+
+ return (0);
+}
+
+
+static int
+hdsp_sysctl_period(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc = oidp->oid_arg1;
+ int error;
+ unsigned int period;
+
+ period = sc->force_period;
+
+ /* Process sysctl (unsigned) integer request. */
+ error = sysctl_handle_int(oidp, &period, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Period is from 2^5 to 2^14, 0 falls back to pcm latency settings. */
+ sc->force_period = 0;
+ if (period > 0) {
+ sc->force_period = 32;
+ while (sc->force_period < period && sc->force_period < 4096)
+ sc->force_period <<= 1;
+ }
+
+ return (0);
+}
+
+static uint32_t
+hdsp_control_clock_preference(enum hdsp_clock_type type)
+{
+ switch (type) {
+ case HDSP_CLOCK_INTERNAL:
+ return (HDSP_CONTROL_MASTER);
+ case HDSP_CLOCK_ADAT1:
+ return (HDSP_CONTROL_CLOCK(0));
+ case HDSP_CLOCK_ADAT2:
+ return (HDSP_CONTROL_CLOCK(1));
+ case HDSP_CLOCK_ADAT3:
+ return (HDSP_CONTROL_CLOCK(2));
+ case HDSP_CLOCK_SPDIF:
+ return (HDSP_CONTROL_CLOCK(3));
+ case HDSP_CLOCK_WORD:
+ return (HDSP_CONTROL_CLOCK(4));
+ case HDSP_CLOCK_ADAT_SYNC:
+ return (HDSP_CONTROL_CLOCK(5));
+ default:
+ return (HDSP_CONTROL_MASTER);
+ }
+}
+
+static int
+hdsp_sysctl_clock_preference(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdsp_clock_source *clock_table, *clock;
+ char buf[16] = "invalid";
+ int error;
+ uint32_t control;
+
+ sc = oidp->oid_arg1;
+
+ /* Select sync ports table for device type. */
+ if (sc->type == HDSP_9632)
+ clock_table = hdsp_clock_source_table_9632;
+ else if (sc->type == HDSP_9652)
+ clock_table = hdsp_clock_source_table_9652;
+ else
+ return (ENXIO);
+
+ /* Extract preferred clock source from control register. */
+ control = sc->ctrl_register & HDSP_CONTROL_CLOCK_MASK;
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (hdsp_control_clock_preference(clock->type) == control)
+ break;
+ }
+ if (clock->name != NULL)
+ strlcpy(buf, clock->name, sizeof(buf));
+
+ /* Process sysctl string request. */
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Find clock source matching the sysctl string. */
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (strncasecmp(buf, clock->name, sizeof(buf)) == 0)
+ break;
+ }
+
+ /* Set preferred clock source in control register. */
+ if (clock->name != NULL) {
+ control = hdsp_control_clock_preference(clock->type);
+ control &= HDSP_CONTROL_CLOCK_MASK;
+ snd_mtxlock(sc->lock);
+ sc->ctrl_register &= ~HDSP_CONTROL_CLOCK_MASK;
+ sc->ctrl_register |= control;
+ hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
+ snd_mtxunlock(sc->lock);
+ }
+ return (0);
+}
+
+static uint32_t
+hdsp_status2_clock_source(enum hdsp_clock_type type)
+{
+ switch (type) {
+ case HDSP_CLOCK_INTERNAL:
+ return (0);
+ case HDSP_CLOCK_ADAT1:
+ return (HDSP_STATUS2_CLOCK(0));
+ case HDSP_CLOCK_ADAT2:
+ return (HDSP_STATUS2_CLOCK(1));
+ case HDSP_CLOCK_ADAT3:
+ return (HDSP_STATUS2_CLOCK(2));
+ case HDSP_CLOCK_SPDIF:
+ return (HDSP_STATUS2_CLOCK(3));
+ case HDSP_CLOCK_WORD:
+ return (HDSP_STATUS2_CLOCK(4));
+ case HDSP_CLOCK_ADAT_SYNC:
+ return (HDSP_STATUS2_CLOCK(5));
+ default:
+ return (0);
+ }
+}
+
+static int
+hdsp_sysctl_clock_source(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdsp_clock_source *clock_table, *clock;
+ char buf[16] = "invalid";
+ uint32_t status2;
+
+ sc = oidp->oid_arg1;
+
+ /* Select sync ports table for device type. */
+ if (sc->type == HDSP_9632)
+ clock_table = hdsp_clock_source_table_9632;
+ else if (sc->type == HDSP_9652)
+ clock_table = hdsp_clock_source_table_9652;
+ else
+ return (ENXIO);
+
+ /* Read current (autosync) clock source from status2 register. */
+ snd_mtxlock(sc->lock);
+ status2 = hdsp_read_4(sc, HDSP_STATUS2_REG);
+ status2 &= HDSP_STATUS2_CLOCK_MASK;
+ snd_mtxunlock(sc->lock);
+
+ /* Translate status2 register value to clock source. */
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ /* In clock master mode, override with internal clock source. */
+ if (sc->ctrl_register & HDSP_CONTROL_MASTER) {
+ if (clock->type == HDSP_CLOCK_INTERNAL)
+ break;
+ } else if (hdsp_status2_clock_source(clock->type) == status2)
+ break;
+ }
+
+ /* Process sysctl string request. */
+ if (clock->name != NULL)
+ strlcpy(buf, clock->name, sizeof(buf));
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static int
+hdsp_sysctl_clock_list(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdsp_clock_source *clock_table, *clock;
+ char buf[256];
+ int n;
+
+ sc = oidp->oid_arg1;
+ n = 0;
+
+ /* Select clock source table for device type. */
+ if (sc->type == HDSP_9632)
+ clock_table = hdsp_clock_source_table_9632;
+ else if (sc->type == HDSP_9652)
+ clock_table = hdsp_clock_source_table_9652;
+ else
+ return (ENXIO);
+
+ /* List available clock sources. */
+ buf[0] = 0;
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (n > 0)
+ n += strlcpy(buf + n, ",", sizeof(buf) - n);
+ n += strlcpy(buf + n, clock->name, sizeof(buf) - n);
+ }
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static bool
+hdsp_clock_source_locked(enum hdsp_clock_type type, uint32_t status,
+ uint32_t status2)
+{
+ switch (type) {
+ case HDSP_CLOCK_INTERNAL:
+ return (true);
+ case HDSP_CLOCK_ADAT1:
+ return ((status >> 3) & 0x01);
+ case HDSP_CLOCK_ADAT2:
+ return ((status >> 2) & 0x01);
+ case HDSP_CLOCK_ADAT3:
+ return ((status >> 1) & 0x01);
+ case HDSP_CLOCK_SPDIF:
+ return (!((status >> 25) & 0x01));
+ case HDSP_CLOCK_WORD:
+ return ((status2 >> 3) & 0x01);
+ case HDSP_CLOCK_ADAT_SYNC:
+ return ((status >> 5) & 0x01);
+ default:
+ return (false);
+ }
+}
+
+static bool
+hdsp_clock_source_synced(enum hdsp_clock_type type, uint32_t status,
+ uint32_t status2)
+{
+ switch (type) {
+ case HDSP_CLOCK_INTERNAL:
+ return (true);
+ case HDSP_CLOCK_ADAT1:
+ return ((status >> 18) & 0x01);
+ case HDSP_CLOCK_ADAT2:
+ return ((status >> 17) & 0x01);
+ case HDSP_CLOCK_ADAT3:
+ return ((status >> 16) & 0x01);
+ case HDSP_CLOCK_SPDIF:
+ return (((status >> 4) & 0x01) && !((status >> 25) & 0x01));
+ case HDSP_CLOCK_WORD:
+ return ((status2 >> 4) & 0x01);
+ case HDSP_CLOCK_ADAT_SYNC:
+ return ((status >> 27) & 0x01);
+ default:
+ return (false);
+ }
+}
+
+static int
+hdsp_sysctl_sync_status(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdsp_clock_source *clock_table, *clock;
+ char buf[256];
+ char *state;
+ int n;
+ uint32_t status, status2;
+
+ sc = oidp->oid_arg1;
+ n = 0;
+
+ /* Select sync ports table for device type. */
+ if (sc->type == HDSP_9632)
+ clock_table = hdsp_clock_source_table_9632;
+ else if (sc->type == HDSP_9652)
+ clock_table = hdsp_clock_source_table_9652;
+ else
+ return (ENXIO);
+
+ /* Read current lock and sync bits from status registers. */
+ snd_mtxlock(sc->lock);
+ status = hdsp_read_4(sc, HDSP_STATUS_REG);
+ status2 = hdsp_read_4(sc, HDSP_STATUS2_REG);
+ snd_mtxunlock(sc->lock);
+
+ /* List clock sources with lock and sync state. */
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (clock->type == HDSP_CLOCK_INTERNAL)
+ continue;
+ if (n > 0)
+ n += strlcpy(buf + n, ",", sizeof(buf) - n);
+ state = "none";
+ if (hdsp_clock_source_locked(clock->type, status, status2)) {
+ if (hdsp_clock_source_synced(clock->type, status,
+ status2))
+ state = "sync";
+ else
+ state = "lock";
+ }
+ n += snprintf(buf + n, sizeof(buf) - n, "%s(%s)",
+ clock->name, state);
+ }
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static int
+hdsp_probe(device_t dev)
+{
+ uint32_t rev;
+
+ if (pci_get_vendor(dev) == PCI_VENDOR_XILINX &&
+ pci_get_device(dev) == PCI_DEVICE_XILINX_HDSP) {
+ rev = pci_get_revid(dev);
+ switch (rev) {
+ case PCI_REVISION_9632:
+ device_set_desc(dev, "RME HDSP 9632");
+ return (0);
+ case PCI_REVISION_9652:
+ device_set_desc(dev, "RME HDSP 9652");
+ return (0);
+ }
+ }
+
+ return (ENXIO);
+}
+
+static int
+hdsp_init(struct sc_info *sc)
+{
+ unsigned mixer_controls;
+
+ /* Set latency. */
+ sc->period = 256;
+ /*
+ * The pcm channel latency settings propagate unreliable blocksizes,
+ * different for recording and playback, and skewed due to rounding
+ * and total buffer size limits.
+ * Force period to a consistent default until these issues are fixed.
+ */
+ sc->force_period = 256;
+ sc->ctrl_register = hdsp_encode_latency(2);
+
+ /* Set rate. */
+ sc->speed = HDSP_SPEED_DEFAULT;
+ sc->force_speed = 0;
+ sc->ctrl_register &= ~HDSP_FREQ_MASK;
+ sc->ctrl_register |= HDSP_FREQ_MASK_DEFAULT;
+
+ /* Set internal clock source (master). */
+ sc->ctrl_register &= ~HDSP_CONTROL_CLOCK_MASK;
+ sc->ctrl_register |= HDSP_CONTROL_MASTER;
+
+ /* SPDIF from coax in, line out. */
+ sc->ctrl_register &= ~HDSP_CONTROL_SPDIF_COAX;
+ sc->ctrl_register |= HDSP_CONTROL_SPDIF_COAX;
+ sc->ctrl_register &= ~HDSP_CONTROL_LINE_OUT;
+ sc->ctrl_register |= HDSP_CONTROL_LINE_OUT;
+
+ hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
+
+ if (sc->type == HDSP_9652)
+ hdsp_write_4(sc, HDSP_CONTROL2_REG, HDSP_CONTROL2_9652_MIXER);
+ else
+ hdsp_write_4(sc, HDSP_CONTROL2_REG, 0);
+
+ switch (sc->type) {
+ case HDSP_9632:
+ /* Mixer matrix is 2 source rows (input, playback) per output. */
+ mixer_controls = 2 * HDSP_MIX_SLOTS_9632 * HDSP_MIX_SLOTS_9632;
+ break;
+ case HDSP_9652:
+ /* Mixer matrix is 2 source rows (input, playback) per output. */
+ mixer_controls = 2 * HDSP_MIX_SLOTS_9652 * HDSP_MIX_SLOTS_9652;
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ /* Initialize mixer matrix by silencing all controls. */
+ for (unsigned offset = 0; offset < mixer_controls * 2; offset += 4) {
+ /* Only accepts 4 byte values, pairs of 16 bit volume controls. */
+ hdsp_write_4(sc, HDSP_MIXER_BASE + offset,
+ (HDSP_MIN_GAIN << 16) | HDSP_MIN_GAIN);
+ }
+
+ /* Reset pointer, rewrite frequency (same register) for 9632. */
+ hdsp_write_4(sc, HDSP_RESET_POINTER, 0);
+ if (sc->type == HDSP_9632) {
+ /* Set DDS value. */
+ hdsp_write_4(sc, HDSP_FREQ_REG, hdsp_freq_reg_value(sc->speed));
+ }
+
+ return (0);
+}
+
+static int
+hdsp_attach(device_t dev)
+{
+ struct hdsp_channel *chan_map;
+ struct sc_pcminfo *scp;
+ struct sc_info *sc;
+ uint32_t rev;
+ int i, err;
+
+#if 0
+ device_printf(dev, "hdsp_attach()\n");
+#endif
+
+ sc = device_get_softc(dev);
+ sc->lock = snd_mtxcreate(device_get_nameunit(dev),
+ "snd_hdsp softc");
+ sc->dev = dev;
+
+ pci_enable_busmaster(dev);
+ rev = pci_get_revid(dev);
+ switch (rev) {
+ case PCI_REVISION_9632:
+ sc->type = HDSP_9632;
+ chan_map = hdsp_unified_pcm ? chan_map_9632_uni : chan_map_9632;
+ break;
+ case PCI_REVISION_9652:
+ sc->type = HDSP_9652;
+ chan_map = hdsp_unified_pcm ? chan_map_9652_uni : chan_map_9652;
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ /* Allocate resources. */
+ err = hdsp_alloc_resources(sc);
+ if (err) {
+ device_printf(dev, "Unable to allocate system resources.\n");
+ return (ENXIO);
+ }
+
+ if (hdsp_init(sc) != 0)
+ return (ENXIO);
+
+ for (i = 0; i < HDSP_MAX_CHANS && chan_map[i].descr != NULL; i++) {
+ scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
+ scp->hc = &chan_map[i];
+ scp->sc = sc;
+ scp->dev = device_add_child(dev, "pcm", -1);
+ device_set_ivars(scp->dev, scp);
+ }
+
+ hdsp_map_dmabuf(sc);
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "sync_status", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, hdsp_sysctl_sync_status, "A",
+ "List clock source signal lock and sync status");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "clock_source", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, hdsp_sysctl_clock_source, "A",
+ "Currently effective clock source");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "clock_preference", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdsp_sysctl_clock_preference, "A",
+ "Set 'internal' (master) or preferred autosync clock source");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "clock_list", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, hdsp_sysctl_clock_list, "A",
+ "List of supported clock sources");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdsp_sysctl_period, "A",
+ "Force period of samples per interrupt (32, 64, ... 4096)");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "sample_rate", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdsp_sysctl_sample_rate, "A",
+ "Force sample rate (32000, 44100, 48000, ... 192000)");
+
+ return (bus_generic_attach(dev));
+}
+
+static void
+hdsp_dmafree(struct sc_info *sc)
+{
+
+ bus_dmamap_unload(sc->dmat, sc->rmap);
+ bus_dmamap_unload(sc->dmat, sc->pmap);
+ bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
+ bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
+ sc->rbuf = sc->pbuf = NULL;
+}
+
+static int
+hdsp_detach(device_t dev)
+{
+ struct sc_info *sc;
+ int err;
+
+ sc = device_get_softc(dev);
+ if (sc == NULL) {
+ device_printf(dev,"Can't detach: softc is null.\n");
+ return (0);
+ }
+
+ err = device_delete_children(dev);
+ if (err)
+ return (err);
+
+ hdsp_dmafree(sc);
+
+ if (sc->ih)
+ bus_teardown_intr(dev, sc->irq, sc->ih);
+ if (sc->dmat)
+ bus_dma_tag_destroy(sc->dmat);
+ if (sc->irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+ if (sc->cs)
+ bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs);
+ if (sc->lock)
+ snd_mtxfree(sc->lock);
+
+ return (0);
+}
+
+static device_method_t hdsp_methods[] = {
+ DEVMETHOD(device_probe, hdsp_probe),
+ DEVMETHOD(device_attach, hdsp_attach),
+ DEVMETHOD(device_detach, hdsp_detach),
+ { 0, 0 }
+};
+
+static driver_t hdsp_driver = {
+ "hdsp",
+ hdsp_methods,
+ PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(snd_hdsp, pci, hdsp_driver, 0, 0);
diff --git a/sys/dev/sound/pci/hdsp.h b/sys/dev/sound/pci/hdsp.h
new file mode 100644
index 000000000000..5ff622892c52
--- /dev/null
+++ b/sys/dev/sound/pci/hdsp.h
@@ -0,0 +1,257 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2012-2016 Ruslan Bukin
+ * Copyright (c) 2023-2024 Florian Walpen
+ * 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.
+ */
+
+#define PCI_VENDOR_XILINX 0x10ee
+#define PCI_DEVICE_XILINX_HDSP 0x3fc5 /* HDSP 9652 */
+#define PCI_REVISION_9632 0x9b
+#define PCI_REVISION_9652 0x6c
+
+#define HDSP_9632 0
+#define HDSP_9652 1
+
+/* Hardware mixer */
+#define HDSP_OUT_ENABLE_BASE 128
+#define HDSP_IN_ENABLE_BASE 384
+#define HDSP_MIXER_BASE 4096
+#define HDSP_MAX_GAIN 32768
+#define HDSP_MIN_GAIN 0
+#define HDSP_MIX_SLOTS_9632 16
+#define HDSP_MIX_SLOTS_9652 26
+#define HDSP_CONTROL2_9652_MIXER (1 << 11)
+
+/* Buffer */
+#define HDSP_PAGE_ADDR_BUF_OUT 32
+#define HDSP_PAGE_ADDR_BUF_IN 36
+#define HDSP_BUF_POSITION_MASK 0x000FFC0
+
+/* Frequency */
+#define HDSP_FREQ_0 (1 << 6)
+#define HDSP_FREQ_1 (1 << 7)
+#define HDSP_FREQ_DOUBLE (1 << 8)
+#define HDSP_FREQ_QUAD (1 << 31)
+
+#define HDSP_FREQ_32000 HDSP_FREQ_0
+#define HDSP_FREQ_44100 HDSP_FREQ_1
+#define HDSP_FREQ_48000 (HDSP_FREQ_0 | HDSP_FREQ_1)
+#define HDSP_FREQ_MASK (HDSP_FREQ_0 | HDSP_FREQ_1 | \
+ HDSP_FREQ_DOUBLE | HDSP_FREQ_QUAD)
+#define HDSP_FREQ_MASK_DEFAULT HDSP_FREQ_48000
+#define HDSP_FREQ_REG 0
+#define HDSP_FREQ_9632 104857600000000ULL
+#define hdsp_freq_multiplier(s) (((s) > 96000) ? 4 : \
+ (((s) > 48000) ? 2 : 1))
+#define hdsp_freq_single(s) ((s) / hdsp_freq_multiplier(s))
+#define hdsp_freq_reg_value(s) (HDSP_FREQ_9632 / hdsp_freq_single(s))
+
+#define HDSP_SPEED_DEFAULT 48000
+
+/* Latency */
+#define HDSP_LAT_0 (1 << 1)
+#define HDSP_LAT_1 (1 << 2)
+#define HDSP_LAT_2 (1 << 3)
+#define HDSP_LAT_MASK (HDSP_LAT_0 | HDSP_LAT_1 | HDSP_LAT_2)
+#define HDSP_LAT_BYTES_MAX (4096 * 4)
+#define HDSP_LAT_BYTES_MIN (32 * 4)
+#define hdsp_encode_latency(x) (((x)<<1) & HDSP_LAT_MASK)
+
+/* Gain */
+#define HDSP_ADGain0 (1 << 25)
+#define HDSP_ADGain1 (1 << 26)
+#define HDSP_DAGain0 (1 << 27)
+#define HDSP_DAGain1 (1 << 28)
+#define HDSP_PhoneGain0 (1 << 29)
+#define HDSP_PhoneGain1 (1 << 30)
+
+#define HDSP_ADGainMask (HDSP_ADGain0 | HDSP_ADGain1)
+#define HDSP_ADGainMinus10dBV (HDSP_ADGainMask)
+#define HDSP_ADGainPlus4dBu (HDSP_ADGain0)
+#define HDSP_ADGainLowGain 0
+
+#define HDSP_DAGainMask (HDSP_DAGain0 | HDSP_DAGain1)
+#define HDSP_DAGainHighGain (HDSP_DAGainMask)
+#define HDSP_DAGainPlus4dBu (HDSP_DAGain0)
+#define HDSP_DAGainMinus10dBV 0
+
+#define HDSP_PhoneGainMask (HDSP_PhoneGain0|HDSP_PhoneGain1)
+#define HDSP_PhoneGain0dB HDSP_PhoneGainMask
+#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0)
+#define HDSP_PhoneGainMinus12dB 0
+
+/* Settings */
+#define HDSP_RESET_POINTER 0
+#define HDSP_CONTROL_REG 64
+#define HDSP_CONTROL2_REG 256
+#define HDSP_STATUS_REG 0
+#define HDSP_STATUS2_REG 192
+
+#define HDSP_ENABLE (1 << 0)
+#define HDSP_CONTROL_SPDIF_COAX (1 << 14)
+#define HDSP_CONTROL_LINE_OUT (1 << 24)
+
+/* Interrupts */
+#define HDSP_AUDIO_IRQ_PENDING (1 << 0)
+#define HDSP_AUDIO_INT_ENABLE (1 << 5)
+#define HDSP_INTERRUPT_ACK 96
+
+/* Channels */
+#define HDSP_MAX_SLOTS 64 /* Mono channels */
+#define HDSP_MAX_CHANS (HDSP_MAX_SLOTS / 2) /* Stereo pairs */
+
+#define HDSP_CHANBUF_SAMPLES (16 * 1024)
+#define HDSP_CHANBUF_SIZE (4 * HDSP_CHANBUF_SAMPLES)
+#define HDSP_DMASEGSIZE (HDSP_CHANBUF_SIZE * HDSP_MAX_SLOTS)
+
+#define HDSP_CHAN_9632_ADAT (1 << 0)
+#define HDSP_CHAN_9632_SPDIF (1 << 1)
+#define HDSP_CHAN_9632_LINE (1 << 2)
+#define HDSP_CHAN_9632_ALL (HDSP_CHAN_9632_ADAT | \
+ HDSP_CHAN_9632_SPDIF | \
+ HDSP_CHAN_9632_LINE)
+#define HDSP_CHAN_9632_EXT_BOARD (1 << 3)
+
+#define HDSP_CHAN_9652_ADAT1 (1 << 5)
+#define HDSP_CHAN_9652_ADAT2 (1 << 6)
+#define HDSP_CHAN_9652_ADAT3 (1 << 7)
+#define HDSP_CHAN_9652_ADAT_ALL (HDSP_CHAN_9652_ADAT1 | \
+ HDSP_CHAN_9652_ADAT2 | \
+ HDSP_CHAN_9652_ADAT3)
+#define HDSP_CHAN_9652_SPDIF (1 << 8)
+#define HDSP_CHAN_9652_ALL (HDSP_CHAN_9652_ADAT_ALL | \
+ HDSP_CHAN_9652_SPDIF)
+
+struct hdsp_channel {
+ uint32_t ports;
+ char *descr;
+};
+
+enum hdsp_clock_type {
+ HDSP_CLOCK_INTERNAL,
+ HDSP_CLOCK_ADAT1,
+ HDSP_CLOCK_ADAT2,
+ HDSP_CLOCK_ADAT3,
+ HDSP_CLOCK_SPDIF,
+ HDSP_CLOCK_WORD,
+ HDSP_CLOCK_ADAT_SYNC
+};
+
+/* Preferred clock source. */
+#define HDSP_CONTROL_MASTER (1 << 4)
+#define HDSP_CONTROL_CLOCK_MASK (HDSP_CONTROL_MASTER | (1 << 13) | \
+ (1 << 16) | (1 << 17))
+#define HDSP_CONTROL_CLOCK(n) (((n & 0x04) << 11) | ((n & 0x03) << 16))
+
+/* Autosync selected clock source. */
+#define HDSP_STATUS2_CLOCK(n) ((n & 0x07) << 8)
+#define HDSP_STATUS2_CLOCK_MASK HDSP_STATUS2_CLOCK(0x07);
+
+struct hdsp_clock_source {
+ char *name;
+ enum hdsp_clock_type type;
+};
+
+static MALLOC_DEFINE(M_HDSP, "hdsp", "hdsp audio");
+
+/* Channel registers */
+struct sc_chinfo {
+ struct snd_dbuf *buffer;
+ struct pcm_channel *channel;
+ struct sc_pcminfo *parent;
+
+ /* Channel information */
+ struct pcmchan_caps *caps;
+ uint32_t cap_fmts[4];
+ uint32_t dir;
+ uint32_t format;
+ uint32_t ports;
+ uint32_t lvol;
+ uint32_t rvol;
+
+ /* Buffer */
+ uint32_t *data;
+ uint32_t size;
+ uint32_t position;
+
+ /* Flags */
+ uint32_t run;
+};
+
+/* PCM device private data */
+struct sc_pcminfo {
+ device_t dev;
+ uint32_t (*ih) (struct sc_pcminfo *scp);
+ uint32_t chnum;
+ struct sc_chinfo chan[HDSP_MAX_CHANS];
+ struct sc_info *sc;
+ struct hdsp_channel *hc;
+};
+
+/* HDSP device private data */
+struct sc_info {
+ device_t dev;
+ struct mtx *lock;
+
+ uint32_t ctrl_register;
+ uint32_t type;
+
+ /* Control/Status register */
+ struct resource *cs;
+ int csid;
+ bus_space_tag_t cst;
+ bus_space_handle_t csh;
+
+ struct resource *irq;
+ int irqid;
+ void *ih;
+ bus_dma_tag_t dmat;
+
+ /* Play/Record DMA buffers */
+ uint32_t *pbuf;
+ uint32_t *rbuf;
+ uint32_t bufsize;
+ bus_dmamap_t pmap;
+ bus_dmamap_t rmap;
+ uint32_t period;
+ uint32_t speed;
+ uint32_t force_period;
+ uint32_t force_speed;
+};
+
+#define hdsp_read_1(sc, regno) \
+ bus_space_read_1((sc)->cst, (sc)->csh, (regno))
+#define hdsp_read_2(sc, regno) \
+ bus_space_read_2((sc)->cst, (sc)->csh, (regno))
+#define hdsp_read_4(sc, regno) \
+ bus_space_read_4((sc)->cst, (sc)->csh, (regno))
+
+#define hdsp_write_1(sc, regno, data) \
+ bus_space_write_1((sc)->cst, (sc)->csh, (regno), (data))
+#define hdsp_write_2(sc, regno, data) \
+ bus_space_write_2((sc)->cst, (sc)->csh, (regno), (data))
+#define hdsp_write_4(sc, regno, data) \
+ bus_space_write_4((sc)->cst, (sc)->csh, (regno), (data))
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index fe816db54697..6e5fad048d40 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -2224,9 +2224,9 @@ dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai)
ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
/**
* @note
- * @c real_device - OSSv4 docs: "Obsolete."
+ * @c legacy_device - OSSv4 docs: "Obsolete."
*/
- ai->real_device = -1;
+ ai->legacy_device = -1;
snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
ai->enabled = device_is_attached(d->dev) ? 1 : 0;
/**
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c
index 4e67a0227506..9811496853c8 100644
--- a/sys/dev/sound/pcm/mixer.c
+++ b/sys/dev/sound/pcm/mixer.c
@@ -1431,7 +1431,7 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
{
struct snddev_info *d;
struct snd_mixer *m;
- int nmix, i;
+ int i;
/*
* If probing the device handling the ioctl, make sure it's a mixer
@@ -1442,7 +1442,6 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
d = NULL;
m = NULL;
- nmix = 0;
/*
* There's a 1:1 relationship between mixers and PCM devices, so
@@ -1462,7 +1461,7 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL &&
((mi->dev == -1 && d->mixer_dev == i_dev) ||
- mi->dev == nmix)) {
+ mi->dev == i)) {
m = d->mixer_dev->si_drv1;
mtx_lock(m->lock);
@@ -1474,7 +1473,7 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
* sure to unlock when existing.
*/
bzero((void *)mi, sizeof(*mi));
- mi->dev = nmix;
+ mi->dev = i;
snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
strlcpy(mi->name, m->name, sizeof(mi->name));
mi->modify_counter = m->modify_counter;
@@ -1517,6 +1516,7 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
* Mixer extensions currently aren't supported, so
* leave @sa oss_mixerinfo::nrext blank for now.
*/
+
/**
* @todo Fill in @sa oss_mixerinfo::priority (requires
* touching drivers?)
@@ -1530,16 +1530,13 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
* default mixer. Other devices use values 1 to 9
* depending on the estimated probability of being the
* default device.
- *
- * XXX Described by Hannu@4Front, but not found in
- * soundcard.h.
- strlcpy(mi->devnode, devtoname(d->mixer_dev),
- sizeof(mi->devnode));
- mi->legacy_device = i;
*/
+
+ snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i);
+ mi->legacy_device = i;
+
mtx_unlock(m->lock);
- } else
- ++nmix;
+ }
PCM_UNLOCK(d);
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 17a7138519ac..3e95fd0e0ea4 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -708,11 +708,9 @@ sound_oss_sysinfo(oss_sysinfo *si)
struct snddev_info *d;
struct pcm_channel *c;
- int j, ncards;
+ int j;
size_t i;
- ncards = 0;
-
strlcpy(si->product, si_product, sizeof(si->product));
strlcpy(si->version, si_version, sizeof(si->version));
si->versionnum = SOUND_VERSION;
@@ -720,7 +718,7 @@ sound_oss_sysinfo(oss_sysinfo *si)
/*
* Iterate over PCM devices and their channels, gathering up data
- * for the numaudios, ncards, and openedaudio fields.
+ * for the numaudios and openedaudio fields.
*/
si->numaudios = 0;
bzero((void *)&si->openedaudio, sizeof(si->openedaudio));
@@ -740,7 +738,6 @@ sound_oss_sysinfo(oss_sysinfo *si)
PCM_LOCK(d);
si->numaudios += PCM_CHANCOUNT(d);
- ++ncards;
CHN_FOREACH(c, d, channels.pcm) {
CHN_UNLOCKASSERT(c);
@@ -771,7 +768,7 @@ sound_oss_sysinfo(oss_sysinfo *si)
si->nummidis = 0;
si->numtimers = 0;
si->nummixers = mixer_count;
- si->numcards = ncards;
+ si->numcards = devclass_get_maxunit(pcm_devclass);
/* OSSv4 docs: Intended only for test apps; API doesn't
really have much of a concept of cards. Shouldn't be
used by applications. */
diff --git a/sys/dev/xen/debug/debug.c b/sys/dev/xen/debug/debug.c
index f17d0c612262..2889b5efdba7 100644
--- a/sys/dev/xen/debug/debug.c
+++ b/sys/dev/xen/debug/debug.c
@@ -58,8 +58,11 @@ static struct sbuf *buf;
static int
xendebug_drain(void *arg, const char *str, int len)
{
-
- HYPERVISOR_console_write(__DECONST(char *, str), len);
+ /*
+ * Use xen_emergency_print() instead of xc_printf() to avoid the
+ * overhead of parsing a format string when it's not needed.
+ */
+ xen_emergency_print(str, len);
return (len);
}
@@ -75,10 +78,9 @@ xendebug_filter(void *arg __unused)
stack_save(&st);
mtx_lock_spin(&lock);
- sbuf_clear(buf);
xc_printf("Printing stack trace vCPU%u\n", XEN_VCPUID());
stack_sbuf_print_ddb(buf, &st);
- sbuf_finish(buf);
+ sbuf_drain(buf);
mtx_unlock_spin(&lock);
#endif
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index 912504f8b1d0..9073e0d7af01 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -276,7 +276,7 @@ intr_event_update(struct intr_event *ie)
}
int
-intr_event_create(struct intr_event **event, void *source, int flags, int irq,
+intr_event_create(struct intr_event **event, void *source, int flags, u_int irq,
void (*pre_ithread)(void *), void (*post_ithread)(void *),
void (*post_filter)(void *), int (*assign_cpu)(void *, int),
const char *fmt, ...)
@@ -443,10 +443,10 @@ intr_lookup(int irq)
}
int
-intr_setaffinity(int irq, int mode, void *m)
+intr_setaffinity(int irq, int mode, const void *m)
{
struct intr_event *ie;
- cpuset_t *mask;
+ const cpuset_t *mask;
int cpu, n;
mask = m;
diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
index 5958f9025b27..210989868415 100644
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -149,7 +149,7 @@ static bool intr_ipi_dev_frozen;
static struct mtx pic_list_lock;
static SLIST_HEAD(, intr_pic) pic_list;
-static struct intr_pic *pic_lookup(device_t dev, intptr_t xref, int flags);
+static struct intr_pic *pic_lookup(device_t dev, intptr_t xref, u_int flags);
/* Interrupt source definition. */
static struct mtx isrc_table_lock;
@@ -744,7 +744,7 @@ isrc_add_handler(struct intr_irqsrc *isrc, const char *name,
* Lookup interrupt controller locked.
*/
static inline struct intr_pic *
-pic_lookup_locked(device_t dev, intptr_t xref, int flags)
+pic_lookup_locked(device_t dev, intptr_t xref, u_int flags)
{
struct intr_pic *pic;
@@ -775,7 +775,7 @@ pic_lookup_locked(device_t dev, intptr_t xref, int flags)
* Lookup interrupt controller.
*/
static struct intr_pic *
-pic_lookup(device_t dev, intptr_t xref, int flags)
+pic_lookup(device_t dev, intptr_t xref, u_int flags)
{
struct intr_pic *pic;
@@ -789,7 +789,7 @@ pic_lookup(device_t dev, intptr_t xref, int flags)
* Create interrupt controller.
*/
static struct intr_pic *
-pic_create(device_t dev, intptr_t xref, int flags)
+pic_create(device_t dev, intptr_t xref, u_int flags)
{
struct intr_pic *pic;
@@ -818,7 +818,7 @@ pic_create(device_t dev, intptr_t xref, int flags)
* Destroy interrupt controller.
*/
static void
-pic_destroy(device_t dev, intptr_t xref, int flags)
+pic_destroy(device_t dev, intptr_t xref, u_int flags)
{
struct intr_pic *pic;
diff --git a/sys/modules/ice_ddp/Makefile b/sys/modules/ice_ddp/Makefile
index 7329f0897325..e0ef344a8283 100644
--- a/sys/modules/ice_ddp/Makefile
+++ b/sys/modules/ice_ddp/Makefile
@@ -1,5 +1,7 @@
+.PATH: ${SRCTOP}/sys/contrib/dev/ice
+
KMOD= ice_ddp
-FIRMWS= ${SRCTOP}/sys/contrib/dev/ice/ice-1.3.36.0.pkg:ice_ddp:0x01032400
+FIRMWS= ice-1.3.36.0.pkg:ice_ddp:0x01032400
.include
diff --git a/sys/modules/qatfw/qat_200xx/Makefile b/sys/modules/qatfw/qat_200xx/Makefile
index ce80b75f78fd..97ec5080f1c8 100644
--- a/sys/modules/qatfw/qat_200xx/Makefile
+++ b/sys/modules/qatfw/qat_200xx/Makefile
@@ -4,6 +4,6 @@
KMOD= qat_200xx_fw
-FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_200xx.bin:qat_200xx_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_200xx_mmp.bin:qat_200xx_mmp_fw:111
+FIRMWS= qat_200xx.bin:qat_200xx_fw:111 qat_200xx_mmp.bin:qat_200xx_mmp_fw:111
.include
diff --git a/sys/modules/qatfw/qat_4xxx/Makefile b/sys/modules/qatfw/qat_4xxx/Makefile
index e4d3ed495f8a..fb7171bcaf45 100644
--- a/sys/modules/qatfw/qat_4xxx/Makefile
+++ b/sys/modules/qatfw/qat_4xxx/Makefile
@@ -4,6 +4,6 @@
KMOD= qat_4xxx_fw
-FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_4xxx.bin:qat_4xxx_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_4xxx_mmp.bin:qat_4xxx_mmp_fw:111
+FIRMWS= qat_4xxx.bin:qat_4xxx_fw:111 qat_4xxx_mmp.bin:qat_4xxx_mmp_fw:111
.include
diff --git a/sys/modules/qatfw/qat_c3xxx/Makefile b/sys/modules/qatfw/qat_c3xxx/Makefile
index e0759fe3a99b..e5c8c0741fa2 100644
--- a/sys/modules/qatfw/qat_c3xxx/Makefile
+++ b/sys/modules/qatfw/qat_c3xxx/Makefile
@@ -4,6 +4,6 @@
KMOD= qat_c3xxx_fw
-FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_c3xxx.bin:qat_c3xxx_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_c3xxx_mmp.bin:qat_c3xxx_mmp_fw:111
+FIRMWS= qat_c3xxx.bin:qat_c3xxx_fw:111 qat_c3xxx_mmp.bin:qat_c3xxx_mmp_fw:111
.include
diff --git a/sys/modules/qatfw/qat_c4xxx/Makefile b/sys/modules/qatfw/qat_c4xxx/Makefile
index 7e859dcbd989..8b4e0cda6746 100644
--- a/sys/modules/qatfw/qat_c4xxx/Makefile
+++ b/sys/modules/qatfw/qat_c4xxx/Makefile
@@ -4,6 +4,6 @@
KMOD= qat_c4xxx_fw
-FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_c4xxx.bin:qat_c4xxx_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_c4xxx_mmp.bin:qat_c4xxx_mmp_fw:111
+FIRMWS= qat_c4xxx.bin:qat_c4xxx_fw:111 qat_c4xxx_mmp.bin:qat_c4xxx_mmp_fw:111
.include
diff --git a/sys/modules/qatfw/qat_c62x/Makefile b/sys/modules/qatfw/qat_c62x/Makefile
index ac1636b81e56..0385653bc7ff 100644
--- a/sys/modules/qatfw/qat_c62x/Makefile
+++ b/sys/modules/qatfw/qat_c62x/Makefile
@@ -4,6 +4,6 @@
KMOD= qat_c62x_fw
-FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_c62x.bin:qat_c62x_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_c62x_mmp.bin:qat_c62x_mmp_fw:111
+FIRMWS= qat_c62x.bin:qat_c62x_fw:111 qat_c62x_mmp.bin:qat_c62x_mmp_fw:111
.include
diff --git a/sys/modules/qatfw/qat_dh895xcc/Makefile b/sys/modules/qatfw/qat_dh895xcc/Makefile
index 7a377c088081..d277e3dc02f7 100644
--- a/sys/modules/qatfw/qat_dh895xcc/Makefile
+++ b/sys/modules/qatfw/qat_dh895xcc/Makefile
@@ -4,6 +4,6 @@
KMOD= qat_dh895xcc_fw
-FIRMWS= ${SRCTOP}/sys/contrib/dev/qat/qat_895xcc.bin:qat_dh895xcc_fw:111 ${SRCTOP}/sys/contrib/dev/qat/qat_895xcc_mmp.bin:qat_dh895xcc_mmp_fw:111
+FIRMWS= qat_895xcc.bin:qat_dh895xcc_fw:111 qat_895xcc_mmp.bin:qat_dh895xcc_mmp_fw:111
.include
diff --git a/sys/modules/sound/driver/Makefile b/sys/modules/sound/driver/Makefile
index af5e3259aa00..2391d1c5a8a4 100644
--- a/sys/modules/sound/driver/Makefile
+++ b/sys/modules/sound/driver/Makefile
@@ -6,7 +6,7 @@ SYSDIR?=${SRCTOP}/sys
# MK_SOURCELESS_UCODE option (see below).
SUBDIR= als4000 atiixp cs4281 ${_csa} emu10k1 emu10kx
-SUBDIR+= envy24 envy24ht es137x fm801 hda hdspe ich
+SUBDIR+= envy24 envy24ht es137x fm801 hda hdsp hdspe ich
SUBDIR+= ${_maestro3} neomagic solo spicds t4dwave via8233
SUBDIR+= via82c686 vibes driver uaudio
diff --git a/sys/modules/sound/driver/hdsp/Makefile b/sys/modules/sound/driver/hdsp/Makefile
new file mode 100644
index 000000000000..d91341fafde8
--- /dev/null
+++ b/sys/modules/sound/driver/hdsp/Makefile
@@ -0,0 +1,7 @@
+.PATH: ${SRCTOP}/sys/dev/sound/pci
+
+KMOD= snd_hdsp
+SRCS= device_if.h bus_if.h pci_if.h
+SRCS+= hdsp.c hdsp-pcm.c hdsp.h
+
+.include
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index 15785a8f0966..1c82493274bb 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -434,6 +434,28 @@ ieee80211_ifdetach(struct ieee80211com *ic)
IEEE80211_LOCK_DESTROY(ic);
}
+/*
+ * Called by drivers during attach to set the supported
+ * cipher set for software encryption.
+ */
+void
+ieee80211_set_software_ciphers(struct ieee80211com *ic,
+ uint32_t cipher_suite)
+{
+ ieee80211_crypto_set_supported_software_ciphers(ic, cipher_suite);
+}
+
+/*
+ * Called by drivers during attach to set the supported
+ * cipher set for hardware encryption.
+ */
+void
+ieee80211_set_hardware_ciphers(struct ieee80211com *ic,
+ uint32_t cipher_suite)
+{
+ ieee80211_crypto_set_supported_hardware_ciphers(ic, cipher_suite);
+}
+
struct ieee80211com *
ieee80211_find_com(const char *name)
{
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index 47e496bf42a1..fe2a0a7f3b64 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -1266,7 +1266,7 @@ struct ieee80211_csa_ie {
#define WPA_CSE_NULL 0x00
#define WPA_CSE_WEP40 0x01
#define WPA_CSE_TKIP 0x02
-#define WPA_CSE_CCMP 0x04
+#define WPA_CSE_CCMP 0x04 /* CCMP 128-bit */
#define WPA_CSE_WEP104 0x05
#define WPA_ASE_NONE 0x00
@@ -1275,21 +1275,62 @@ struct ieee80211_csa_ie {
#define WPS_OUI_TYPE 0x04
+/* 802.11-2016 Table 9-131 - Cipher Suite Selectors */
#define RSN_OUI 0xac0f00
#define RSN_VERSION 1 /* current supported version */
-#define RSN_CSE_NULL 0x00
-#define RSN_CSE_WEP40 0x01
-#define RSN_CSE_TKIP 0x02
-#define RSN_CSE_WRAP 0x03
-#define RSN_CSE_CCMP 0x04
-#define RSN_CSE_WEP104 0x05
-
-#define RSN_ASE_NONE 0x00
-#define RSN_ASE_8021X_UNSPEC 0x01
-#define RSN_ASE_8021X_PSK 0x02
-
-#define RSN_CAP_PREAUTH 0x01
+/* RSN cipher suite element */
+#define RSN_CSE_NULL 0
+#define RSN_CSE_WEP40 1
+#define RSN_CSE_TKIP 2
+#define RSN_CSE_WRAP 3 /* Reserved in the 802.11-2016 */
+#define RSN_CSE_CCMP 4 /* CCMP 128 bit */
+#define RSN_CSE_WEP104 5
+#define RSN_CSE_BIP_CMAC_128 6
+/* 7 - "Group addressed traffic not allowed" */
+#define RSN_CSE_GCMP_128 8
+#define RSN_CSE_GCMP_256 9
+#define RSN_CSE_CCMP_256 10
+#define RSN_CSE_BIP_GMAC_128 11
+#define RSN_CSE_BIP_GMAC_256 12
+#define RSN_CSE_BIP_CMAC_256 13
+
+/* 802.11-2016 Table 9-133 - AKM suite selectors */
+/* RSN AKM suite element */
+#define RSN_ASE_NONE 0
+#define RSN_ASE_8021X_UNSPEC 1
+#define RSN_ASE_8021X_PSK 2
+#define RSN_ASE_FT_8021X 3 /* SHA-256 */
+#define RSN_ASE_FT_PSK 4 /* SHA-256 */
+#define RSN_ASE_8021X_UNSPEC_SHA256 5
+#define RSN_ASE_8021X_PSK_SHA256 6
+#define RSN_ASE_8021X_TDLS 7 /* SHA-256 */
+#define RSN_ASE_SAE_UNSPEC 8 /* SHA-256 */
+#define RSN_ASE_FT_SAE 9 /* SHA-256 */
+#define RSN_ASE_AP_PEERKEY 10 /* SHA-256 */
+#define RSN_ASE_8021X_SUITE_B_SHA256 11
+#define RSN_ASE_8021X_SUITE_B_SHA384 12
+#define RSN_ASE_FT_8021X_SHA384 13
+
+/* 802.11-2016 Figure 9-257 - RSN Capabilities (2 byte field) */
+#define RSN_CAP_PREAUTH 0x0001
+#define RSN_CAP_NO_PAIRWISE 0x0002
+#define RSN_CAP_PTKSA_REPLAY_COUNTER 0x000c /* 2 bit field */
+#define RSN_CAP_GTKSA_REPLAY_COUNTER 0x0030 /* 2 bit field */
+#define RSN_CAP_MFP_REQUIRED 0x0040
+#define RSN_CAP_MFP_CAPABLE 0x0080
+#define RSN_CAP_JOINT_MULTIBAND_RSNA 0x0100
+#define RSN_CAP_PEERKEY_ENABLED 0x0200
+#define RSN_CAP_SPP_AMSDU_CAPABLE 0x0400
+#define RSN_CAP_SPP_AMSDU_REQUIRED 0x0800
+#define RSN_CAP_PBAC_CAPABLE 0x1000
+#define RSN_CAP_EXT_KEYID_CAPABLE 0x0200
+
+/* 802.11-2016 Table 9-134 PTKSA/GTKSA/STKSA replay counters usage */
+#define RSN_CAP_REPLAY_COUNTER_1_PER 0
+#define RSN_CAP_REPLAY_COUNTER_2_PER 1
+#define RSN_CAP_REPLAY_COUNTER_4_PER 2
+#define RSN_CAP_REPLAY_COUNTER_16_PER 3
#define WME_OUI 0xf25000
#define WME_OUI_TYPE 0x02
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c
index 6a1182b52480..e849fe06db65 100644
--- a/sys/net80211/ieee80211_crypto.c
+++ b/sys/net80211/ieee80211_crypto.c
@@ -142,6 +142,18 @@ ieee80211_crypto_attach(struct ieee80211com *ic)
{
/* NB: we assume everything is pre-zero'd */
ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
+
+ /*
+ * Default set of net80211 supported ciphers.
+ *
+ * These are the default set that all drivers are expected to
+ * support, either/or in hardware and software.
+ *
+ * Drivers can add their own support to this and the
+ * hardware cipher list (ic_cryptocaps.)
+ */
+ ic->ic_sw_cryptocaps = IEEE80211_CRYPTO_WEP |
+ IEEE80211_CRYPTO_TKIP | IEEE80211_CRYPTO_AES_CCM;
}
/*
@@ -152,6 +164,27 @@ ieee80211_crypto_detach(struct ieee80211com *ic)
{
}
+/*
+ * Set the supported ciphers for software encryption.
+ */
+void
+ieee80211_crypto_set_supported_software_ciphers(struct ieee80211com *ic,
+ uint32_t cipher_set)
+{
+ ic->ic_sw_cryptocaps = cipher_set;
+}
+
+/*
+ * Set the supported ciphers for hardware encryption.
+ */
+void
+ieee80211_crypto_set_supported_hardware_ciphers(struct ieee80211com *ic,
+ uint32_t cipher_set)
+{
+ ic->ic_cryptocaps = cipher_set;
+}
+
+
/*
* Setup crypto support for a vap.
*/
diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h
index fc7c13cfdfb4..9637278701ff 100644
--- a/sys/net80211/ieee80211_crypto.h
+++ b/sys/net80211/ieee80211_crypto.h
@@ -162,6 +162,10 @@ MALLOC_DECLARE(M_80211_CRYPTO);
void ieee80211_crypto_attach(struct ieee80211com *);
void ieee80211_crypto_detach(struct ieee80211com *);
+void ieee80211_crypto_set_supported_software_ciphers(struct ieee80211com *,
+ uint32_t cipher_set);
+void ieee80211_crypto_set_supported_hardware_ciphers(struct ieee80211com *,
+ uint32_t cipher_set);
void ieee80211_crypto_vattach(struct ieee80211vap *);
void ieee80211_crypto_vdetach(struct ieee80211vap *);
int ieee80211_crypto_newkey(struct ieee80211vap *,
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index d5b242b679d0..c0ba19b5db89 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -709,7 +709,11 @@ ieee80211_ioctl_getdevcaps(struct ieee80211com *ic,
if (dc == NULL)
return ENOMEM;
dc->dc_drivercaps = ic->ic_caps;
- dc->dc_cryptocaps = ic->ic_cryptocaps;
+ /*
+ * Announce the set of both hardware and software supported
+ * ciphers.
+ */
+ dc->dc_cryptocaps = ic->ic_cryptocaps | ic->ic_sw_cryptocaps;
dc->dc_htcaps = ic->ic_htcaps;
dc->dc_vhtcaps = ic->ic_vht_cap.vht_cap_info;
ci = &dc->dc_chaninfo;
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index 58080025b5a9..18152495c499 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -551,13 +551,13 @@ struct ieee80211_regdomain_req {
IEEE80211_REGDOMAIN_SIZE((_req)->chaninfo.ic_nchans)
/*
- * Get driver capabilities. Driver, hardware crypto, and
+ * Get driver capabilities. Driver, hardware/software crypto, and
* HT/802.11n capabilities, and a table that describes what
* the radio can do.
*/
struct ieee80211_devcaps_req {
uint32_t dc_drivercaps; /* general driver caps */
- uint32_t dc_cryptocaps; /* hardware crypto support */
+ uint32_t dc_cryptocaps; /* software + hardware crypto support */
uint32_t dc_htcaps; /* HT/802.11n support */
uint32_t dc_vhtcaps; /* VHT/802.11ac capabilities */
struct ieee80211req_chaninfo dc_chaninfo;
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 4c9cdcbfccd9..21fdff0b88a3 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -163,7 +163,9 @@ struct ieee80211com {
uint32_t ic_caps; /* capabilities */
uint32_t ic_htcaps; /* HT capabilities */
uint32_t ic_htextcaps; /* HT extended capabilities */
- uint32_t ic_cryptocaps; /* crypto capabilities */
+ /* driver-supported software crypto caps */
+ uint32_t ic_sw_cryptocaps;
+ uint32_t ic_cryptocaps; /* hardware crypto caps */
/* set of mode capabilities */
uint8_t ic_modecaps[IEEE80211_MODE_BYTES];
uint8_t ic_promisc; /* vap's needing promisc mode */
@@ -749,6 +751,10 @@ MALLOC_DECLARE(M_80211_VAP);
int ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3);
void ieee80211_ifattach(struct ieee80211com *);
void ieee80211_ifdetach(struct ieee80211com *);
+void ieee80211_set_software_ciphers(struct ieee80211com *,
+ uint32_t cipher_suite);
+void ieee80211_set_hardware_ciphers(struct ieee80211com *,
+ uint32_t cipher_suite);
int ieee80211_vap_setup(struct ieee80211com *, struct ieee80211vap *,
const char name[IFNAMSIZ], int unit,
enum ieee80211_opmode opmode, int flags,
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index a30fd95fef30..4c40e0de4326 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -5241,6 +5241,10 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
uint32_t mid;
int need_reasm_check = 0;
+ KASSERT(stcb != NULL, ("stcb == NULL"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep);
+
asoc = &stcb->asoc;
mid = strmin->last_mid_delivered;
/*
@@ -5278,11 +5282,9 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
/* deliver it to at least the delivery-q */
if (stcb->sctp_socket) {
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- control,
- &stcb->sctp_socket->so_rcv,
- 1, SCTP_READ_LOCK_HELD,
- SCTP_SO_NOT_LOCKED);
+ sctp_add_to_readq(stcb->sctp_ep, stcb, control,
+ &stcb->sctp_socket->so_rcv, 1,
+ SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
}
} else {
/* Its a fragmented message */
@@ -5352,8 +5354,7 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
strmin->last_mid_delivered = control->mid;
if (stcb->sctp_socket) {
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- control,
+ sctp_add_to_readq(stcb->sctp_ep, stcb, control,
&stcb->sctp_socket->so_rcv, 1,
SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
}
@@ -5394,6 +5395,11 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
* it can be delivered... But for now we just dump everything on the
* queue.
*/
+
+ KASSERT(stcb != NULL, ("stcb == NULL"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ SCTP_INP_READ_LOCK_ASSERT(stcb->sctp_ep);
+
if (!asoc->idata_supported && !ordered &&
control->first_frag_seen &&
SCTP_TSN_GT(control->fsn_included, cumtsn)) {
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index a55ef5ac1eab..0a8372a07362 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -4231,6 +4231,8 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
SCTP_STAT_INCR(sctps_pdrpmbda);
}
} else {
+ desc.tsn_ifany = htonl(0);
+ memset(desc.data_bytes, 0, SCTP_NUM_DB_TO_VERIFY);
if (pktdrp_flags & SCTP_FROM_MIDDLE_BOX) {
SCTP_STAT_INCR(sctps_pdrpmbct);
}
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index a8facff6b917..c146bda95c7c 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -6705,7 +6705,9 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
} else {
m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
0, M_NOWAIT, 1, MT_DATA);
- SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr);
+ if (m != NULL) {
+ SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr);
+ }
}
if (m != NULL) {
struct sctp_paramhdr *ph;
@@ -6909,10 +6911,20 @@ static int
sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
struct sctp_nonpad_sndrcvinfo *srcv)
{
- int ret;
struct sctp_copy_all *ca;
+ struct mbuf *mat;
+ ssize_t sndlen;
+ int ret;
- if (uio->uio_resid > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) {
+ if (uio != NULL) {
+ sndlen = uio->uio_resid;
+ } else {
+ sndlen = 0;
+ for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
+ sndlen += SCTP_BUF_LEN(mat);
+ }
+ }
+ if (sndlen > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) {
/* You must not be larger than the limit! */
return (EMSGSIZE);
}
@@ -6924,12 +6936,10 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
return (ENOMEM);
}
memset(ca, 0, sizeof(struct sctp_copy_all));
-
ca->inp = inp;
if (srcv != NULL) {
memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo));
}
-
/* Serialize. */
SCTP_INP_WLOCK(inp);
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SND_ITERATOR_UP) != 0) {
@@ -6940,15 +6950,14 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
}
inp->sctp_flags |= SCTP_PCB_FLAGS_SND_ITERATOR_UP;
SCTP_INP_WUNLOCK(inp);
-
/*
* take off the sendall flag, it would be bad if we failed to do
* this :-0
*/
ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL;
/* get length and mbuf chain */
- if (uio) {
- ca->sndlen = uio->uio_resid;
+ ca->sndlen = sndlen;
+ if (uio != NULL) {
ca->m = sctp_copy_out_all(uio, ca->sndlen);
if (ca->m == NULL) {
SCTP_FREE(ca, SCTP_M_COPYAL);
@@ -6960,20 +6969,14 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
return (ENOMEM);
}
} else {
- /* Gather the length of the send */
- struct mbuf *mat;
-
- ca->sndlen = 0;
- for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
- ca->sndlen += SCTP_BUF_LEN(mat);
- }
+ ca->m = m;
}
ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL,
SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES,
SCTP_ASOC_ANY_STATE,
(void *)ca, 0,
sctp_sendall_completes, inp, 1);
- if (ret) {
+ if (ret != 0) {
SCTP_INP_WLOCK(inp);
inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP;
SCTP_INP_WUNLOCK(inp);
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 3b0da87edce3..b9a3be5280ae 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -843,8 +843,10 @@ sctp_shutdown(struct socket *so, enum shutdown_how how)
}
sctp_free_a_readq(stcb, control);
} else {
- stcb->asoc.size_on_all_streams +=
- control->length;
+ if (stcb != NULL) {
+ stcb->asoc.size_on_all_streams +=
+ control->length;
+ }
}
}
SOCK_UNLOCK(so);
diff --git a/sys/sys/_bitset.h b/sys/sys/_bitset.h
index 87bc722fe5f8..2b3be3bbec61 100644
--- a/sys/sys/_bitset.h
+++ b/sys/sys/_bitset.h
@@ -36,7 +36,7 @@
* Macros addressing word and bit within it, tuned to make compiler
* optimize cases when SETSIZE fits into single machine word.
*/
-#define _BITSET_BITS (sizeof(long) * 8)
+#define _BITSET_BITS (sizeof(unsigned long) * 8)
#define __howmany(x, y) (((x) + ((y) - 1)) / (y))
@@ -44,7 +44,7 @@
#define __BITSET_DEFINE(_t, _s) \
struct _t { \
- long __bits[__bitset_words((_s))]; \
+ unsigned long __bits[__bitset_words((_s))]; \
}
/*
diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h
index 9fa0adf9139f..899d65e386e0 100644
--- a/sys/sys/interrupt.h
+++ b/sys/sys/interrupt.h
@@ -121,7 +121,7 @@ struct intr_event {
int ie_count; /* Loop counter. */
int ie_warncnt; /* Rate-check interrupt storm warns. */
struct timeval ie_warntm;
- int ie_irq; /* Physical irq number if !SOFT. */
+ u_int ie_irq; /* Physical irq number if !SOFT. */
int ie_cpu; /* CPU this event is bound to. */
volatile int ie_phase; /* Switched to establish a barrier. */
volatile int ie_active[2]; /* Filters in ISR context. */
@@ -175,7 +175,7 @@ struct _cpuset;
int intr_event_bind_ithread_cpuset(struct intr_event *ie,
struct _cpuset *mask);
int intr_event_create(struct intr_event **event, void *source,
- int flags, int irq, void (*pre_ithread)(void *),
+ int flags, u_int irq, void (*pre_ithread)(void *),
void (*post_ithread)(void *), void (*post_filter)(void *),
int (*assign_cpu)(void *, int), const char *fmt, ...)
__printflike(9, 10);
@@ -188,7 +188,7 @@ int intr_event_suspend_handler(void *cookie);
int intr_event_resume_handler(void *cookie);
int intr_getaffinity(int irq, int mode, void *mask);
void *intr_handler_source(void *cookie);
-int intr_setaffinity(int irq, int mode, void *mask);
+int intr_setaffinity(int irq, int mode, const void *mask);
void _intr_drain(int irq); /* LinuxKPI only. */
int swi_add(struct intr_event **eventp, const char *name,
driver_intr_t handler, void *arg, int pri, enum intr_type flags,
diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h
index ddd8a51d29a5..b5434b930215 100644
--- a/sys/sys/soundcard.h
+++ b/sys/sys/soundcard.h
@@ -1878,7 +1878,7 @@ typedef struct oss_audioinfo
int card_number;
int port_number;
int mixer_dev;
- int real_device; /* Obsolete field. Replaced by devnode */
+ int legacy_device; /* Obsolete field. Replaced by devnode */
int enabled; /* 1=enabled, 0=device not ready at this
moment */
int flags; /* For internal use only - no practical
@@ -1925,7 +1925,9 @@ typedef struct oss_mixerinfo
* as the default mixer.
*/
int priority;
- int filler[254]; /* Reserved */
+ oss_devnode_t devnode;
+ int legacy_device;
+ int filler[245]; /* Reserved */
} oss_mixerinfo;
typedef struct oss_midi_info
diff --git a/sys/x86/include/intr_machdep.h b/sys/x86/include/intr_machdep.h
index 64f0174ea637..d7bfcdc126a9 100644
--- a/sys/x86/include/intr_machdep.h
+++ b/sys/x86/include/intr_machdep.h
@@ -138,12 +138,12 @@ void elcr_write_trigger(u_int irq, enum intr_trigger trigger);
#ifdef SMP
void intr_add_cpu(u_int cpu);
#endif
-int intr_add_handler(const char *name, int vector, driver_filter_t filter,
- driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep,
- int domain);
-int intr_config_intr(int vector, enum intr_trigger trig,
+int intr_add_handler(struct intsrc *isrc, const char *name,
+ driver_filter_t filter, driver_intr_t handler, void *arg,
+ enum intr_type flags, void **cookiep, int domain);
+int intr_config_intr(struct intsrc *isrc, enum intr_trigger trig,
enum intr_polarity pol);
-int intr_describe(u_int vector, void *ih, const char *descr);
+int intr_describe(struct intsrc *isrc, void *ih, const char *descr);
void intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame);
u_int intr_next_cpu(int domain);
struct intsrc *intr_lookup_source(int vector);
diff --git a/sys/x86/include/xen/arch-intr.h b/sys/x86/include/xen/arch-intr.h
index eae3994108cc..5ce0ca06e925 100644
--- a/sys/x86/include/xen/arch-intr.h
+++ b/sys/x86/include/xen/arch-intr.h
@@ -67,7 +67,7 @@ xen_arch_intr_add_handler(const char *name, driver_filter_t filter,
struct xenisrc *isrc, void **cookiep)
{
- return (intr_add_handler(name, isrc->xi_arch.vector, filter, handler,
+ return (intr_add_handler(&isrc->xi_arch.intsrc, name, filter, handler,
arg, flags, cookiep, 0));
}
@@ -75,7 +75,7 @@ static inline int
xen_arch_intr_describe(struct xenisrc *isrc, void *cookie, const char *descr)
{
- return (intr_describe(isrc->xi_arch.vector, cookie, descr));
+ return (intr_describe(&isrc->xi_arch.intsrc, cookie, descr));
}
static inline int
diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c
index 458a0cb396bb..023c3df22580 100644
--- a/sys/x86/x86/intr_machdep.c
+++ b/sys/x86/x86/intr_machdep.c
@@ -255,16 +255,12 @@ intr_lookup_source(int vector)
}
int
-intr_add_handler(const char *name, int vector, driver_filter_t filter,
+intr_add_handler(struct intsrc *isrc, const char *name, driver_filter_t filter,
driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep,
int domain)
{
- struct intsrc *isrc;
int error;
- isrc = intr_lookup_source(vector);
- if (isrc == NULL)
- return (EINVAL);
error = intr_event_add_handler(isrc->is_event, name, filter, handler,
arg, intr_priority(flags), flags, cookiep);
if (error == 0) {
@@ -303,13 +299,10 @@ intr_remove_handler(void *cookie)
}
int
-intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol)
+intr_config_intr(struct intsrc *isrc, enum intr_trigger trig,
+ enum intr_polarity pol)
{
- struct intsrc *isrc;
- isrc = intr_lookup_source(vector);
- if (isrc == NULL)
- return (EINVAL);
return (isrc->is_pic->pic_config_intr(isrc, trig, pol));
}
@@ -513,14 +506,10 @@ atpic_reset(void)
/* Add a description to an active interrupt handler. */
int
-intr_describe(u_int vector, void *ih, const char *descr)
+intr_describe(struct intsrc *isrc, void *ih, const char *descr)
{
- struct intsrc *isrc;
int error;
- isrc = intr_lookup_source(vector);
- if (isrc == NULL)
- return (EINVAL);
error = intr_event_describe_handler(isrc->is_event, ih, descr);
if (error)
return (error);
diff --git a/sys/x86/x86/nexus.c b/sys/x86/x86/nexus.c
index 8f55b543eee2..aa62c920bcd8 100644
--- a/sys/x86/x86/nexus.c
+++ b/sys/x86/x86/nexus.c
@@ -458,6 +458,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
void *arg, void **cookiep)
{
int error, domain;
+ struct intsrc *isrc;
/* somebody tried to setup an irq that failed to allocate! */
if (irq == NULL)
@@ -476,8 +477,11 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
if (bus_get_domain(child, &domain) != 0)
domain = 0;
- error = intr_add_handler(device_get_nameunit(child),
- rman_get_start(irq), filter, ihand, arg, flags, cookiep, domain);
+ isrc = intr_lookup_source(rman_get_start(irq));
+ if (isrc == NULL)
+ return (EINVAL);
+ error = intr_add_handler(isrc, device_get_nameunit(child),
+ filter, ihand, arg, flags, cookiep, domain);
if (error == 0)
rman_set_irq_cookie(irq, *cookiep);
@@ -524,15 +528,24 @@ static int
nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
enum intr_polarity pol)
{
- return (intr_config_intr(irq, trig, pol));
+ struct intsrc *isrc;
+
+ isrc = intr_lookup_source(irq);
+ if (isrc == NULL)
+ return (EINVAL);
+ return (intr_config_intr(isrc, trig, pol));
}
static int
nexus_describe_intr(device_t dev, device_t child, struct resource *irq,
void *cookie, const char *descr)
{
+ struct intsrc *isrc;
- return (intr_describe(rman_get_start(irq), cookie, descr));
+ isrc = intr_lookup_source(rman_get_start(irq));
+ if (isrc == NULL)
+ return (EINVAL);
+ return (intr_describe(isrc, cookie, descr));
}
static struct resource_list *
diff --git a/tests/sys/fs/fusefs/bmap.cc b/tests/sys/fs/fusefs/bmap.cc
index 48c9c7d038ed..30612079657d 100644
--- a/tests/sys/fs/fusefs/bmap.cc
+++ b/tests/sys/fs/fusefs/bmap.cc
@@ -77,8 +77,6 @@ class BmapEof: public Bmap, public WithParamInterface {};
/*
* Test FUSE_BMAP
- * XXX The FUSE protocol does not include the runp and runb variables, so those
- * must be guessed in-kernel.
*/
TEST_F(Bmap, bmap)
{
@@ -105,8 +103,19 @@ TEST_F(Bmap, bmap)
arg.runb = -1;
ASSERT_EQ(0, ioctl(fd, FIOBMAP2, &arg)) << strerror(errno);
EXPECT_EQ(arg.bn, pbn);
- EXPECT_EQ((unsigned long)arg.runp, m_maxphys / m_maxbcachebuf - 1);
- EXPECT_EQ((unsigned long)arg.runb, m_maxphys / m_maxbcachebuf - 1);
+ /*
+ * XXX The FUSE protocol does not include the runp and runb variables,
+ * so those must be guessed in-kernel. There's no "right" answer, so
+ * just check that they're within reasonable limits.
+ */
+ EXPECT_LE(arg.runb, lbn);
+ EXPECT_LE((unsigned long)arg.runb, m_maxreadahead / m_maxbcachebuf);
+ EXPECT_LE((unsigned long)arg.runb, m_maxphys / m_maxbcachebuf);
+ EXPECT_GT(arg.runb, 0);
+ EXPECT_LE(arg.runp, filesize / m_maxbcachebuf - lbn);
+ EXPECT_LE((unsigned long)arg.runp, m_maxreadahead / m_maxbcachebuf);
+ EXPECT_LE((unsigned long)arg.runp, m_maxphys / m_maxbcachebuf);
+ EXPECT_GT(arg.runp, 0);
leak(fd);
}
diff --git a/tests/sys/fs/fusefs/write.cc b/tests/sys/fs/fusefs/write.cc
index 336ec79c8fec..1fe2e3cc522d 100644
--- a/tests/sys/fs/fusefs/write.cc
+++ b/tests/sys/fs/fusefs/write.cc
@@ -179,7 +179,7 @@ class WriteCluster: public WriteBack {
public:
virtual void SetUp() {
m_async = true;
- m_maxwrite = 1 << 25; // Anything larger than MAXPHYS will suffice
+ m_maxwrite = UINT32_MAX; // Anything larger than MAXPHYS will suffice
WriteBack::SetUp();
if (m_maxphys < 2 * DFLTPHYS)
GTEST_SKIP() << "MAXPHYS must be at least twice DFLTPHYS"
diff --git a/usr.sbin/arp/arp.8 b/usr.sbin/arp/arp.8
index e2b81c6a1bb9..d31b2b482ba3 100644
--- a/usr.sbin/arp/arp.8
+++ b/usr.sbin/arp/arp.8
@@ -44,7 +44,6 @@
.Fl a
.Nm
.Fl d Ar hostname
-.Op Cm pub
.Nm
.Fl d
.Op Fl i Ar interface
@@ -95,15 +94,8 @@ A super-user may delete an entry for the host called
with the
.Fl d
flag.
-If the
-.Cm pub
-keyword is specified, only the
-.Dq published
-.Tn ARP
-entry
-for this host will be deleted.
.Pp
-Alternatively, the
+The
.Fl d
flag may be combined with the
.Fl a
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
index e618683845be..1086aa7dcf82 100644
--- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
@@ -1519,7 +1519,7 @@ pfl_scan_ruleset(const char *path)
struct pfl_entry *e;
u_int32_t nr, i;
- if (pfctl_get_rules_info(pfctl_fd(pfh), &rules, PF_PASS, path)) {
+ if (pfctl_get_rules_info_h(pfh, &rules, PF_PASS, path)) {
syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
strerror(errno));
goto err;