From owner-freebsd-multimedia@FreeBSD.ORG Wed Nov 2 14:14:16 2005 Return-Path: X-Original-To: freebsd-multimedia@freebsd.org Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9C97F16A41F for ; Wed, 2 Nov 2005 14:14:16 +0000 (GMT) (envelope-from kazuhito@ph.noda.tus.ac.jp) Received: from t-mta3.odn.ne.jp (mfep3.odn.ne.jp [143.90.131.181]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9C85943D48 for ; Wed, 2 Nov 2005 14:14:14 +0000 (GMT) (envelope-from kazuhito@ph.noda.tus.ac.jp) Received: from localhost ([61.116.129.252]) by t-mta3.odn.ne.jp with ESMTP id <20051102141413475.SETW.496069.t-mta3.odn.ne.jp@mta3.odn.ne.jp>; Wed, 2 Nov 2005 23:14:13 +0900 Date: Wed, 02 Nov 2005 23:14:12 +0900 (JST) Message-Id: <20051102.231412.343190544.kazuhito@ph.noda.tus.ac.jp> To: skywizard@MyBSD.org.my From: Kazuhito HONDA In-Reply-To: <20051029094831.1c6c785d.skywizard@MyBSD.org.my> References: <20051027133448.vptim01kwoco8wcw@netchild.homeip.net> <20051028.224049.343190967.kazuhito@ph.noda.tus.ac.jp> <20051029094831.1c6c785d.skywizard@MyBSD.org.my> X-Mailer: Mew version 3.3 on XEmacs 21.4.17 (Jumbo Shrimp) Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="--Next_Part(Wed_Nov__2_23:14:12_2005_702)--" Content-Transfer-Encoding: 7bit Cc: freebsd-multimedia@freebsd.org, Alexander@Leidinger.net Subject: Re: uaudio and Digigram UAX220 X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Nov 2005 14:14:16 -0000 ----Next_Part(Wed_Nov__2_23:14:12_2005_702)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit From: Ariff Abdullah Subject: Re: uaudio and Digigram UAX220 Date: Sat, 29 Oct 2005 09:48:31 +0800 > Could you please do the cleanup? :) The only thing is that Julian > already said that those patch break his USB microphone, so this must > undergo some serious regression test to be accepted. Oh, I missed that. I wonder why it isn't committed. I have searched the patch and found one problem. In uaudio_query_formats() of uaudio.c + + if ( numchan != 1 && numchan == 2 ) + + foundcount++; + `foundcount' is a flag to indicate which a valid format is found or not. `numchan' is a number of channel. If a device has mono channels only, foundcont flag isn't changed. I guess that it broke Julian's USB microphone, because microphone is usually mono. `if' line is unnecessary. We should remove this line and lieve `foundcount++'. And thank you for your comments and advice. I have done the cleanup and improvements of the patch along them. (include bug fix, 24 bit and 32 bit sound stream, and speed setting) It is attached at the end of this mail. Sincerely yours, Kazuhito HONDA ----Next_Part(Wed_Nov__2_23:14:12_2005_702)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="setspeed_patch" --- uaudio.c.old Wed Nov 2 16:16:00 2005 +++ uaudio.c Wed Nov 2 16:18:32 2005 @@ -1,5 +1,5 @@ /* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ -/* $FreeBSD: src/sys/dev/sound/usb/uaudio.c,v 1.16 2005/09/18 15:13:06 netchild Exp $ */ +/* $FreeBSD: src/sys/dev/sound/usb/uaudio.c, kazuhito Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -239,6 +239,7 @@ struct uaudio_softc { #define HAS_MULAW 0x10 #define UA_NOFRAC 0x20 /* don't do sample rate adjustment */ #define HAS_24 0x40 +#define HAS_32 0x80 int sc_mode; /* play/record capability */ struct mixerctl *sc_ctls; /* mixer controls */ int sc_nctls; /* # of mixer controls */ @@ -2050,7 +2051,7 @@ uaudio_process_as(struct uaudio_softc *s format = UGETW(asid->wFormatTag); chan = asf1d->bNrChannels; prec = asf1d->bBitResolution; - if (prec != 8 && prec != 16 && prec != 24) { + if (prec != 8 && prec != 16 && prec != 24 && prec != 32) { printf("%s: ignored setting with precision %d\n", USBDEVNAME(sc->sc_dev), prec); return USBD_NORMAL_COMPLETION; @@ -2063,6 +2064,8 @@ uaudio_process_as(struct uaudio_softc *s sc->sc_altflags |= HAS_16; } else if (prec == 24) { sc->sc_altflags |= HAS_24; + } else if (prec == 32) { + sc->sc_altflags |= HAS_32; } enc = AUDIO_ENCODING_SLINEAR_LE; format_str = "pcm"; @@ -3742,7 +3745,7 @@ uaudio_init_params(struct uaudio_softc * if ((sc->sc_playchan.pipe != NULL) || (sc->sc_recchan.pipe != NULL)) return (-1); - switch(ch->format & 0x0000FFFF) { + switch(ch->format & 0x000FFFFF) { case AFMT_U8: enc = AUDIO_ENCODING_ULINEAR_LE; ch->precision = 8; @@ -3775,6 +3778,38 @@ uaudio_init_params(struct uaudio_softc * enc = AUDIO_ENCODING_ULINEAR_BE; ch->precision = 16; break; + case AFMT_S24_LE: + enc = AUDIO_ENCODING_SLINEAR_LE; + ch->precision = 24; + break; + case AFMT_S24_BE: + enc = AUDIO_ENCODING_SLINEAR_BE; + ch->precision = 24; + break; + case AFMT_U24_LE: + enc = AUDIO_ENCODING_ULINEAR_LE; + ch->precision = 24; + break; + case AFMT_U24_BE: + enc = AUDIO_ENCODING_ULINEAR_BE; + ch->precision = 24; + break; + case AFMT_S32_LE: + enc = AUDIO_ENCODING_SLINEAR_LE; + ch->precision = 32; + break; + case AFMT_S32_BE: + enc = AUDIO_ENCODING_SLINEAR_BE; + ch->precision = 32; + break; + case AFMT_U32_LE: + enc = AUDIO_ENCODING_ULINEAR_LE; + ch->precision = 32; + break; + case AFMT_U32_BE: + enc = AUDIO_ENCODING_ULINEAR_BE; + ch->precision = 32; + break; default: enc = 0; ch->precision = 16; @@ -3857,83 +3892,135 @@ uaudio_init_params(struct uaudio_softc * return (0); } -void -uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt) +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_ULINEAR_LE, 24, AFMT_U24_LE}, + {AUDIO_ENCODING_ULINEAR_LE, 32, AFMT_U32_LE}, + {AUDIO_ENCODING_ULINEAR_BE, 16, AFMT_U16_BE}, + {AUDIO_ENCODING_ULINEAR_BE, 24, AFMT_U24_BE}, + {AUDIO_ENCODING_ULINEAR_BE, 32, AFMT_U32_BE}, + {AUDIO_ENCODING_SLINEAR_LE, 8, AFMT_S8}, + {AUDIO_ENCODING_SLINEAR_LE, 16, AFMT_S16_LE}, + {AUDIO_ENCODING_SLINEAR_LE, 24, AFMT_S24_LE}, + {AUDIO_ENCODING_SLINEAR_LE, 24, AFMT_S32_LE}, + {AUDIO_ENCODING_SLINEAR_BE, 16, AFMT_S16_BE}, + {AUDIO_ENCODING_SLINEAR_BE, 24, AFMT_S24_BE}, + {AUDIO_ENCODING_SLINEAR_BE, 24, AFMT_S32_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) { - int i, pn=0, rn=0; - int prec, dir; - u_int32_t fmt; struct uaudio_softc *sc; - - const struct usb_audio_streaming_type1_descriptor *a1d; + const struct usb_audio_streaming_type1_descriptor *asf1d; + const struct uaudio_convesion *iterator; + unsigned fmtcount, foundcount; + u_int32_t fmt; + uint8_t format, numchan, subframesize, prec, dir, iscontinuous; + int freq, freq_min, freq_max; + char *numchannel_descr; + char freq_descr[64]; + int i,r; sc = device_get_softc(dev); + if (sc == NULL) + return 0; + + 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 */ + dir = UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress); - 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; - } + if ((dir == UE_DIR_OUT) != (reqdir == PCMDIR_PLAY)) + continue; - if (fmt != 0) { - if (a1d->bNrChannels == 2) { /* stereo/mono */ - fmt |= AFMT_STEREO; - } else if (a1d->bNrChannels != 1) { - fmt = 0; - } + 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 (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 (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 (iterator->uaudio_fmt == 0) + continue; + + fmt = iterator->freebsd_fmt; + + if (numchan == 2) + fmt |= AFMT_STEREO; + + 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 @@ -3982,25 +4069,81 @@ uaudio_chan_set_param_blocksize(device_t 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, score, hiscore, bestspeed; 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. + */ + hiscore = 0; + bestspeed = 1; + 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; - ch->sample_rate = speed; + if ((dir == UE_DIR_OUT) != (reqdir == PCMDIR_PLAY)) + continue; - return; + for (iterator = accepted_conversion ; iterator->uaudio_fmt != 0 ; iterator++) + if (iterator->uaudio_fmt != format || iterator->freebsd_fmt != (ch->format&0xfffffff)) + continue; + if (iscontinuous) { + if (speed >= UA_SAMP_LO(asf1d) && speed <= UA_SAMP_HI(asf1d)) { + ch->sample_rate = speed; + return speed; + } else if (speed < UA_SAMP_LO(asf1d)) { + score = 0xfff * speed / UA_SAMP_LO(asf1d); + if (score > hiscore) { + bestspeed = UA_SAMP_LO(asf1d); + hiscore = score; + } + } else if (speed < UA_SAMP_HI(asf1d)) { + score = 0xfff * UA_SAMP_HI(asf1d) / speed; + if (score > hiscore) { + bestspeed = UA_SAMP_HI(asf1d); + hiscore = score; + } + } + continue; + } + for (r = 0; r < asf1d->bSamFreqType; r++) { + if (speed == UA_GETSAMP(asf1d, r)) { + ch->sample_rate = speed; + return speed; + } + if (speed > UA_GETSAMP(asf1d, r)) + score = 0xfff * UA_GETSAMP(asf1d, r) / speed; + else + score = 0xfff * speed / UA_GETSAMP(asf1d, r); + if (score > hiscore) { + bestspeed = UA_GETSAMP(asf1d, r); + hiscore = score; + } + } + } + if (bestspeed != 1) { + ch->sample_rate = bestspeed; + return bestspeed; + } + + return 0; } int --- uaudio_pcm.c.old Wed Nov 2 16:15:42 2005 +++ uaudio_pcm.c Wed Nov 2 22:42:25 2005 @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/dev/sound/usb/uaudio_pcm.c,v 1.17 2005/10/02 15:51:19 netchild Exp $ */ +/* $FreeBSD: src/sys/dev/sound/usb/uaudio_pcm.c,kazuhito Exp $ */ /*- * Copyright (c) 2000-2002 Hiroyuki Aizu @@ -49,16 +49,13 @@ struct ua_info { device_t sc_dev; u_int32_t bufsz; struct ua_chinfo pch, rch; +#define FORMAT_NUM 32 + u_int32_t ua_playfmt[FORMAT_NUM*2+1]; /* FORMAT_NUM format * (stereo or mono) + endptr */ + u_int32_t ua_recfmt[FORMAT_NUM*2+1]; /* FORMAT_NUM 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,23 +73,9 @@ ua_chan_init(kobj_t obj, void *devinfo, 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) + if (ch->buf == NULL) return NULL; if (sndbuf_setup(b, ch->buf, sc->bufsz) != 0) { free(ch->buf, M_DEVBUF); @@ -133,6 +116,9 @@ ua_chan_setformat(kobj_t obj, void *data 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 +130,15 @@ ua_chan_setformat(kobj_t obj, void *data static int ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed) { + struct ua_chinfo *ch; device_t pa_dev; - struct ua_info *ua; + int bestspeed; - struct ua_chinfo *ch = data; - ch->spd = speed; + ch = data; + pa_dev = device_get_parent(ch->parent->sc_dev); - ua = ch->parent; - pa_dev = device_get_parent(ua->sc_dev); - uaudio_chan_set_param_speed(pa_dev, speed, ch->dir); + if ((bestspeed = uaudio_chan_set_param_speed(pa_dev, speed, ch->dir))) + ch->spd = bestspeed; return ch->spd; } @@ -224,9 +210,10 @@ ua_chan_getptr(kobj_t obj, void *data) static struct pcmchan_caps * ua_chan_getcaps(kobj_t obj, void *data) { - struct ua_chinfo *ch = data; + struct ua_chinfo *ch; - return (ch->dir == PCMDIR_PLAY) ? &ua_playcaps : & ua_reccaps; + ch = data; + return (ch->dir == PCMDIR_PLAY) ? &(ch->parent->ua_playcaps) : &(ch->parent->ua_reccaps); } static kobj_method_t ua_chan_methods[] = { @@ -327,42 +314,63 @@ ua_attach(device_t dev) { 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); if (mixer_init(dev, &ua_mixer_class, ua)) { - return(ENXIO); + goto bad; } snprintf(status, SND_STATUSLEN, "at ? %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, FORMAT_NUM * 2, &ua->ua_playcaps); + nrec = uaudio_query_formats(pa_dev, PCMDIR_REC, FORMAT_NUM * 2, &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; } sndstat_unregister(dev); uaudio_sndstat_register(dev); - pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua); + for (i = 0; i < nplay; i++) { + 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 ----Next_Part(Wed_Nov__2_23:14:12_2005_702)----