Add code from Kazuhito HONDA that allows the user to see

the available modes in /dev/sndstat.
e.g.
pcm1: <USB Audio> at addr ? (0p/1r/0v channels duplex)
        mode 1:(input) 1ch, 16/16bit, pcm, 44100Hz
	mode 2:(input) 1ch, 16/16bit, pcm, 22050Hz
	mode 3:(input) 1ch, 16/16bit, pcm, 11025Hz
	mode 4:(input) 1ch, 16/16bit, pcm, 8000Hz
This commit is contained in:
Julian Elischer 2005-04-27 17:16:27 +00:00
parent 4104e6bc1d
commit 7f05203a38
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=145599
3 changed files with 157 additions and 0 deletions

View File

@ -72,6 +72,7 @@ __KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $");
#include <sys/poll.h>
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <sys/sbuf.h>
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
@ -83,6 +84,7 @@ __KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $");
#elif defined(__FreeBSD__)
#include <dev/sound/pcm/sound.h> /* XXXXX */
#include <dev/sound/chip.h>
#include "feeder_if.h"
#endif
#include <dev/usb/usb.h>
@ -234,6 +236,10 @@ struct uaudio_softc {
int sc_nctls; /* # of mixer controls */
device_ptr_t sc_audiodev;
char sc_dying;
#if defined(__FreeBSD__)
struct sbuf uaudio_sndstat;
int uaudio_sndstat_flag;
#endif
};
struct terminal_list {
@ -444,6 +450,7 @@ Static struct audio_device uaudio_device = {
#elif defined(__FreeBSD__)
Static int audio_attach_mi(device_t);
Static int uaudio_init_params(struct uaudio_softc * sc, struct chan *ch, int mode);
static int uaudio_sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose);
/* for NetBSD compatibirity */
#define AUMODE_PLAY 0x01
@ -642,6 +649,9 @@ USB_DETACH(uaudio)
{
USB_DETACH_START(uaudio, sc);
sbuf_delete(&(sc->uaudio_sndstat));
sc->uaudio_sndstat_flag = 0;
sc->sc_dying = 1;
#if 0 /* XXX */
@ -1894,6 +1904,7 @@ uaudio_process_as(struct uaudio_softc *sc, const char *buf, int *offsp,
const char *format_str;
asid = (const void *)(buf + offs);
if (asid->bDescriptorType != UDESC_CS_INTERFACE ||
asid->bDescriptorSubtype != AS_GENERAL)
return (USBD_INVAL);
@ -2067,6 +2078,28 @@ uaudio_process_as(struct uaudio_softc *sc, const char *buf, int *offsp,
printf(",%d", UA_GETSAMP(asf1d, r));
printf("Hz\n");
}
#endif
#if defined(__FreeBSD__)
if (sc->uaudio_sndstat_flag != 0) {
sbuf_printf(&(sc->uaudio_sndstat), "\n\t");
sbuf_printf(&(sc->uaudio_sndstat),
"mode %d:(%s) %dch, %d/%dbit, %s,",
id->bAlternateSetting,
dir == UE_DIR_IN ? "input" : "output",
chan, prec, asf1d->bSubFrameSize * 8, format_str);
if (asf1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
sbuf_printf(&(sc->uaudio_sndstat), " %d-%dHz",
UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
} else {
int r;
sbuf_printf(&(sc->uaudio_sndstat),
" %d", UA_GETSAMP(asf1d, 0));
for (r = 1; r < asf1d->bSamFreqType; r++)
sbuf_printf(&(sc->uaudio_sndstat),
",%d", UA_GETSAMP(asf1d, r));
sbuf_printf(&(sc->uaudio_sndstat), "Hz");
}
}
#endif
ai.alt = id->bAlternateSetting;
ai.encoding = enc;
@ -2106,6 +2139,11 @@ uaudio_identify_as(struct uaudio_softc *sc,
if (id == NULL)
return (USBD_INVAL);
#if defined(__FreeBSD__)
sc->uaudio_sndstat_flag = 0;
if (sbuf_new(&(sc->uaudio_sndstat), NULL, 4096, SBUF_AUTOEXTEND) != NULL)
sc->uaudio_sndstat_flag = 1;
#endif
/* Loop through all the alternate settings. */
while (offs <= size) {
DPRINTFN(2, ("uaudio_identify: interface=%d offset=%d\n",
@ -2132,6 +2170,9 @@ uaudio_identify_as(struct uaudio_softc *sc,
if (id == NULL)
break;
}
#if defined(__FreeBSD__)
sbuf_finish(&(sc->uaudio_sndstat));
#endif
if (offs > size)
return (USBD_INVAL);
DPRINTF(("uaudio_identify_as: %d alts available\n", sc->sc_nalts));
@ -4171,6 +4212,118 @@ uaudio_mixer_setrecsrc(device_t dev, u_int32_t src)
return (1 << mc->slctrtype[mc->minval - 1]);
}
static int
uaudio_sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
{
struct snddev_info *d;
struct snddev_channel *sce;
struct pcm_channel *c;
struct pcm_feeder *f;
int pc, rc, vc;
device_t pa_dev = device_get_parent(dev);
struct uaudio_softc *sc = device_get_softc(pa_dev);
if (verbose < 1)
return 0;
d = device_get_softc(dev);
if (!d)
return ENXIO;
snd_mtxlock(d->lock);
if (SLIST_EMPTY(&d->channels)) {
sbuf_printf(s, " (mixer only)");
snd_mtxunlock(d->lock);
return 0;
}
pc = rc = vc = 0;
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
if (c->direction == PCMDIR_PLAY) {
if (c->flags & CHN_F_VIRTUAL)
vc++;
else
pc++;
} else
rc++;
}
sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)",
d->playcount, d->reccount, d->vchancount,
(d->flags & SD_F_SIMPLEX)? "" : " duplex",
#ifdef USING_DEVFS
(device_get_unit(dev) == snd_unit)? " default" : ""
#else
""
#endif
);
if (sc->uaudio_sndstat_flag != 0) {
sbuf_cat(s, sbuf_data(&(sc->uaudio_sndstat)));
}
if (verbose <= 1) {
snd_mtxunlock(d->lock);
return 0;
}
SLIST_FOREACH(sce, &d->channels, link) {
c = sce->channel;
sbuf_printf(s, "\n\t");
/* it would be better to indent child channels */
sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name);
sbuf_printf(s, "spd %d", c->speed);
if (c->speed != sndbuf_getspd(c->bufhard))
sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard));
sbuf_printf(s, ", fmt 0x%08x", c->format);
if (c->format != sndbuf_getfmt(c->bufhard))
sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard));
sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags);
if (c->pid != -1)
sbuf_printf(s, ", pid %d", c->pid);
sbuf_printf(s, "\n\t");
if (c->bufhard != NULL && c->bufsoft != NULL) {
sbuf_printf(s, "interrupts %d, ", c->interrupts);
if (c->direction == PCMDIR_REC)
sbuf_printf(s, "overruns %d, hfree %d, sfree %d",
c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft));
else
sbuf_printf(s, "underruns %d, ready %d",
c->xruns, sndbuf_getready(c->bufsoft));
sbuf_printf(s, "\n\t");
}
sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland");
sbuf_printf(s, " -> ");
f = c->feeder;
while (f->source != NULL)
f = f->source;
while (f != NULL) {
sbuf_printf(s, "%s", f->class->name);
if (f->desc->type == FEEDER_FMT)
sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
if (f->desc->type == FEEDER_RATE)
sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER)
sbuf_printf(s, "(0x%08x)", f->desc->out);
sbuf_printf(s, " -> ");
f = f->parent;
}
sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware");
}
snd_mtxunlock(d->lock);
return 0;
}
void
uaudio_sndstat_register(device_t dev)
{
struct snddev_info *d = device_get_softc(dev);
sndstat_register(dev, d->status, uaudio_sndstat_prepare_pcm);
}
Static int
audio_attach_mi(device_t dev)
{

View File

@ -50,3 +50,4 @@ u_int32_t uaudio_mixer_setrecsrc(device_t dev, u_int32_t src);
u_int32_t uaudio_query_mix_info(device_t dev);
u_int32_t uaudio_query_recsrc_info(device_t dev);
void uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt);
void uaudio_sndstat_register(device_t dev);

View File

@ -344,6 +344,9 @@ ua_attach(device_t dev)
return(ENXIO);
}
sndstat_unregister(dev);
uaudio_sndstat_register(dev);
pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
#ifndef NO_RECORDING
pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);