]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/usb/usbaudio.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6-omap-h63xx.git] / sound / usb / usbaudio.c
index c2db0f959681da6608e0906a580db3240000d45f..823296d7d5781cbebb7d2ff4ab37cb8ecfefe74c 100644 (file)
@@ -121,6 +121,7 @@ struct audioformat {
        unsigned char attributes;       /* corresponding attributes of cs endpoint */
        unsigned char endpoint;         /* endpoint */
        unsigned char ep_attr;          /* endpoint attributes */
+       unsigned char datainterval;     /* log_2 of data packet interval */
        unsigned int maxpacksize;       /* max. packet size */
        unsigned int rates;             /* rate bitmasks */
        unsigned int rate_min, rate_max;        /* min/max rates */
@@ -170,7 +171,6 @@ struct snd_usb_substream {
        unsigned int curframesize;      /* current packet size in frames (for capture) */
        unsigned int fill_max: 1;       /* fill max packet size always */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
-       unsigned int packs_per_ms;      /* packets per millisecond (for playback) */
 
        unsigned int running: 1;        /* running status */
 
@@ -607,9 +607,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
                                break;
                        }
                }
-               /* finish at the frame boundary at/after the period boundary */
-               if (period_elapsed &&
-                   (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1)
+               if (period_elapsed) /* finish at the period boundary */
                        break;
        }
        if (subs->hwptr_done + offs > runtime->buffer_size) {
@@ -1067,7 +1065,6 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                packs_per_ms = 8 >> subs->datainterval;
        else
                packs_per_ms = 1;
-       subs->packs_per_ms = packs_per_ms;
 
        if (is_playback) {
                urb_packs = max(nrpacks, 1);
@@ -1087,18 +1084,17 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                        minsize -= minsize >> 3;
                minsize = max(minsize, 1u);
                total_packs = (period_bytes + minsize - 1) / minsize;
-               /* round up to multiple of packs_per_ms */
-               total_packs = (total_packs + packs_per_ms - 1)
-                               & ~(packs_per_ms - 1);
                /* we need at least two URBs for queueing */
-               if (total_packs < 2 * packs_per_ms) {
-                       total_packs = 2 * packs_per_ms;
+               if (total_packs < 2) {
+                       total_packs = 2;
                } else {
                        /* and we don't want too long a queue either */
                        maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
                        total_packs = min(total_packs, maxpacks);
                }
        } else {
+               while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
+                       urb_packs >>= 1;
                total_packs = MAX_URBS * urb_packs;
        }
        subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
@@ -1350,12 +1346,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                subs->datapipe = usb_sndisocpipe(dev, ep);
        else
                subs->datapipe = usb_rcvisocpipe(dev, ep);
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH &&
-           get_endpoint(alts, 0)->bInterval >= 1 &&
-           get_endpoint(alts, 0)->bInterval <= 4)
-               subs->datainterval = get_endpoint(alts, 0)->bInterval - 1;
-       else
-               subs->datainterval = 0;
+       subs->datainterval = fmt->datainterval;
        subs->syncpipe = subs->syncinterval = 0;
        subs->maxpacksize = fmt->maxpacksize;
        subs->fill_max = 0;
@@ -1568,11 +1559,15 @@ static struct snd_pcm_hardware snd_usb_hardware =
 #define hwc_debug(fmt, args...) /**/
 #endif
 
-static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audioformat *fp)
+static int hw_check_valid_format(struct snd_usb_substream *subs,
+                                struct snd_pcm_hw_params *params,
+                                struct audioformat *fp)
 {
        struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME);
+       unsigned int ptime;
 
        /* check the format */
        if (!snd_mask_test(fmts, fp->format)) {
@@ -1593,6 +1588,14 @@ static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audiof
                hwc_debug("   > check: rate_max %d < min %d\n", fp->rate_max, it->min);
                return 0;
        }
+       /* check whether the period time is >= the data packet interval */
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) {
+               ptime = 125 * (1 << fp->datainterval);
+               if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
+                       hwc_debug("   > check: ptime %u > max %u\n", ptime, pt->max);
+                       return 0;
+               }
+       }
        return 1;
 }
 
@@ -1611,7 +1614,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (!hw_check_valid_format(params, fp))
+               if (!hw_check_valid_format(subs, params, fp))
                        continue;
                if (changed++) {
                        if (rmin > fp->rate_min)
@@ -1665,7 +1668,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (!hw_check_valid_format(params, fp))
+               if (!hw_check_valid_format(subs, params, fp))
                        continue;
                if (changed++) {
                        if (rmin > fp->channels)
@@ -1718,7 +1721,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (!hw_check_valid_format(params, fp))
+               if (!hw_check_valid_format(subs, params, fp))
                        continue;
                fbits |= (1ULL << fp->format);
        }
@@ -1736,95 +1739,42 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
        return changed;
 }
 
