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;