fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / sound / usb / usbaudio.c
index 1b7f499..1bd9af6 100644 (file)
@@ -68,7 +68,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;     /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
 static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
 static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
-static int nrpacks = 4;                /* max. number of packets per urb */
+static int nrpacks = 8;                /* max. number of packets per urb */
 static int async_unlink = 1;
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
 
@@ -100,7 +100,7 @@ MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
  *
  */
 
-#define MAX_PACKS      10
+#define MAX_PACKS      20
 #define MAX_PACKS_HS   (MAX_PACKS * 8) /* in high speed mode */
 #define MAX_URBS       8
 #define SYNC_URBS      4       /* always four urbs for sync */
@@ -123,6 +123,7 @@ struct audioformat {
        unsigned int rate_min, rate_max;        /* min/max rates */
        unsigned int nr_rates;          /* number of rate table entries */
        unsigned int *rate_table;       /* rate table */
+       unsigned int needs_knot;        /* any unusual rates? */
 };
 
 struct snd_usb_substream;
@@ -185,6 +186,7 @@ struct snd_usb_substream {
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
        struct list_head fmt_list;      /* format list */
+       struct snd_pcm_hw_constraint_list rate_list;    /* limited rates */
        spinlock_t lock;
 
        struct snd_urb_ops ops;         /* callbacks (must be filled at init) */
@@ -652,7 +654,7 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
 /*
  * complete callback from data urb
  */
-static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
+static void snd_complete_urb(struct urb *urb)
 {
        struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
        struct snd_usb_substream *subs = ctx->subs;
@@ -675,7 +677,7 @@ static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
 /*
  * complete callback from sync urb
  */
-static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
+static void snd_complete_sync_urb(struct urb *urb)
 {
        struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
        struct snd_usb_substream *subs = ctx->subs;
@@ -1468,7 +1470,8 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->cur_audiofmt = NULL;
        subs->cur_rate = 0;
        subs->period_bytes = 0;
-       release_substream_urbs(subs, 0);
+       if (!subs->stream->chip->shutdown)
+               release_substream_urbs(subs, 0);
        return snd_pcm_free_vmalloc_buffer(substream);
 }
 
@@ -1759,6 +1762,9 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
                }
                channels[f->format] |= (1 << f->channels);
                rates[f->format] |= f->rates;
+               /* needs knot? */
+               if (f->needs_knot)
+                       goto __out;
        }
        /* check whether channels and rates match for all formats */
        cmaster = rmaster = 0;
@@ -1799,6 +1805,43 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
        return err;
 }
 
+/*
+ *  If the device supports unusual bit rates, does the request meet these?
+ */
+static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
+                                 struct snd_usb_substream *subs)
+{
+       struct audioformat *fp;
+       int count = 0, needs_knot = 0;
+       int err;
+
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
+                       return 0;
+               count += fp->nr_rates;
+               if (fp->needs_knot)
+                       needs_knot = 1;
+       }
+       if (!needs_knot)
+               return 0;
+
+       subs->rate_list.count = count;
+       subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+       subs->rate_list.mask = 0;
+       count = 0;
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               int i;
+               for (i = 0; i < fp->nr_rates; i++)
+                       subs->rate_list.list[count++] = fp->rate_table[i];
+       }
+       err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                        &subs->rate_list);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 
 /*
  * set up the runtime hardware information.
@@ -1861,6 +1904,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
                                               SNDRV_PCM_HW_PARAM_CHANNELS,
                                               -1)) < 0)
                        return err;
+               if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
+                       return err;
        }
        return 0;
 }
@@ -2008,10 +2053,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
        void *buf = NULL;
 
        if (size > 0) {
-               buf = kmalloc(size, GFP_KERNEL);
+               buf = kmemdup(data, size, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
-               memcpy(buf, data, size);
        }
        err = usb_control_msg(dev, pipe, request, requesttype,
                              value, index, buf, size, timeout);
@@ -2049,7 +2093,7 @@ static struct usb_driver usb_audio_driver = {
 };
 
 
-#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS)
 
 /*
  * proc interface for list the supported pcm formats
@@ -2193,6 +2237,7 @@ static void free_substream(struct snd_usb_substream *subs)
                kfree(fp->rate_table);
                kfree(fp);
        }
+       kfree(subs->rate_list.list);
 }
 
 
@@ -2406,6 +2451,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                                    unsigned char *fmt, int offset)
 {
        int nr_rates = fmt[offset];
+       int found;
        if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
                snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
                                   chip->dev->devnum, fp->iface, fp->altsetting);
@@ -2417,6 +2463,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                 * build the rate table and bitmap flags
                 */
                int r, idx, c;