-#define MAX_MASK       64
-
-/*
- * check whether the registered audio formats need special hw-constraints
- */
-static int check_hw_params_convention(struct snd_usb_substream *subs)
+static int hw_rule_period_time(struct snd_pcm_hw_params *params,
+                              struct snd_pcm_hw_rule *rule)
 {
-       int i;
-       u32 *channels;
-       u32 *rates;
-       u32 cmaster, rmaster;
-       u32 rate_min = 0, rate_max = 0;
-       struct list_head *p;
-       int err = 1;
-
-       channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
-       rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
-       if (!channels || !rates) {
-               err = -ENOMEM;
-               goto __out;
-       }
+       struct snd_usb_substream *subs = rule->private;
+       struct audioformat *fp;
+       struct snd_interval *it;
+       unsigned char min_datainterval;
+       unsigned int pmin;
+       int changed;
 
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *f;
-               f = list_entry(p, struct audioformat, list);
-               /* unconventional channels? */
-               if (f->channels > 32)
-                       goto __out;
-               /* continuous rate min/max matches? */
-               if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) {
-                       if (rate_min && f->rate_min != rate_min)
-                               goto __out;
-                       if (rate_max && f->rate_max != rate_max)
-                               goto __out;
-                       rate_min = f->rate_min;
-                       rate_max = f->rate_max;
-               }
-               /* combination of continuous rates and fixed rates? */
-               if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) {
-                       if (f->rates != rates[f->format])
-                               goto __out;
-               }
-               if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) {
-                       if (rates[f->format] && rates[f->format] != f->rates)
-                               goto __out;
-               }
-               channels[f->format] |= 1 << (f->channels - 1);
-               rates[f->format] |= f->rates;
-               /* needs knot? */
-               if (f->rates & SNDRV_PCM_RATE_KNOT)
-                       goto __out;
-       }
-       /* check whether channels and rates match for all formats */
-       cmaster = rmaster = 0;
-       for (i = 0; i < MAX_MASK; i++) {
-               if (cmaster != channels[i] && cmaster && channels[i])
-                       goto __out;
-               if (rmaster != rates[i] && rmaster && rates[i])
-                       goto __out;
-               if (channels[i])
-                       cmaster = channels[i];
-               if (rates[i])
-                       rmaster = rates[i];
-       }
-       /* check whether channels match for all distinct rates */
-       memset(channels, 0, MAX_MASK * sizeof(u32));
-       list_for_each(p, &subs->fmt_list) {
-               struct audioformat *f;
-               f = list_entry(p, struct audioformat, list);
-               if (f->rates & SNDRV_PCM_RATE_CONTINUOUS)
+       it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME);
+       hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max);
+       min_datainterval = 0xff;
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               if (!hw_check_valid_format(subs, params, fp))
                        continue;
-               for (i = 0; i < 32; i++) {
-                       if (f->rates & (1 << i))
-                               channels[i] |= 1 << (f->channels - 1);
-               }
+               min_datainterval = min(min_datainterval, fp->datainterval);
        }
-       cmaster = 0;
-       for (i = 0; i < 32; i++) {
-               if (cmaster != channels[i] && cmaster && channels[i])
-                       goto __out;
-               if (channels[i])
-                       cmaster = channels[i];
+       if (min_datainterval == 0xff) {
+               hwc_debug("  --> get emtpy\n");
+               it->empty = 1;
+               return -EINVAL;
        }
-       err = 0;
-
- __out:
-       kfree(channels);
-       kfree(rates);
-       return err;
+       pmin = 125 * (1 << min_datainterval);
+       changed = 0;
+       if (it->min < pmin) {
+               it->min = pmin;
+               it->openmin = 0;
+               changed = 1;
+       }
+       if (snd_interval_checkempty(it)) {
+               it->empty = 1;
+               return -EINVAL;
+       }
+       hwc_debug("  --> (%u,%u) (changed = %d)\n", it->min, it->max, changed);
+       return changed;
 }
 
 /*
@@ -1872,6 +1822,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
 static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)
 {
        struct list_head *p;
+       unsigned int pt, ptmin;
+       int param_period_time_if_needed;
        int err;
 
        runtime->hw.formats = subs->formats;
@@ -1881,6 +1833,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
        runtime->hw.channels_min = 256;
        runtime->hw.channels_max = 0;
        runtime->hw.rates = 0;
+       ptmin = UINT_MAX;
        /* check min/max rates and channels */
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
@@ -1899,42 +1852,54 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
                        runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =
                                fp->frame_size;
                }
+               pt = 125 * (1 << fp->datainterval);
+               ptmin = min(ptmin, pt);
        }
 
