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

Reply via email to