sound: Retire unit.*

The unit.* code is largely obsolete and imposes limits that are no
longer needed nowadays.

- Capping the maximum allowed soundcards in a given machine. By default,
  the limit is 512 (snd_max_u() in unit.c), and the maximum possible is
  2048 (SND_UNIT_UMAX in unit.h). It can also be tuned through the
  hw.snd.maxunit loader(8) tunable. Even though these limits are large
  enough that they should never cause problems, there is no need for
  this limit to exist in the first place.
- Capping the available device/channel types. By default, this is 32
  (snd_max_d() in unit.c). However, these types are pre-defined in
  pcm/sound.h (see SND_DEV_*), so the cap is unnecessary when we know
  that their number is constant.
- Capping the number of channels per-device. By default, the limit 1024
  (snd_max_c() in unit.c). This is probably the most problematic of the
  limits mentioned, because this limit can never be reached, as the
  maximum is hard-capped at either hw.snd.maxautovchans (16 by default),
  or SND_MAXHWCHAN and SND_MAXVCHANS.

These limtits are encoded in masks (see SND_U_MASK, SND_D_MASK,
SND_C_MASK in unit.h) and are used to construct a bitfield of the form
[dsp_unit, type, channel_unit] in snd_mkunit() which is assigned to
pcm_channel->unit.

This patch gets rid of everything unit.*-related and makes a slightly
different use of the "unit" field to only contain the channel unit
number. The channel type is stored in a new pcm_channel->type field, and
the DSP unit number need not be stored at all, since we can fetch it
from device_get_unit(pcm_channel->dev). This change has the effect that
we no longer need to impose caps on the number of soundcards,
device/channel types and per-device channels. As a result the code is
noticeably simplified and more readable.

Apart from the fact that the hw.snd.maxunit loader(8) tunable is also
retired as a side-effect of this patch, sound(4)'s behavior remains the
same.

Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Reviewed by:	dev_submerge.ch
Differential Revision:	https://reviews.freebsd.org/D44912
This commit is contained in:
Christos Margiolis 2024-04-28 21:44:35 +02:00
parent fa28452549
commit 25723d6636
13 changed files with 74 additions and 454 deletions

View file

@ -10,6 +10,9 @@ newline. Entries should be separated by a newline.
Changes to this file should not be MFCed.
8fef193e14e2:
As a side-effect of retiring the unit.* code in sound(4), the
hw.snd.maxunit loader(8) tunable is also retired.
6d5ce2bb6344:
The default value of the nfs_reserved_port_only rc.conf(5) setting has
changed. The FreeBSD NFS server now requires the source port of

View file

@ -3072,7 +3072,6 @@ dev/smc/if_smc.c optional smc
dev/smc/if_smc_acpi.c optional smc acpi
dev/smc/if_smc_fdt.c optional smc fdt
dev/snp/snp.c optional snp
dev/sound/unit.c optional sound
dev/sound/pci/als4000.c optional snd_als4000 pci
dev/sound/pci/atiixp.c optional snd_atiixp pci
dev/sound/pci/cmi.c optional snd_cmi pci

View file

