Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/sound/pcm/sound.c
Show First 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) | ||||
flags |= INTR_TYPE_AV; | flags |= INTR_TYPE_AV; | ||||
d = device_get_softc(dev); | d = device_get_softc(dev); | ||||
if (d != NULL && (flags & INTR_MPSAFE)) | if (d != NULL && (flags & INTR_MPSAFE)) | ||||
d->flags |= SD_F_MPSAFE; | d->flags |= SD_F_MPSAFE; | ||||
return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); | return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); | ||||
} | } | ||||
int | |||||
pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, | |||||
pid_t pid, char *comm) | |||||
{ | |||||
struct pcm_channel *c; | |||||
int err, vchancount; | |||||
bool retry; | |||||
KASSERT(d != NULL && ch != NULL && | |||||
(direction == PCMDIR_PLAY || direction == PCMDIR_REC), | |||||
("%s(): invalid d=%p ch=%p direction=%d pid=%d", | |||||
__func__, d, ch, direction, pid)); | |||||
PCM_BUSYASSERT(d); | |||||
*ch = NULL; | |||||
vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount : | |||||
d->rvchancount; | |||||
retry = false; | |||||
retry_chnalloc: | |||||
/* Scan for a free channel. */ | |||||
CHN_FOREACH(c, d, channels.pcm) { | |||||
CHN_LOCK(c); | |||||
if (c->direction != direction) { | |||||
CHN_UNLOCK(c); | |||||
continue; | |||||
} | |||||
if (!(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); | |||||
} | |||||
CHN_UNLOCK(c); | |||||
} | |||||
/* Maybe next time... */ | |||||
if (retry) | |||||
return (EBUSY); | |||||
/* No channel available. We also cannot create more VCHANs. */ | |||||
if (!(vchancount > 0 && vchancount < snd_maxautovchans)) | |||||
return (ENOTSUP); | |||||
/* Increase the VCHAN count and try to get the new channel. */ | |||||
err = vchan_setnew(d, direction, vchancount + 1); | |||||
if (err == 0) { | |||||
retry = true; | |||||
goto retry_chnalloc; | |||||
} | |||||
return (err); | |||||
} | |||||
static int | static int | ||||
sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) | sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct snddev_info *d; | struct snddev_info *d; | ||||
int error, unit; | int error, unit; | ||||
unit = snd_unit; | unit = snd_unit; | ||||
error = sysctl_handle_int(oidp, &unit, 0, req); | error = sysctl_handle_int(oidp, &unit, 0, req); | ||||
if (error == 0 && req->newptr != NULL) { | if (error == 0 && req->newptr != NULL) { | ||||
d = devclass_get_softc(pcm_devclass, unit); | d = devclass_get_softc(pcm_devclass, unit); | ||||
if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) | if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) | ||||
return EINVAL; | return EINVAL; | ||||
snd_unit = unit; | snd_unit = unit; | ||||
snd_unit_auto = 0; | snd_unit_auto = 0; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* XXX: do we need a way to let the user change the default unit? */ | /* XXX: do we need a way to let the user change the default unit? */ | ||||
SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, | SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, | ||||
CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_NEEDGIANT, 0, | CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_NEEDGIANT, 0, | ||||
sizeof(int), sysctl_hw_snd_default_unit, "I", | sizeof(int), sysctl_hw_snd_default_unit, "I", | ||||
"default sound device"); | "default sound device"); | ||||
/* | |||||
* Create a primary channel. | |||||
*/ | |||||
int | int | ||||
pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) | pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) | ||||
{ | { | ||||
struct snddev_info *d = device_get_softc(dev); | struct snddev_info *d = device_get_softc(dev); | ||||
struct pcm_channel *ch; | struct pcm_channel *ch; | ||||
PCM_BUSYASSERT(d); | PCM_BUSYASSERT(d); | ||||
PCM_LOCK(d); | PCM_LOCK(d); | ||||
ch = chn_init(d, NULL, cls, dir, devinfo); | ch = chn_init(d, NULL, cls, dir, devinfo); | ||||
if (!ch) { | if (!ch) { | ||||
device_printf(d->dev, "chn_init(%s, %d, %p) failed\n", | device_printf(d->dev, "chn_init(%s, %d, %p) failed\n", | ||||
cls->name, dir, devinfo); | cls->name, dir, devinfo); | ||||
PCM_UNLOCK(d); | PCM_UNLOCK(d); | ||||
return (ENODEV); | return (ENODEV); | ||||
} | } | ||||
/* | |||||
* Adapt the vchan rates to the drivers' selected rate, instead of | |||||
* hardcoding a possibly unsupported value. | |||||
*/ | |||||
if (dir == PCMDIR_PLAY) | |||||
d->pvchanrate = sndbuf_getspd(ch->bufhard); | |||||
else if (dir == PCMDIR_REC) | |||||
d->rvchanrate = sndbuf_getspd(ch->bufhard); | |||||
PCM_UNLOCK(d); | PCM_UNLOCK(d); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pcm_killchans(struct snddev_info *d) | pcm_killchans(struct snddev_info *d) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 254 Lines • ▼ Show 20 Lines | pcm_init(device_t dev, void *devinfo) | ||||
d->p_unr = new_unrhdr(0, INT_MAX, NULL); | d->p_unr = new_unrhdr(0, INT_MAX, NULL); | ||||
d->vp_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->r_unr = new_unrhdr(0, INT_MAX, NULL); | ||||
d->vr_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); | ||||
CHN_INIT(d, channels.pcm.busy); | CHN_INIT(d, channels.pcm.busy); | ||||
CHN_INIT(d, channels.pcm.opened); | CHN_INIT(d, channels.pcm.opened); | ||||
CHN_INIT(d, channels.pcm.primary); | |||||
} | } | ||||
int | int | ||||
pcm_register(device_t dev, char *str) | pcm_register(device_t dev, char *str) | ||||
{ | { | ||||
struct snddev_info *d = device_get_softc(dev); | struct snddev_info *d = device_get_softc(dev); | ||||
/* should only be called once */ | /* should only be called once */ | ||||
if (d->flags & SD_F_REGISTERED) | if (d->flags & SD_F_REGISTERED) | ||||
return (EINVAL); | return (EINVAL); | ||||
PCM_BUSYASSERT(d); | PCM_BUSYASSERT(d); | ||||
if (d->playcount == 0 || d->reccount == 0) | if (d->playcount == 0 || d->reccount == 0) | ||||
d->flags |= SD_F_SIMPLEX; | d->flags |= SD_F_SIMPLEX; | ||||
if (d->playcount > 0 || d->reccount > 0) | if (d->playcount > 0 || d->reccount > 0) | ||||
d->flags |= SD_F_AUTOVCHAN; | d->flags |= SD_F_AUTOVCHAN; | ||||
vchan_setmaxauto(d, snd_maxautovchans); | if (d->playcount > 0) | ||||
d->flags |= SD_F_PVCHANS; | |||||
if (d->reccount > 0) | |||||
d->flags |= SD_F_RVCHANS; | |||||
strlcpy(d->status, str, SND_STATUSLEN); | strlcpy(d->status, str, SND_STATUSLEN); | ||||
sndstat_register(dev, d->status); | sndstat_register(dev, d->status); | ||||
PCM_LOCK(d); | PCM_LOCK(d); | ||||
/* Done, we're ready.. */ | /* Done, we're ready.. */ | ||||
d->flags |= SD_F_REGISTERED; | d->flags |= SD_F_REGISTERED; | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | |||||
sound_global_init(void) | sound_global_init(void) | ||||
{ | { | ||||
if (snd_verbose < 0 || snd_verbose > 4) | if (snd_verbose < 0 || snd_verbose > 4) | ||||
snd_verbose = 1; | snd_verbose = 1; | ||||
if (snd_unit < 0) | if (snd_unit < 0) | ||||
snd_unit = -1; | snd_unit = -1; | ||||
if (snd_maxautovchans < 0 || | snd_vchans_enable = true; | ||||
snd_maxautovchans > SND_MAXVCHANS) | |||||
snd_maxautovchans = 0; | |||||
if (chn_latency < CHN_LATENCY_MIN || | if (chn_latency < CHN_LATENCY_MIN || | ||||
chn_latency > CHN_LATENCY_MAX) | chn_latency > CHN_LATENCY_MAX) | ||||
chn_latency = CHN_LATENCY_DEFAULT; | chn_latency = CHN_LATENCY_DEFAULT; | ||||
if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || | if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || | ||||
chn_latency_profile > CHN_LATENCY_PROFILE_MAX) | chn_latency_profile > CHN_LATENCY_PROFILE_MAX) | ||||
chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; | chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; | ||||
if (feeder_rate_min < FEEDRATE_MIN || | if (feeder_rate_min < FEEDRATE_MIN || | ||||
feeder_rate_max < FEEDRATE_MIN || | feeder_rate_max < FEEDRATE_MIN || | ||||
feeder_rate_min > FEEDRATE_MAX || | feeder_rate_min > FEEDRATE_MAX || | ||||
feeder_rate_max > FEEDRATE_MAX || | feeder_rate_max > FEEDRATE_MAX || | ||||
!(feeder_rate_min < feeder_rate_max)) { | !(feeder_rate_min < feeder_rate_max)) { | ||||
feeder_rate_min = FEEDRATE_RATEMIN; | feeder_rate_min = FEEDRATE_RATEMIN; | ||||
feeder_rate_max = FEEDRATE_RATEMAX; | feeder_rate_max = FEEDRATE_RATEMAX; | ||||
} | } | ||||
if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || | if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || | ||||
feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) | feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) | ||||
feeder_rate_round = FEEDRATE_ROUNDHZ; | feeder_rate_round = FEEDRATE_ROUNDHZ; | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("%s: snd_unit=%d snd_maxautovchans=%d " | printf("%s: snd_unit=%d snd_vchans_enable=%d " | ||||
"latency=%d " | "latency=%d " | ||||
"feeder_rate_min=%d feeder_rate_max=%d " | "feeder_rate_min=%d feeder_rate_max=%d " | ||||
"feeder_rate_round=%d\n", | "feeder_rate_round=%d\n", | ||||
__func__, snd_unit, snd_maxautovchans, | __func__, snd_unit, snd_vchans_enable, | ||||
chn_latency, | chn_latency, | ||||
feeder_rate_min, feeder_rate_max, | feeder_rate_min, feeder_rate_max, | ||||
feeder_rate_round); | feeder_rate_round); | ||||
} | } | ||||
static int | static int | ||||
sound_modevent(module_t mod, int type, void *data) | sound_modevent(module_t mod, int type, void *data) | ||||
{ | { | ||||
Show All 26 Lines |