[Fwd: please test uaudio capabilities patch]
Julian Elischer
julian at elischer.org
Sun Apr 17 23:06:47 PDT 2005
mat says he can't send this to the list and asked for me to forward it.
FWIW the patch breaks my USB microphone.
-------- Original Message --------
Subject: please test uaudio capabilities patch
Date: Sun, 17 Apr 2005 13:20:14 -0400
From: Mathew Kanner <mat at cnd.mcgill.ca>
Organization: I speak for myself, operating in Montreal, CANADA
To: freebsd-multimedia at freebsd.org
CC: Julian Elischer <julian at elischer.org>
Hi All,
The following patch changes the driver to probe the
capabilities. With this patch I can run mplayer with a non-native
speed or format and the internal soft-mixer will get the right
chain. Without the patch, I get stuck and I have to disconnect.
I'm going to commit this soon. This is is against HEAD post my
commit to de-dma the driver.
--Mat
-------------- next part --------------
Index: uaudio.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/usb/uaudio.c,v
retrieving revision 1.13
diff -u -r1.13 uaudio.c
--- uaudio.c 6 Jan 2005 01:43:22 -0000 1.13
+++ uaudio.c 17 Apr 2005 17:11:05 -0000
@@ -3764,83 +3764,127 @@
return (0);
}
-void
-uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt)
-{
- int i, pn=0, rn=0;
- int prec, dir;
+struct uaudio_convesion {
+ uint8_t uaudio_fmt;
+ uint8_t uaudio_prec;
+ uint32_t freebsd_fmt;
+};
+
+const struct uaudio_convesion const accepted_conversion[] = {
+ {AUDIO_ENCODING_ULINEAR_LE, 8, AFMT_U8},
+ {AUDIO_ENCODING_ULINEAR_LE, 16, AFMT_U16_LE},
+ {AUDIO_ENCODING_SLINEAR_LE, 8, AFMT_S8},
+ {AUDIO_ENCODING_SLINEAR_LE, 16, AFMT_S16_LE},
+ {AUDIO_ENCODING_SLINEAR_BE, 16, AFMT_S16_BE},
+ {AUDIO_ENCODING_ALAW, 8, AFMT_A_LAW},
+ {AUDIO_ENCODING_ULAW, 8, AFMT_MU_LAW},
+ {0,0,0}
+};
+
+unsigned
+uaudio_query_formats(device_t dev, int reqdir, unsigned maxfmt, struct pcmchan_caps *cap)
+{
+ struct uaudio_softc *sc = device_get_softc(dev);
+ const struct usb_audio_streaming_type1_descriptor *asf1d;
+ const struct uaudio_convesion *iterator;
+ unsigned fmtcount, foundcount;
u_int32_t fmt;
- struct uaudio_softc *sc;
+ uint8_t format, numchan, subframesize, prec, dir, iscontinuous;
+ int freq, freq_min, freq_max;
+ char *numchannel_descr;
+ char freq_descr[64];
+ int i,r;
- const struct usb_audio_streaming_type1_descriptor *a1d;
+ if ( sc == NULL )
+ return 0;
- sc = device_get_softc(dev);
+ cap->minspeed = cap->maxspeed = 0;
+ foundcount = fmtcount = 0;
for (i = 0; i < sc->sc_nalts; i++) {
- fmt = 0;
- a1d = sc->sc_alts[i].asf1desc;
- prec = a1d->bBitResolution; /* precision */
-
- switch (sc->sc_alts[i].encoding) {
- case AUDIO_ENCODING_ULINEAR_LE:
- if (prec == 8) {
- fmt = AFMT_U8;
- } else if (prec == 16) {
- fmt = AFMT_U16_LE;
- }
- break;
- case AUDIO_ENCODING_SLINEAR_LE:
- if (prec == 8) {
- fmt = AFMT_S8;
- } else if (prec == 16) {
- fmt = AFMT_S16_LE;
- }
- break;
- case AUDIO_ENCODING_ULINEAR_BE:
- if (prec == 16) {
- fmt = AFMT_U16_BE;
- }
- break;
- case AUDIO_ENCODING_SLINEAR_BE:
- if (prec == 16) {
- fmt = AFMT_S16_BE;
- }
- break;
- case AUDIO_ENCODING_ALAW:
- if (prec == 8) {
- fmt = AFMT_A_LAW;
- }
- break;
- case AUDIO_ENCODING_ULAW:
- if (prec == 8) {
- fmt = AFMT_MU_LAW;
- }
- break;
- }
+ dir = UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
- if (fmt != 0) {
- if (a1d->bNrChannels == 2) { /* stereo/mono */
- fmt |= AFMT_STEREO;
- } else if (a1d->bNrChannels != 1) {
- fmt = 0;
- }
+ if ( (dir == UE_DIR_OUT) != (reqdir == PCMDIR_PLAY) )
+ continue;
+
+ asf1d = sc->sc_alts[i].asf1desc;
+ format = sc->sc_alts[i].encoding;
+
+ numchan = asf1d->bNrChannels;
+ subframesize = asf1d->bSubFrameSize;
+ prec = asf1d->bBitResolution; /* precision */
+ iscontinuous = asf1d->bSamFreqType == UA_SAMP_CONTNUOUS;
+
+ if (iscontinuous)
+ snprintf(freq_descr, 64, "continous min %d max %d", UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
+ else
+ snprintf(freq_descr, 64, "fixed frequency (%d listed formats)", asf1d->bSamFreqType);
+
+ if ( numchan == 1)
+ numchannel_descr = " (mono)";
+ else if ( numchan == 2 )
+ numchannel_descr = " (stereo)";
+ else
+ numchannel_descr = "";
+
+ if (bootverbose) {
+ device_printf( dev, "uaudio_query_formats: found a native %s channel%s %s %dbit %dbytes/subframe X %d channels = %d bytes per sample\n",
+ (dir==UE_DIR_OUT)?"playback":"record",
+ numchannel_descr, freq_descr,
+ prec, subframesize, numchan, subframesize*numchan);
}
+ /*
+ * Now start rejecting the ones that don't map to FreeBSD
+ */
+
+ if (numchan != 1 && numchan != 2)
+ continue;
+
+ for ( iterator = accepted_conversion ; iterator->uaudio_fmt != 0 ; iterator++ )
+ if ( iterator->uaudio_fmt == format && iterator->uaudio_prec == prec )
+ break;
- if (fmt != 0) {
- dir= UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
- if (dir == UE_DIR_OUT) {
- pfmt[pn++] = fmt;
- } else if (dir == UE_DIR_IN) {
- rfmt[rn++] = fmt;
+ if ( iterator->uaudio_fmt == 0 )
+ continue;
+
+ fmt = iterator->freebsd_fmt;
+
+ if (asf1d->bNrChannels == 2)
+ fmt |= AFMT_STEREO;
+
+ if ( numchan != 1 && numchan == 2 )
+
+ foundcount++;
+
+ if (fmtcount >= maxfmt )
+ continue;
+
+ cap->fmtlist[fmtcount++] = fmt;
+
+ if (iscontinuous) {
+ freq_min = UA_SAMP_LO(asf1d);
+ freq_max = UA_SAMP_HI(asf1d);
+
+ if ( cap->minspeed == 0 || freq_min < cap->minspeed )
+ cap->minspeed = freq_min;
+ if ( cap->maxspeed == 0 )
+ cap->maxspeed = cap->minspeed;
+ if ( freq_max > cap->maxspeed )
+ cap->maxspeed = freq_max;
+ } else {
+ for (r = 0; r < asf1d->bSamFreqType; r++) {
+ freq = UA_GETSAMP(asf1d, r);
+ if (cap->minspeed == 0 || freq < cap->minspeed)
+ cap->minspeed = freq;
+ if (cap->maxspeed == 0)
+ cap->maxspeed = cap->minspeed;
+ if (freq > cap->maxspeed)
+ cap->maxspeed = freq;
}
}
-
- if ((pn > 8*2) || (rn > 8*2))
- break;
}
- pfmt[pn] = 0;
- rfmt[rn] = 0;
- return;
+ cap->fmtlist[fmtcount] = 0;
+ return foundcount;
}
void
@@ -3889,25 +3933,53 @@
return;
}
-void
-uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir)
+int
+uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int reqdir)
{
+ const struct uaudio_convesion *iterator;
struct uaudio_softc *sc;
struct chan *ch;
+ int i, r;
sc = device_get_softc(dev);
#ifndef NO_RECORDING
- if (dir == PCMDIR_PLAY)
+ if (reqdir == PCMDIR_PLAY)
ch = &sc->sc_playchan;
else
ch = &sc->sc_recchan;
#else
ch = &sc->sc_playchan;
#endif
+ /*
+ * We are successful if we find an endpoint that matches our selected format and it
+ * supports the requested speed.
+ */
+ for (i = 0; i < sc->sc_nalts; i++) {
+ int dir = UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
+ int format = sc->sc_alts[i].encoding;
+ const struct usb_audio_streaming_type1_descriptor *asf1d = sc->sc_alts[i].asf1desc;
+ int iscontinuous = asf1d->bSamFreqType == UA_SAMP_CONTNUOUS;
+
+ if ( (dir == UE_DIR_OUT) != (reqdir == PCMDIR_PLAY) )
+ continue;
- ch->sample_rate = speed;
+ for ( iterator = accepted_conversion ; iterator->uaudio_fmt != 0 ; iterator++ )
+ if ( iterator->uaudio_fmt == format && iterator->freebsd_fmt == (ch->format&0xfffffff) ) {
+ if (iscontinuous) {
+ if ( speed >= UA_SAMP_LO(asf1d) && speed <= UA_SAMP_HI(asf1d)) {
+ ch->sample_rate = speed;
+ return 1;
+ }
+ } else
+ for (r = 0; r < asf1d->bSamFreqType; r++)
+ if ( speed == UA_GETSAMP(asf1d, r) ) {
+ ch->sample_rate = speed;
+ return 1;
+ }
+ }
+ }
- return;
+ return 0;
}
int
Index: uaudio.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/usb/uaudio.h,v
retrieving revision 1.5
diff -u -r1.5 uaudio.h
--- uaudio.h 6 Jan 2005 01:43:22 -0000 1.5
+++ uaudio.h 17 Apr 2005 16:42:53 -0000
@@ -41,7 +41,7 @@
#endif
void uaudio_chan_set_param(device_t, u_char *, u_char *);
void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir);
-void uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir);
+int uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int reqdir);
void uaudio_chan_set_param_format(device_t dev, u_int32_t format,int dir);
int uaudio_chan_getptr(device_t dev, int);
void uaudio_mixer_set(device_t dev, unsigned type, unsigned left,
@@ -49,4 +49,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);
+unsigned uaudio_query_formats(device_t dev, int dir, unsigned maxfmt, struct pcmchan_caps *fmt);
Index: uaudio_pcm.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/usb/uaudio_pcm.c,v
retrieving revision 1.13
diff -u -r1.13 uaudio_pcm.c
--- uaudio_pcm.c 17 Apr 2005 15:26:51 -0000 1.13
+++ uaudio_pcm.c 17 Apr 2005 17:06:38 -0000
@@ -49,16 +49,12 @@
device_t sc_dev;
u_int32_t bufsz;
struct ua_chinfo pch, rch;
+ u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
+ u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
+ struct pcmchan_caps ua_playcaps;
+ struct pcmchan_caps ua_reccaps;
};
-static u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
-
-static struct pcmchan_caps ua_playcaps = {8000, 48000, ua_playfmt, 0};
-
-static u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
-
-static struct pcmchan_caps ua_reccaps = {8000, 48000, ua_recfmt, 0};
-
#define UAUDIO_DEFAULT_BUFSZ 16*1024
/************************************************************/
@@ -76,20 +72,6 @@
ch->dir = dir;
pa_dev = device_get_parent(sc->sc_dev);
- /* Create ua_playfmt[] & ua_recfmt[] */
- uaudio_query_formats(pa_dev, (u_int32_t *)&ua_playfmt, (u_int32_t *)&ua_recfmt);
- if (dir == PCMDIR_PLAY) {
- if (ua_playfmt[0] == 0) {
- printf("play channel supported format list invalid\n");
- return NULL;
- }
- } else {
- if (ua_recfmt[0] == 0) {
- printf("record channel supported format list invalid\n");
- return NULL;
- }
-
- }
ch->buf = malloc(sc->bufsz, M_DEVBUF, M_NOWAIT);
if (ch->buf == NULL)
@@ -133,6 +115,9 @@
struct ua_chinfo *ch = data;
+ /*
+ * At this point, no need to queury as we shouldn't select an unsorted format
+ */
ua = ch->parent;
pa_dev = device_get_parent(ua->sc_dev);
uaudio_chan_set_param_format(pa_dev, format, ch->dir);
@@ -144,15 +129,12 @@
static int
ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
- device_t pa_dev;
- struct ua_info *ua;
-
struct ua_chinfo *ch = data;
- ch->spd = speed;
+ device_t pa_dev = device_get_parent(ch->parent->sc_dev);
+ int res;
- ua = ch->parent;
- pa_dev = device_get_parent(ua->sc_dev);
- uaudio_chan_set_param_speed(pa_dev, speed, ch->dir);
+ if ( (res = uaudio_chan_set_param_speed(pa_dev, speed, ch->dir)) )
+ ch->spd = speed;
return ch->spd;
}
@@ -226,7 +208,7 @@
{
struct ua_chinfo *ch = data;
- return (ch->dir == PCMDIR_PLAY) ? &ua_playcaps : & ua_reccaps;
+ return (ch->dir == PCMDIR_PLAY) ? &(ch->parent->ua_playcaps) : &(ch->parent->ua_reccaps);
}
static kobj_method_t ua_chan_methods[] = {
@@ -318,40 +300,62 @@
{
struct ua_info *ua;
char status[SND_STATUSLEN];
+ device_t pa_dev;
+ u_int32_t nplay, nrec;
+ int i;
- ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_NOWAIT);
- if (!ua)
+ ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_ZERO | M_NOWAIT);
+ if ( ua == NULL )
return ENXIO;
- bzero(ua, sizeof *ua);
ua->sc_dev = dev;
+ pa_dev = device_get_parent(dev);
+
ua->bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_DEFAULT_BUFSZ, 65536);
if (bootverbose)
device_printf(dev, "using a default buffer size of %jd\n", (intmax_t)ua->bufsz);
ua->bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_DEFAULT_BUFSZ, 65536);
if (mixer_init(dev, &ua_mixer_class, ua)) {
- return(ENXIO);
+ goto bad;
}
- snprintf(status, SND_STATUSLEN, "at addr ?");
+ snprintf(status, SND_STATUSLEN, "%s", PCM_KLDSTRING(snd_uaudio));
+
+ ua->ua_playcaps.fmtlist = ua->ua_playfmt;
+ ua->ua_reccaps.fmtlist = ua->ua_recfmt;
+ nplay = uaudio_query_formats(pa_dev, PCMDIR_PLAY, 8, &ua->ua_playcaps);
+ nrec = uaudio_query_formats(pa_dev, PCMDIR_REC, 8, &ua->ua_reccaps);
+
+ if ( nplay > 1 )
+ nplay = 1;
+ if ( nrec > 1 )
+ nrec = 1;
#ifndef NO_RECORDING
- if (pcm_register(dev, ua, 1, 1)) {
+ if (pcm_register(dev, ua, nplay, nrec)) {
#else
- if (pcm_register(dev, ua, 1, 0)) {
+ if (pcm_register(dev, ua, nplay, 0)) {
#endif
- return(ENXIO);
+ goto bad;
+ }
+
+ for (i = 0; i < nplay; i++) {
+ pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
}
- pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
#ifndef NO_RECORDING
- pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
+ for (i = 0; i < nrec; i++) {
+ pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
+ }
#endif
pcm_setstatus(dev, status);
return 0;
+
+bad: free(ua, M_DEVBUF);
+ return ENXIO;
}
static int
More information about the freebsd-multimedia
mailing list