mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
sound: Use unr(9) to produce unique channel unit numbers
Currently it is possible to assign a unit number that already exists. Suppose the following channel list: [vp2] If we create 3 channels, we'll end up with the following list: [vp0, vp1, vp2, vp2] This happens because chn_init() does not check if the unit number we are assigning already exists. While fixing this is trivial when the channel list is sorted in ascending order, it is way more involved when sorted in descending order. Even though sorting the list in descending order would require deliberately modifying pcm_chn_add(), and is most likely not going to happen, make the mechanism more robust by using a unr(9) allocator for each channel type. Sponsored by: The FreeBSD Foundation MFC after: 2 days Reviewed by: dev_submerge.ch Differential Revision: https://reviews.freebsd.org/D46680 (cherry picked from commit ad4c8671bddaa30bf0413089c74dde6a618d9021)
This commit is contained in:
parent
30a64793aa
commit
463eafcff9
3 changed files with 38 additions and 9 deletions
|
|
@ -1157,6 +1157,24 @@ chn_reset(struct pcm_channel *c, uint32_t fmt, uint32_t spd)
|
|||
return r;
|
||||
}
|
||||
|
||||
static struct unrhdr *
|
||||
chn_getunr(struct snddev_info *d, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case SND_DEV_DSPHW_PLAY:
|
||||
return (d->p_unr);
|
||||
case SND_DEV_DSPHW_VPLAY:
|
||||
return (d->vp_unr);
|
||||
case SND_DEV_DSPHW_REC:
|
||||
return (d->r_unr);
|
||||
case SND_DEV_DSPHW_VREC:
|
||||
return (d->vr_unr);
|
||||
default:
|
||||
__assert_unreachable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct pcm_channel *
|
||||
chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
|
||||
int dir, void *devinfo)
|
||||
|
|
@ -1165,7 +1183,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
|
|||
struct feeder_class *fc;
|
||||
struct snd_dbuf *b, *bs;
|
||||
char *dirs, buf[CHN_NAMELEN];
|
||||
int i, direction, type, unit;
|
||||
int i, direction, type;
|
||||
|
||||
PCM_BUSYASSERT(d);
|
||||
PCM_LOCKASSERT(d);
|
||||
|
|
@ -1198,13 +1216,6 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
unit = 0;
|
||||
CHN_FOREACH(c, d, channels.pcm) {
|
||||
if (c->type != type)
|
||||
continue;
|
||||
unit++;
|
||||
}
|
||||
|
||||
PCM_UNLOCK(d);
|
||||
b = NULL;
|
||||
bs = NULL;
|
||||
|
|
@ -1216,7 +1227,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
|
|||
CHN_INIT(c, children.busy);
|
||||
c->direction = direction;
|
||||
c->type = type;
|
||||
c->unit = unit;
|
||||
c->unit = alloc_unr(chn_getunr(d, c->type));
|
||||
c->format = SND_FORMAT(AFMT_U8, 1, 0);
|
||||
c->speed = DSP_DEFAULT_SPEED;
|
||||
c->pid = -1;
|
||||
|
|
@ -1304,6 +1315,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
|
|||
return (c);
|
||||
|
||||
fail:
|
||||
free_unr(chn_getunr(d, c->type), c->unit);
|
||||
feeder_remove(c);
|
||||
if (c->devinfo && CHANNEL_FREE(c->methods, c->devinfo))
|
||||
sndbuf_free(b);
|
||||
|
|
@ -1335,6 +1347,7 @@ chn_kill(struct pcm_channel *c)
|
|||
chn_trigger(c, PCMTRIG_ABORT);
|
||||
CHN_UNLOCK(c);
|
||||
}
|
||||
free_unr(chn_getunr(c->parentsnddev, c->type), c->unit);
|
||||
feeder_remove(c);
|
||||
if (CHANNEL_FREE(c->methods, c->devinfo))
|
||||
sndbuf_free(b);
|
||||
|
|
|
|||
|
|
@ -568,6 +568,10 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
|
|||
d->pvchanformat = 0;
|
||||
d->rvchanrate = 0;
|
||||
d->rvchanformat = 0;
|
||||
d->p_unr = new_unrhdr(0, INT_MAX, NULL);
|
||||
d->vp_unr = new_unrhdr(0, INT_MAX, NULL);
|
||||
d->r_unr = new_unrhdr(0, INT_MAX, NULL);
|
||||
d->vr_unr = new_unrhdr(0, INT_MAX, NULL);
|
||||
|
||||
CHN_INIT(d, channels.pcm);
|
||||
CHN_INIT(d, channels.pcm.busy);
|
||||
|
|
@ -653,6 +657,14 @@ pcm_unregister(device_t dev)
|
|||
cv_destroy(&d->cv);
|
||||
PCM_UNLOCK(d);
|
||||
snd_mtxfree(d->lock);
|
||||
if (d->p_unr != NULL)
|
||||
delete_unrhdr(d->p_unr);
|
||||
if (d->vp_unr != NULL)
|
||||
delete_unrhdr(d->vp_unr);
|
||||
if (d->r_unr != NULL)
|
||||
delete_unrhdr(d->r_unr);
|
||||
if (d->vr_unr != NULL)
|
||||
delete_unrhdr(d->vr_unr);
|
||||
|
||||
if (snd_unit == device_get_unit(dev)) {
|
||||
snd_unit = pcm_best_unit(-1);
|
||||
|
|
|
|||
|
|
@ -325,6 +325,10 @@ struct snddev_info {
|
|||
struct sysctl_ctx_list play_sysctl_ctx, rec_sysctl_ctx;
|
||||
struct sysctl_oid *play_sysctl_tree, *rec_sysctl_tree;
|
||||
struct cv cv;
|
||||
struct unrhdr *p_unr;
|
||||
struct unrhdr *vp_unr;
|
||||
struct unrhdr *r_unr;
|
||||
struct unrhdr *vr_unr;
|
||||
};
|
||||
|
||||
void sound_oss_sysinfo(oss_sysinfo *);
|
||||
|
|
|
|||
Loading…
Reference in a new issue