@ -104,6 +104,7 @@ struct pcm_channel {
void *devinfo;
device_t dev;
int unit;
int type;
char name[CHN_NAMELEN];
char comm[MAXCOMLEN + 1];
struct mtx *lock;
@ -224,7 +225,7 @@ struct pcm_channel {
#define CHN_INSERT_SORT(w, x, y, z) do { \
struct pcm_channel *t, *a = NULL; \
CHN_FOREACH(t, x, z) { \
if ((y)->unit w t->unit) \
if ((y)->type w t->type) \
a = t; \
else \
break; \
@ -235,13 +236,9 @@ struct pcm_channel {
CHN_INSERT_HEAD(x, y, z); \
} while (0)
#define CHN_INSERT_SORT_ASCEND(x, y, z) CHN_INSERT_SORT(>, x, y, z)
#define CHN_INSERT_SORT_ASCEND(x, y, z) CHN_INSERT_SORT(>=, x, y, z)
#define CHN_INSERT_SORT_DESCEND(x, y, z) CHN_INSERT_SORT(<, x, y, z)
#define CHN_UNIT(x) (snd_unit2u((x)->unit))
#define CHN_DEV(x) (snd_unit2d((x)->unit))
#define CHN_CHAN(x) (snd_unit2c((x)->unit))
#define CHN_BUF_PARENT(x, y) \
(((x) != NULL && (x)->parentchannel != NULL && \
(x)->parentchannel->bufhard != NULL) ? \

View file

@ -444,7 +444,7 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
if (DSP_F_READ(flags)) {
/* open for read */
rderror = pcm_chnalloc(d, &rdch, PCMDIR_REC,
td->td_proc->p_pid, td->td_proc->p_comm, -1);
td->td_proc->p_pid, td->td_proc->p_comm);
if (rderror == 0 && chn_reset(rdch, fmt, spd) != 0)
rderror = ENXIO;
@ -472,7 +472,7 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
if (DSP_F_WRITE(flags)) {
/* open for write */
wrerror = pcm_chnalloc(d, &wrch, PCMDIR_PLAY,
td->td_proc->p_pid, td->td_proc->p_comm, -1);
td->td_proc->p_pid, td->td_proc->p_comm);
if (wrerror == 0 && chn_reset(wrch, fmt, spd) != 0)
wrerror = ENXIO;
@ -629,69 +629,13 @@ dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
return (dsp_io_ops(priv, buf));
}
static int
dsp_get_volume_channel(struct dsp_cdevpriv *priv, struct pcm_channel **volch)
{
struct snddev_info *d;
struct pcm_channel *c;
int unit;
KASSERT(volch != NULL,
("%s(): NULL query priv=%p volch=%p", __func__, priv, volch));
d = priv->sc;
if (!PCM_REGISTERED(d)) {
*volch = NULL;
return (EINVAL);
}
PCM_UNLOCKASSERT(d);
*volch = NULL;
c = priv->volch;
if (c != NULL) {
if (!(c->feederflags & (1 << FEEDER_VOLUME)))
return (-1);
*volch = c;
return (0);
}
PCM_LOCK(d);
PCM_WAIT(d);
PCM_ACQUIRE(d);
unit = dev2unit(d->dsp_dev);
CHN_FOREACH(c, d, channels.pcm) {
CHN_LOCK(c);
if (c->unit != unit) {
CHN_UNLOCK(c);
continue;
}
*volch = c;
pcm_chnref(c, 1);
priv->volch = c;
CHN_UNLOCK(c);
PCM_RELEASE(d);
PCM_UNLOCK(d);
return ((c->feederflags & (1 << FEEDER_VOLUME)) ? 0 : -1);
}
PCM_RELEASE(d);
PCM_UNLOCK(d);
return (EINVAL);
}
static int
dsp_ioctl_channel(struct dsp_cdevpriv *priv, struct pcm_channel *volch,
u_long cmd, caddr_t arg)
{
struct snddev_info *d;
struct pcm_channel *rdch, *wrch;
int j, devtype, ret;
int left, right, center, mute;
int j, left, right, center, mute;
d = priv->sc;
if (!PCM_REGISTERED(d) || !(pcm_getflags(d->dev) & SD_F_VPC))
@ -716,19 +660,6 @@ dsp_ioctl_channel(struct dsp_cdevpriv *priv, struct pcm_channel *volch,
volch = wrch;
}
devtype = PCMDEV(d->dsp_dev);
/* Look super harder */
if (volch == NULL &&
(devtype == SND_DEV_DSPHW_PLAY || devtype == SND_DEV_DSPHW_VPLAY ||
devtype == SND_DEV_DSPHW_REC || devtype == SND_DEV_DSPHW_VREC)) {
ret = dsp_get_volume_channel(priv, &volch);
if (ret != 0)
return (ret);
if (volch == NULL)
return (EINVAL);
}
/* Final validation */
if (volch == NULL)
return (EINVAL);
@ -2105,8 +2036,6 @@ dsp_sysinit(void *p)
{
if (dsp_ehtag != NULL)
return;
/* initialize unit numbering */
snd_unit_init();
dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
}
@ -2123,20 +2052,19 @@ SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
char *
dsp_unit2name(char *buf, size_t len, int unit)
dsp_unit2name(char *buf, size_t len, struct pcm_channel *ch)
{
int i, dtype;
int i;
KASSERT(buf != NULL && len != 0,
("bogus buf=%p len=%ju", buf, (uintmax_t)len));
dtype = snd_unit2d(unit);
for (i = 0; i < nitems(dsp_cdevs); i++) {
if (dtype != dsp_cdevs[i].type || dsp_cdevs[i].alias != NULL)
if (ch->type != dsp_cdevs[i].type || dsp_cdevs[i].alias != NULL)
continue;
snprintf(buf, len, "%s%d%s%d", dsp_cdevs[i].name,
snd_unit2u(unit), dsp_cdevs[i].sep, snd_unit2c(unit));
snprintf(buf, len, "%s%d%s%d",
dsp_cdevs[i].name, device_get_unit(ch->dev),
dsp_cdevs[i].sep, ch->unit);
return (buf);
}
@ -2224,12 +2152,10 @@ dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai)
if (devfs_foreach_cdevpriv(i_dev,
dsp_oss_audioinfo_cb, ch) != 0) {
devname = dsp_unit2name(buf,
sizeof(buf), ch->unit);
sizeof(buf), ch);
}
} else if (ai->dev == nchan) {
devname = dsp_unit2name(buf, sizeof(buf),
ch->unit);
}
} else if (ai->dev == nchan)
devname = dsp_unit2name(buf, sizeof(buf), ch);
if (devname != NULL)
break;
CHN_UNLOCK(ch);

View file

@ -35,7 +35,7 @@ extern struct cdevsw dsp_cdevsw;
int dsp_make_dev(device_t);
void dsp_destroy_dev(device_t);
char *dsp_unit2name(char *, size_t, int);
char *dsp_unit2name(char *, size_t, struct pcm_channel *);
int dsp_oss_audioinfo(struct cdev *, oss_audioinfo *);
#endif /* !_PCMDSP_H_ */

View file

@ -82,9 +82,7 @@ feeder_register(void *p)
if (snd_verbose < 0 || snd_verbose > 4)
snd_verbose = 1;
/* initialize unit numbering */
snd_unit_init();
if (snd_unit < 0 || snd_unit > PCMMAXUNIT)
if (snd_unit < 0)
snd_unit = -1;
if (snd_maxautovchans < 0 ||

View file

@ -727,7 +727,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
u_int16_t v;
struct cdev *pdev;
const char *name;
int i, unit, devunit, val;
int i, unit, val;
snddev = device_get_softc(dev);
if (snddev == NULL)
@ -764,8 +764,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
mixer_setrecsrc(m, 0); /* Set default input. */
devunit = snd_mkunit(unit, SND_DEV_CTL, 0);
pdev = make_dev(&mixer_cdevsw, devunit, UID_ROOT, GID_WHEEL, 0666,
pdev = make_dev(&mixer_cdevsw, SND_DEV_CTL, UID_ROOT, GID_WHEEL, 0666,
"mixer%d", unit);
pdev->si_drv1 = m;
snddev->mixer_dev = pdev;

View file

@ -244,98 +244,63 @@ pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
/* return error status and a locked channel */
int
pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
pid_t pid, char *comm, int devunit)
pid_t pid, char *comm)
{
struct pcm_channel *c;
int err, vchancount, vchan_num;
bool retry;
KASSERT(d != NULL && ch != NULL && (devunit == -1 ||
!(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) &&
KASSERT(d != NULL && ch != NULL &&
(direction == PCMDIR_PLAY || direction == PCMDIR_REC),
("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d",
__func__, d, ch, direction, pid, devunit));
("%s(): invalid d=%p ch=%p direction=%d pid=%d",
__func__, d, ch, direction, pid));
PCM_BUSYASSERT(d);
/* Double check again. */
if (devunit != -1) {
switch (snd_unit2d(devunit)) {
case SND_DEV_DSPHW_PLAY:
case SND_DEV_DSPHW_VPLAY:
if (direction != PCMDIR_PLAY)
return (ENOTSUP);
break;
case SND_DEV_DSPHW_REC:
case SND_DEV_DSPHW_VREC:
if (direction != PCMDIR_REC)
return (ENOTSUP);
break;
default:
if (!(direction == PCMDIR_PLAY ||
direction == PCMDIR_REC))
return (ENOTSUP);
break;
}
}
*ch = NULL;
vchan_num = 0;
vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount :
d->rvchancount;
retry = false;
retry_chnalloc:
err = ENOTSUP;
/* scan for a free channel */
CHN_FOREACH(c, d, channels.pcm) {
CHN_LOCK(c);
if (devunit == -1 && c->direction == direction &&
(c->flags & CHN_F_VIRTUAL)) {
if (c->direction == direction && (c->flags & CHN_F_VIRTUAL)) {
if (vchancount < snd_maxautovchans &&
vchan_num < CHN_CHAN(c)) {
vchan_num < c->unit) {
CHN_UNLOCK(c);
goto vchan_alloc;
}
vchan_num++;
}
if (c->direction == direction && !(c->flags & CHN_F_BUSY) &&
(devunit == -1 || devunit == -2 || c->unit == devunit)) {
if (c->direction == direction && !(c->flags & CHN_F_BUSY)) {
c->flags |= CHN_F_BUSY;
c->pid = pid;
strlcpy(c->comm, (comm != NULL) ? comm :
CHN_COMM_UNKNOWN, sizeof(c->comm));
*ch = c;
return (0);
} else if (c->unit == devunit) {
if (c->direction != direction)
err = ENOTSUP;
else if (c->flags & CHN_F_BUSY)
err = EBUSY;
else
err = EINVAL;
CHN_UNLOCK(c);
return (err);
} else if ((devunit == -1 || devunit == -2) &&
c->direction == direction && (c->flags & CHN_F_BUSY))
} else if (c->direction == direction && (c->flags & CHN_F_BUSY))
err = EBUSY;
CHN_UNLOCK(c);
}
if (devunit == -2)
/*
* We came from retry_chnalloc and still didn't find a free channel.
*/
if (retry)
return (err);
vchan_alloc:
/* no channel available */
if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY ||
snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) {
if (!(vchancount > 0 && vchancount < snd_maxautovchans) &&
(devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans))
return (err);
err = pcm_setvchans(d, direction, vchancount + 1,
(devunit == -1) ? -1 : snd_unit2c(devunit));
if (err == 0) {
if (devunit == -1)
devunit = -2;
goto retry_chnalloc;
}
if (!(vchancount > 0 && vchancount < snd_maxautovchans))
return (err);
err = pcm_setvchans(d, direction, vchancount + 1, -1);
if (err == 0) {
retry = true;
goto retry_chnalloc;
}
return (err);
@ -445,7 +410,7 @@ pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t c
{
struct pcm_channel *ch;
int direction, err, rpnum, *pnum, max;
int udc, device, chan;
int type, unit;
char *dirs, *devname, buf[CHN_NAMELEN];
PCM_BUSYASSERT(d);
@ -457,56 +422,54 @@ pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t c
dirs = "play";
direction = PCMDIR_PLAY;
pnum = &d->playcount;
device = SND_DEV_DSPHW_PLAY;
type = SND_DEV_DSPHW_PLAY;
max = SND_MAXHWCHAN;
break;
case PCMDIR_PLAY_VIRTUAL:
dirs = "virtual_play";
direction = PCMDIR_PLAY;
pnum = &d->pvchancount;
device = SND_DEV_DSPHW_VPLAY;
type = SND_DEV_DSPHW_VPLAY;
max = SND_MAXVCHANS;
break;
case PCMDIR_REC:
dirs = "record";
direction = PCMDIR_REC;
pnum = &d->reccount;
device = SND_DEV_DSPHW_REC;
type = SND_DEV_DSPHW_REC;
max = SND_MAXHWCHAN;
break;
case PCMDIR_REC_VIRTUAL:
dirs = "virtual_record";
direction = PCMDIR_REC;
pnum = &d->rvchancount;
device = SND_DEV_DSPHW_VREC;
type = SND_DEV_DSPHW_VREC;
max = SND_MAXVCHANS;
break;
default:
return (NULL);
}
chan = (num == -1) ? 0 : num;
unit = (num == -1) ? 0 : num;
if (*pnum >= max || chan >= max)
if (*pnum >= max || unit >= max)
return (NULL);
rpnum = 0;
CHN_FOREACH(ch, d, channels.pcm) {
if (CHN_DEV(ch) != device)
if (ch->type != type)
continue;
if (chan == CHN_CHAN(ch)) {
if (num != -1) {
device_printf(d->dev,
"channel num=%d allocated!\n", chan);
return (NULL);
}
chan++;
if (chan >= max) {
device_printf(d->dev,
"chan=%d > %d\n", chan, max);
return (NULL);
}
if (unit == ch->unit && num != -1) {
device_printf(d->dev,
"channel num=%d allocated!\n", unit);
return (NULL);
}
unit++;
if (unit >= max) {
device_printf(d->dev,
"chan=%d > %d\n", unit, max);
return (NULL);
}
rpnum++;
}
@ -518,25 +481,24 @@ pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t c
return (NULL);
}
udc = snd_mkunit(device_get_unit(d->dev), device, chan);
devname = dsp_unit2name(buf, sizeof(buf), udc);
if (devname == NULL) {
device_printf(d->dev,
"Failed to query device name udc=0x%08x\n", udc);
return (NULL);
}
PCM_UNLOCK(d);
ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
ch->unit = udc;
ch->type = type;
ch->unit = unit;
ch->pid = -1;
strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm));
ch->parentsnddev = d;
ch->parentchannel = parent;
ch->dev = d->dev;
ch->trigger = PCMTRIG_STOP;
devname = dsp_unit2name(buf, sizeof(buf), ch);
if (devname == NULL) {
device_printf(d->dev, "Failed to query device name");
kobj_delete(ch->methods, M_DEVBUF);
free(ch, M_DEVBUF);
return (NULL);
}
snprintf(ch->name, sizeof(ch->name), "%s:%s:%s",
device_get_nameunit(ch->dev), dirs, devname);
@ -585,7 +547,7 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
CHN_INSERT_SORT_ASCEND(d, ch, channels.pcm);
switch (CHN_DEV(ch)) {
switch (ch->type) {
case SND_DEV_DSPHW_PLAY:
d->playcount++;
break;
@ -625,7 +587,7 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
CHN_REMOVE(d, ch, channels.pcm);
switch (CHN_DEV(ch)) {
switch (ch->type) {
case SND_DEV_DSPHW_PLAY:
d->playcount--;
break;
@ -939,14 +901,6 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
return EINVAL;
}
if (device_get_unit(dev) > PCMMAXUNIT) {
device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n",
device_get_unit(dev), PCMMAXUNIT);
device_printf(dev,
"Use 'hw.snd.maxunit' tunable to raise the limit.\n");
return ENODEV;
}
d = device_get_softc(dev);
d->dev = dev;
d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");

View file

@ -88,7 +88,6 @@ struct snd_mixer;
#include <dev/sound/pcm/feeder.h>
#include <dev/sound/pcm/mixer.h>
#include <dev/sound/pcm/dsp.h>
#include <dev/sound/unit.h>
#define PCM_SOFTC_SIZE (sizeof(struct snddev_info))
@ -100,21 +99,6 @@ struct snd_mixer;
#define SOUND_PREFVER SOUND_MODVER
#define SOUND_MAXVER SOUND_MODVER
/*
* We're abusing the fact that MAXMINOR still have enough room
* for our bit twiddling and nobody ever need 512 unique soundcards,
* 32 unique device types and 1024 unique cloneable devices for the
* next 100 years...
*/
#define PCMMAXUNIT (snd_max_u())
#define PCMMAXDEV (snd_max_d())
#define PCMMAXCHAN (snd_max_c())
#define PCMUNIT(x) (snd_unit2u(dev2unit(x)))
#define PCMDEV(x) (snd_unit2d(dev2unit(x)))
#define PCMCHAN(x) (snd_unit2c(dev2unit(x)))
/*
* By design, limit possible channels for each direction.
*/
@ -311,7 +295,7 @@ SYSCTL_DECL(_hw_snd);
int pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num);
int pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
pid_t pid, char *comm, int devunit);
pid_t pid, char *comm);
int pcm_chnrelease(struct pcm_channel *c);
int pcm_chnref(struct pcm_channel *c, int ref);

View file

@ -923,7 +923,7 @@ vchan_sync(struct pcm_channel *c)
if (snd_passthrough_verbose != 0) {
char *devname, buf[CHN_NAMELEN];
devname = dsp_unit2name(buf, sizeof(buf), c->unit);
devname = dsp_unit2name(buf, sizeof(buf), c);
device_printf(c->dev,
"%s(%s/%s) %s() -> re-sync err=%d\n",
__func__, (devname != NULL) ? devname : "dspX", c->comm,

View file

@ -1,188 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#ifdef HAVE_KERNEL_OPTION_HEADERS
#include "opt_snd.h"
#endif
#include <dev/sound/unit.h>
/*
* Unit magic allocator for sound driver.
*
* 'u' = Unit of attached soundcards
* 'd' = Device type
* 'c' = Channel number
*
* eg: dsp0.p1 - u=0, d=p, c=1
* dsp1.vp0 - u=1, d=vp, c=0
*
* Maximum unit of soundcards can be tuned through "hw.snd.maxunit", which is
* between SND_UNIT_UMIN (16) and SND_UNIT_UMAX (2048). By design, the maximum
* allowable allocated channel is 256.
*/
/* Default width */
static int snd_u_shift = 9; /* 0 - 0x1ff : 512 distinct soundcards */
static int snd_d_shift = 5; /* 0 - 0x1f : 32 distinct device types */
static int snd_c_shift = 10; /* 0 - 0x3ff : 1024 distinct channels
(256 limit "by design") */
static int snd_unit_initialized = 0;
#ifdef SND_DIAGNOSTIC
#define SND_UNIT_ASSERT() do { \
if (snd_unit_initialized == 0) \
panic("%s(): Uninitialized sound unit!", __func__); \
} while (0)
#else
#define SND_UNIT_ASSERT() KASSERT(snd_unit_initialized != 0, \
("%s(): Uninitialized sound unit!", \
__func__))
#endif
#define MKMASK(x) ((1 << snd_##x##_shift) - 1)
int
snd_max_u(void)
{
SND_UNIT_ASSERT();
return (MKMASK(u));
}
int
snd_max_d(void)
{
SND_UNIT_ASSERT();
return (MKMASK(d));
}
int
snd_max_c(void)
{
SND_UNIT_ASSERT();
return (MKMASK(c));
}
int
snd_unit2u(int unit)
{
SND_UNIT_ASSERT();
return ((unit >> (snd_c_shift + snd_d_shift)) & MKMASK(u));
}
int
snd_unit2d(int unit)
{
SND_UNIT_ASSERT();
return ((unit >> snd_c_shift) & MKMASK(d));
}
int
snd_unit2c(int unit)
{
SND_UNIT_ASSERT();
return (unit & MKMASK(c));
}
int
snd_u2unit(int u)
{
SND_UNIT_ASSERT();
return ((u & MKMASK(u)) << (snd_c_shift + snd_d_shift));
}
int
snd_d2unit(int d)
{
SND_UNIT_ASSERT();
return ((d & MKMASK(d)) << snd_c_shift);
}
int
snd_c2unit(int c)
{
SND_UNIT_ASSERT();
return (c & MKMASK(c));
}
int
snd_mkunit(int u, int d, int c)
{
SND_UNIT_ASSERT();
return ((c & MKMASK(c)) | ((d & MKMASK(d)) << snd_c_shift) |
((u & MKMASK(u)) << (snd_c_shift + snd_d_shift)));
}
/*
* This *must* be called first before any of the functions above!!!
*/
void
snd_unit_init(void)
{
int i;
if (snd_unit_initialized != 0)
return;
snd_unit_initialized = 1;
if (getenv_int("hw.snd.maxunit", &i) != 0) {
if (i < SND_UNIT_UMIN)
i = SND_UNIT_UMIN;
else if (i > SND_UNIT_UMAX)
i = SND_UNIT_UMAX;
else
i = roundup2(i, 2);
for (snd_u_shift = 0; (i >> (snd_u_shift + 1)) != 0;
snd_u_shift++)
;
/* Make room for channels to fit within 24bit MAXMINOR limit. */
snd_c_shift = 24 - snd_u_shift - snd_d_shift;
}
if (bootverbose != 0)
printf("%s() u=0x%08x [%d] d=0x%08x [%d] c=0x%08x [%d]\n",
__func__, SND_U_MASK, snd_max_u() + 1,
SND_D_MASK, snd_max_d() + 1, SND_C_MASK, snd_max_c() + 1);
}

View file

@ -1,52 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SND_UNIT_H_
#define _SND_UNIT_H_
#define SND_UNIT_UMIN 16
#define SND_UNIT_UMAX 2048
int snd_max_u(void);
int snd_max_d(void);
int snd_max_c(void);
int snd_unit2u(int);
int snd_unit2d(int);
int snd_unit2c(int);
int snd_u2unit(int);
int snd_d2unit(int);
int snd_c2unit(int);
int snd_mkunit(int, int, int);
void snd_unit_init(void);
#define SND_U_MASK (snd_u2unit(snd_max_u()))
#define SND_D_MASK (snd_d2unit(snd_max_d()))
#define SND_C_MASK (snd_c2unit(snd_max_c()))
#endif /* !_SND_UNIT_H_ */

View file

@ -17,7 +17,7 @@ SRCS+= feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h
SRCS+= mpu_if.h mpufoi_if.h synth_if.h
SRCS+= mpu_if.c mpufoi_if.c synth_if.c
SRCS+= ac97.c ac97_patch.c buffer.c channel.c dsp.c
SRCS+= mixer.c sndstat.c sound.c unit.c vchan.c
SRCS+= mixer.c sndstat.c sound.c vchan.c
SRCS+= midi.c mpu401.c sequencer.c
feeder_eq_gen.h: ${SYSDIR}/tools/sound/feeder_eq_mkfilter.awk