Update of /cvsroot/alsa/alsa-kernel/usb In directory sc8-pr-cvs1:/tmp/cvs-serv17105
Modified Files: usbaudio.c Log Message: moved some schedulable functions to hw_params callback from prepare callback. Index: usbaudio.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.c,v retrieving revision 1.58 retrieving revision 1.59 diff -u -r1.58 -r1.59 --- usbaudio.c 20 Jun 2003 18:04:03 -0000 1.58 +++ usbaudio.c 23 Jun 2003 12:41:36 -0000 1.59 @@ -153,6 +153,9 @@ int direction; /* playback or capture */ int interface; /* current interface */ int endpoint; /* assigned endpoint */ + struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ + unsigned int cur_rate; /* current rate (for hw_params callback) */ + unsigned int period_bytes; /* current period bytes (for hw_params callback) */ unsigned int format; /* USB data format */ unsigned int datapipe; /* the data i/o pipe */ unsigned int syncpipe; /* 1 - async out or adaptive in */ @@ -808,14 +811,15 @@ /* * initialize a substream for plaback/capture */ -static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) +static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_bytes, + unsigned int rate, unsigned int frame_bits) { unsigned int maxsize, n, i; int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; unsigned int npacks[MAX_URBS], total_packs; /* calculate the frequency in 10.14 format */ - subs->freqn = subs->freqm = get_usb_rate(runtime->rate); + subs->freqn = subs->freqm = get_usb_rate(rate); subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */ subs->phase = 0; @@ -828,7 +832,7 @@ subs->unlink_mask = 0; /* calculate the max. size of packet */ - maxsize = ((subs->freqmax + 0x3fff) * (runtime->frame_bits >> 3)) >> 14; + maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14; if (subs->maxpacksize && maxsize > subs->maxpacksize) { //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", // maxsize, subs->maxpacksize); @@ -839,7 +843,6 @@ subs->curpacksize = subs->maxpacksize; else subs->curpacksize = maxsize; - subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); /* allocate a temporary buffer for playback */ if (is_playback) { @@ -851,7 +854,7 @@ } /* decide how many packets to be used */ - total_packs = (frames_to_bytes(runtime, runtime->period_size) + maxsize - 1) / maxsize; + total_packs = (period_bytes + maxsize - 1) / maxsize; if (total_packs < 2 * MIN_PACKS_URB) total_packs = 2 * MIN_PACKS_URB; subs->nurbs = (total_packs + nrpacks - 1) / nrpacks; @@ -945,7 +948,8 @@ /* * find a matching audio format */ -static struct audioformat *find_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) +static struct audioformat *find_format(snd_usb_substream_t *subs, unsigned int format, + unsigned int rate, unsigned int channels) { struct list_head *p; struct audioformat *found = NULL; @@ -953,23 +957,21 @@ list_for_each(p, &subs->fmt_list) { struct audioformat *fp; fp = list_entry(p, struct audioformat, list); - if (fp->format != runtime->format || - fp->channels != runtime->channels) + if (fp->format != format || fp->channels != channels) continue; - if (runtime->rate < fp->rate_min || runtime->rate > fp->rate_max) + if (rate < fp->rate_min || rate > fp->rate_max) continue; - if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { - if (! found || fp->maxpacksize > found->maxpacksize) - found = fp; - } else { + if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { unsigned int i; for (i = 0; i < fp->nr_rates; i++) - if (fp->rate_table[i] == runtime->rate) { - if (! found || fp->maxpacksize > found->maxpacksize) - found = fp; + if (fp->rate_table[i] == rate) break; - } + if (i >= fp->nr_rates) + continue; } + /* find the format with the largest max. packet size */ + if (! found || fp->maxpacksize > found->maxpacksize) + found = fp; } return found; } @@ -1042,30 +1044,25 @@ /* * find a matching format and set up the interface */ -static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) +static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) { struct usb_device *dev = subs->dev; struct usb_host_config *config = dev->actconfig; struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; struct usb_interface *iface; - struct audioformat *fmt; unsigned int ep, attr; int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; int err; - fmt = find_format(subs, runtime); - if (! fmt) { - snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n", - snd_pcm_format_name(runtime->format), runtime->rate, runtime->channels); - return -EINVAL; - } - iface = &config->interface[fmt->iface]; alts = &iface->altsetting[fmt->altset_idx]; altsd = get_iface_desc(alts); snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL); + if (fmt == subs->cur_audiofmt) + return 0; + /* close the old interface */ if (subs->interface >= 0 && subs->interface != fmt->iface) { usb_set_interface(subs->dev, subs->interface, 0); @@ -1093,7 +1090,6 @@ subs->datapipe = usb_rcvisocpipe(dev, ep); subs->syncpipe = subs->syncinterval = 0; subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; - subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->fill_max = 0; /* we need a sync pipe in async OUT or adaptive IN mode */ @@ -1123,18 +1119,18 @@ subs->syncinterval = get_endpoint(alts, 1)->bRefresh; } - if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 || - (err = init_usb_sample_rate(dev, subs->interface, alts, fmt, - runtime->rate)) < 0) - return err; - /* always fill max packet size */ if (fmt->attributes & EP_CS_ATTR_FILL_MAX) subs->fill_max = 1; + if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0) + return err; + + subs->cur_audiofmt = fmt; + #if 0 printk("setting done: format = %d, rate = %d, channels = %d\n", - runtime->format, runtime->rate, runtime->channels); + fmt->format, fmt->rate, fmt->channels); printk(" datapipe = 0x%0x, syncpipe = 0x%0x\n", subs->datapipe, subs->syncpipe); #endif @@ -1143,7 +1139,9 @@ } /* - * allocate a buffer. + * hw_params callback + * + * allocate a buffer and set the given audio format. * * so far we use a physically linear buffer although packetize transfer * doesn't need a continuous area. @@ -1153,33 +1151,91 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; + struct audioformat *fmt; + unsigned int channels, rate, format; + int ret, changed; + + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (ret < 0) + return ret; + + format = params_format(hw_params); + rate = params_rate(hw_params); + channels = params_channels(hw_params); + fmt = find_format(subs, format, rate, channels); + if (! fmt) { + snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n", + snd_pcm_format_name(format), rate, channels); + return -EINVAL; + } + + changed = subs->cur_audiofmt != fmt || + subs->period_bytes != params_period_bytes(hw_params) || + subs->cur_rate != rate; + if ((ret = set_format(subs, fmt)) < 0) + return ret; + + if (subs->cur_rate != rate) { + struct usb_host_config *config = subs->dev->actconfig; + struct usb_host_interface *alts; + struct usb_interface *iface; + iface = &config->interface[fmt->iface]; + alts = &iface->altsetting[fmt->altset_idx]; + ret = init_usb_sample_rate(subs->dev, subs->interface, alts, fmt, rate); + if (ret < 0) + return ret; + subs->cur_rate = rate; + } + + if (changed) { + /* format changed */ + release_substream_urbs(subs, 0); + /* influenced: period_bytes, channels, rate, format, */ + ret = init_substream_urbs(subs, params_period_bytes(hw_params), + params_rate(hw_params), + snd_pcm_format_physical_width(params_format(hw_params)) * params_channels(hw_params)); + } + + return ret; } /* - * free the buffer + * hw_free callback + * + * reset the audio format and release the buffer */ static int snd_usb_hw_free(snd_pcm_substream_t *substream) { + snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; + + subs->cur_audiofmt = NULL; + subs->cur_rate = 0; + subs->period_bytes = 0; + release_substream_urbs(subs, 0); return snd_pcm_lib_free_pages(substream); } /* * prepare callback * - * set format and initialize urbs + * only a few subtle things... */ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data; - int err; - release_substream_urbs(subs, 0); - if ((err = set_format(subs, runtime)) < 0) - return err; + if (! subs->cur_audiofmt) { + snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); + return -ENXIO; + } - return init_substream_urbs(subs, runtime); + /* some unit conversions in runtime */ + subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); + subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); + + return 0; } static snd_pcm_hardware_t snd_usb_playback = @@ -1536,9 +1592,10 @@ snd_usb_stream_t *as = snd_pcm_substream_chip(substream); snd_usb_substream_t *subs = &as->substream[direction]; - release_substream_urbs(subs, 0); - if (subs->interface >= 0) + if (subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); + subs->interface = -1; + } subs->pcm_substream = NULL; return 0; } ------------------------------------------------------- This SF.Net email is sponsored by: INetU Attention Web Developers & Consultants: Become An INetU Hosting Partner. Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission! INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php _______________________________________________ Alsa-cvslog mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-cvslog