+               unsigned int nonzero_rates = 0;
                /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */
                static unsigned int conv_rates[] = {
                        5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
@@ -2428,21 +2475,39 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                        return -1;
                }
 
+               fp->needs_knot = 0;
                fp->nr_rates = nr_rates;
                fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
                for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
-                       unsigned int rate = fp->rate_table[r] = combine_triple(&fmt[idx]);
+                       unsigned int rate = combine_triple(&fmt[idx]);
+                       /* C-Media CM6501 mislabels its 96 kHz altsetting */
+                       if (rate == 48000 && nr_rates == 1 &&
+                           chip->usb_id == USB_ID(0x0d8c, 0x0201) &&
+                           fp->altsetting == 5 && fp->maxpacksize == 392)
+                               rate = 96000;
+                       fp->rate_table[r] = rate;
+                       nonzero_rates |= rate;
                        if (rate < fp->rate_min)
                                fp->rate_min = rate;
                        else if (rate > fp->rate_max)
                                fp->rate_max = rate;
+                       found = 0;
                        for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
                                if (rate == conv_rates[c]) {
+                                       found = 1;
                                        fp->rates |= (1 << c);
                                        break;
                                }
                        }
+                       if (!found)
+                               fp->needs_knot = 1;
                }
+               if (!nonzero_rates) {
+                       hwc_debug("All rates were zero. Skipping format!\n");
+                       return -1;
+               }
+               if (fp->needs_knot)
+                       fp->rates |= SNDRV_PCM_RATE_KNOT;
        } else {
                /* continuous rates */
                fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
@@ -2800,12 +2865,11 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        int stream, err;
        int *rate_table = NULL;
 
-       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
        if (! fp) {
-               snd_printk(KERN_ERR "cannot malloc\n");
+               snd_printk(KERN_ERR "cannot memdup\n");
                return -ENOMEM;
        }
-       memcpy(fp, quirk->data, sizeof(*fp));
        if (fp->nr_rates > 0) {
                rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
                if (!rate_table) {
@@ -2983,10 +3047,9 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
            altsd->bNumEndpoints != 1)
                return -ENXIO;
 
-       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       fp = kmemdup(&ua1000_format, sizeof(*fp), GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
-       memcpy(fp, &ua1000_format, sizeof(*fp));
 
        fp->channels = alts->extra[4];
        fp->iface = altsd->bInterfaceNumber;
@@ -3236,6 +3299,7 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
 
 static int snd_usb_audio_free(struct snd_usb_audio *chip)
 {
+       usb_chip[chip->index] = NULL;
        kfree(chip);
        return 0;
 }
@@ -3497,9 +3561,8 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
                list_for_each(p, &chip->mixer_list) {
                        snd_usb_mixer_disconnect(p);
                }
-               usb_chip[chip->index] = NULL;
                mutex_unlock(&register_mutex);
-               snd_card_free(card);
+               snd_card_free_when_closed(card);
        } else {
                mutex_unlock(&register_mutex);
        }
@@ -3533,8 +3596,7 @@ static int __init snd_usb_audio_init(void)
                printk(KERN_WARNING "invalid nrpacks value.\n");
                return -EINVAL;
        }
-       usb_register(&usb_audio_driver);
-       return 0;
+       return usb_register(&usb_audio_driver);
 }