-       /* set the period time minimum 1ms */
-       /* FIXME: high-speed mode allows 125us minimum period, but many parts
-        * in the current code assume the 1ms period.
-        */
+       param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
+       if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH)
+               /* full speed devices have fixed data packet interval */
+               ptmin = 1000;
+       if (ptmin == 1000)
+               /* if period time doesn't go below 1 ms, no rules needed */
+               param_period_time_if_needed = -1;
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-                                    1000,
-                                    /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
-
-       err = check_hw_params_convention(subs);
-       if (err < 0)
+                                    ptmin, UINT_MAX);
+
+       if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                      hw_rule_rate, subs,
+                                      SNDRV_PCM_HW_PARAM_FORMAT,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      param_period_time_if_needed,
+                                      -1)) < 0)
                return err;
-       else if (err) {
-               hwc_debug("setting extra hw constraints...\n");
-               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                              hw_rule_rate, subs,
-                                              SNDRV_PCM_HW_PARAM_FORMAT,
-                                              SNDRV_PCM_HW_PARAM_CHANNELS,
-                                              -1)) < 0)
-                       return err;
-               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                                              hw_rule_channels, subs,
-                                              SNDRV_PCM_HW_PARAM_FORMAT,
-                                              SNDRV_PCM_HW_PARAM_RATE,
-                                              -1)) < 0)
-                       return err;
-               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
-                                              hw_rule_format, subs,
-                                              SNDRV_PCM_HW_PARAM_RATE,
-                                              SNDRV_PCM_HW_PARAM_CHANNELS,
-                                              -1)) < 0)
-                       return err;
-               if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
+       if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      hw_rule_channels, subs,
+                                      SNDRV_PCM_HW_PARAM_FORMAT,
+                                      SNDRV_PCM_HW_PARAM_RATE,
+                                      param_period_time_if_needed,
+                                      -1)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
+                                      hw_rule_format, subs,
+                                      SNDRV_PCM_HW_PARAM_RATE,
+                                      SNDRV_PCM_HW_PARAM_CHANNELS,
+                                      param_period_time_if_needed,
+                                      -1)) < 0)
+               return err;
+       if (param_period_time_if_needed >= 0) {
+               err = snd_pcm_hw_rule_add(runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+                                         hw_rule_period_time, subs,
+                                         SNDRV_PCM_HW_PARAM_FORMAT,
+                                         SNDRV_PCM_HW_PARAM_CHANNELS,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         -1);
+               if (err < 0)
                        return err;
        }
+       if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
+               return err;
        return 0;
 }
 
@@ -2147,7 +2112,8 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                fp = list_entry(p, struct audioformat, list);
                snd_iprintf(buffer, "  Interface %d\n", fp->iface);
                snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
-               snd_iprintf(buffer, "    Format: %#x\n", fp->format);
+               snd_iprintf(buffer, "    Format: %#x (%d bits)\n",
+                           fp->format, snd_pcm_format_width(fp->format));
                snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
                            fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
@@ -2166,6 +2132,9 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                        }
                        snd_iprintf(buffer, "\n");
                }
+               if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+                       snd_iprintf(buffer, "    Data packet interval: %d us\n",
+                                   125 * (1 << fp->datainterval));
                // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
                // snd_iprintf(buffer, "    EP Attribute = %#x\n", fp->attributes);
        }
@@ -2659,6 +2628,17 @@ static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp
        return 0;
 }
 
+static unsigned char parse_datainterval(struct snd_usb_audio *chip,
+                                       struct usb_host_interface *alts)
+{
+       if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH &&
+           get_endpoint(alts, 0)->bInterval >= 1 &&
+           get_endpoint(alts, 0)->bInterval <= 4)
+               return get_endpoint(alts, 0)->bInterval - 1;
+       else
+               return 0;
+}
+
 static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
                                         int iface, int altno);
 static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
@@ -2764,6 +2744,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                fp->altset_idx = i;
                fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
                fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+               fp->datainterval = parse_datainterval(chip, alts);
                fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
                        fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
@@ -2955,6 +2936,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                return -EINVAL;
        }
        alts = &iface->altsetting[fp->altset_idx];
+       fp->datainterval = parse_datainterval(chip, alts);
        fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
        usb_set_interface(chip->dev, fp->iface, 0);
        init_usb_pitch(chip->dev, fp->iface, alts, fp);
@@ -3049,6 +3031,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        fp->iface = altsd->bInterfaceNumber;
        fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
        fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+       fp->datainterval = 0;
        fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
 
        switch (fp->maxpacksize) {
@@ -3116,6 +3099,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
        fp->iface = altsd->bInterfaceNumber;
        fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
        fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+       fp->datainterval = parse_datainterval(chip, alts);
        fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
        fp->rate_max = fp->rate_min = combine_triple(&alts->extra[8]);
 
@@ -3168,6 +3152,7 @@ static int create_ua101_quirk(struct snd_usb_audio *chip,
        fp->iface = altsd->bInterfaceNumber;
        fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
        fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+       fp->datainterval = parse_datainterval(chip, alts);
        fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
        fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]);