]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'topic/usb-audio' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2009 23:36:22 +0000 (00:36 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2009 23:36:22 +0000 (00:36 +0100)
1  2 
sound/usb/usbaudio.c
sound/usb/usbmixer.c
sound/usb/usbquirks.h

diff --combined sound/usb/usbaudio.c
index 8f3cdb37a0ec3ddd7723eb1a5eb34e82de295157,defe9913cbb290dc4bbb82eccbe48822c874ef2c..c2db0f959681da6608e0906a580db3240000d45f
@@@ -107,7 -107,7 +107,7 @@@ MODULE_PARM_DESC(ignore_ctl_error
  #define MAX_PACKS_HS  (MAX_PACKS * 8) /* in high speed mode */
  #define MAX_URBS      8
  #define SYNC_URBS     4       /* always four urbs for sync */
- #define MIN_PACKS_URB 1       /* minimum 1 packet per urb */
+ #define MAX_QUEUE     24      /* try not to exceed this queue length, in ms */
  
  struct audioformat {
        struct list_head list;
@@@ -525,7 -525,7 +525,7 @@@ static int snd_usb_audio_next_packet_si
  /*
   * Prepare urb for streaming before playback starts or when paused.
   *
-  * We don't have any data, so we send a frame of silence.
+  * We don't have any data, so we send silence.
   */
  static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
                                       struct snd_pcm_runtime *runtime,
  
        offs = 0;
        urb->dev = ctx->subs->dev;
-       urb->number_of_packets = subs->packs_per_ms;
-       for (i = 0; i < subs->packs_per_ms; ++i) {
+       for (i = 0; i < ctx->packets; ++i) {
                counts = snd_usb_audio_next_packet_size(subs);
                urb->iso_frame_desc[i].offset = offs * stride;
                urb->iso_frame_desc[i].length = counts * stride;
                offs += counts;
        }
+       urb->number_of_packets = ctx->packets;
        urb->transfer_buffer_length = offs * stride;
        memset(urb->transfer_buffer,
               subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
@@@ -1034,9 -1034,9 +1034,9 @@@ static void release_substream_urbs(stru
  static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes,
                               unsigned int rate, unsigned int frame_bits)
  {
-       unsigned int maxsize, n, i;
+       unsigned int maxsize, i;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
+       unsigned int urb_packs, total_packs, packs_per_ms;
  
        /* calculate the frequency in 16.16 format */
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
        subs->packs_per_ms = packs_per_ms;
  
        if (is_playback) {
-               urb_packs = nrpacks;
-               urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
+               urb_packs = max(nrpacks, 1);
                urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
        } else
                urb_packs = 1;
  
        /* decide how many packets to be used */
        if (is_playback) {
-               unsigned int minsize;
+               unsigned int minsize, maxpacks;
                /* determine how small a packet can be */
                minsize = (subs->freqn >> (16 - subs->datainterval))
                          * (frame_bits >> 3);
                total_packs = (total_packs + packs_per_ms - 1)
                                & ~(packs_per_ms - 1);
                /* we need at least two URBs for queueing */
-               if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
-                       total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+               if (total_packs < 2 * packs_per_ms) {
+                       total_packs = 2 * packs_per_ms;
+               } 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 {
                total_packs = MAX_URBS * urb_packs;
        }
                /* too much... */
                subs->nurbs = MAX_URBS;
                total_packs = MAX_URBS * urb_packs;
-       }
-       n = total_packs;
-       for (i = 0; i < subs->nurbs; i++) {
-               npacks[i] = n > urb_packs ? urb_packs : n;
-               n -= urb_packs;
-       }
-       if (subs->nurbs <= 1) {
+       } else if (subs->nurbs < 2) {
                /* too little - we need at least two packets
                 * to ensure contiguous playback/capture
                 */
                subs->nurbs = 2;
-               npacks[0] = (total_packs + 1) / 2;
-               npacks[1] = total_packs - npacks[0];
-       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
-               /* the last packet is too small.. */
-               if (subs->nurbs > 2) {
-                       /* merge to the first one */
-                       npacks[0] += npacks[subs->nurbs - 1];
-                       subs->nurbs--;
-               } else {
-                       /* divide to two */
-                       subs->nurbs = 2;
-                       npacks[0] = (total_packs + 1) / 2;
-                       npacks[1] = total_packs - npacks[0];
-               }
        }
  
        /* allocate and initialize data urbs */
                struct snd_urb_ctx *u = &subs->dataurb[i];
                u->index = i;
                u->subs = subs;
-               u->packets = npacks[i];
+               u->packets = (i + 1) * total_packs / subs->nurbs
+                       - i * total_packs / subs->nurbs;
                u->buffer_size = maxsize * u->packets;
                if (subs->fmt_type == USB_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
@@@ -1292,14 -1277,14 +1277,14 @@@ static int init_usb_sample_rate(struct 
                if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
                                           SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
+                       snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
                                   dev->devnum, iface, fmt->altsetting, rate, ep);
                        return err;
                }
                if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
                                           SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep 0x%x\n",
+                       snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
                                   dev->devnum, iface, fmt->altsetting, ep);
                        return 0; /* some devices don't support reading */
                }
@@@ -1431,9 -1416,11 +1416,11 @@@ static int set_format(struct snd_usb_su
        subs->cur_audiofmt = fmt;
  
  #if 0
-       printk("setting done: format = %d, rate = %d..%d, channels = %d\n",
+       printk(KERN_DEBUG
+              "setting done: format = %d, rate = %d..%d, channels = %d\n",
               fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
-       printk("  datapipe = 0x%0x, syncpipe = 0x%0x\n",
+       printk(KERN_DEBUG
+              "  datapipe = 0x%0x, syncpipe = 0x%0x\n",
               subs->datapipe, subs->syncpipe);
  #endif
  
@@@ -1468,7 -1455,7 +1455,7 @@@ static int snd_usb_hw_params(struct snd
        channels = params_channels(hw_params);
        fmt = find_format(subs, format, rate, channels);
        if (!fmt) {
-               snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
+               snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
                           format, rate, channels);
                return -EINVAL;
        }
@@@ -1795,7 -1782,7 +1782,7 @@@ static int check_hw_params_convention(s
                        if (rates[f->format] && rates[f->format] != f->rates)
                                goto __out;
                }
-               channels[f->format] |= (1 << f->channels);
+               channels[f->format] |= 1 << (f->channels - 1);
                rates[f->format] |= f->rates;
                /* needs knot? */
                if (f->rates & SNDRV_PCM_RATE_KNOT)
                        continue;
                for (i = 0; i < 32; i++) {
                        if (f->rates & (1 << i))
-                               channels[i] |= (1 << f->channels);
+                               channels[i] |= 1 << (f->channels - 1);
                }
        }
        cmaster = 0;
@@@ -1919,7 -1906,7 +1906,7 @@@ static int setup_hw_info(struct snd_pcm
         * in the current code assume the 1ms period.
         */
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-                                    1000 * MIN_PACKS_URB,
+                                    1000,
                                     /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
  
        err = check_hw_params_convention(subs);
@@@ -2160,7 -2147,7 +2147,7 @@@ static void proc_dump_substream_formats
                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: 0x%x\n", fp->format);
+               snd_iprintf(buffer, "    Format: %#x\n", fp->format);
                snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
                            fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
                        snd_iprintf(buffer, "\n");
                }
                // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
-               // snd_iprintf(buffer, "    EP Attribute = 0x%x\n", fp->attributes);
+               // snd_iprintf(buffer, "    EP Attribute = %#x\n", fp->attributes);
        }
  }
  
@@@ -2524,6 -2511,7 +2511,6 @@@ static int parse_audio_format_rates(str
                 * build the rate table and bitmap flags
                 */
                int r, idx;
 -              unsigned int nonzero_rates = 0;
  
                fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
                if (fp->rate_table == NULL) {
                        return -1;
                }
  
 -              fp->nr_rates = nr_rates;
 -              fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
 +              fp->nr_rates = 0;
 +              fp->rate_min = fp->rate_max = 0;
                for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
                        unsigned int rate = combine_triple(&fmt[idx]);
 +                      if (!rate)
 +                              continue;
                        /* C-Media CM6501 mislabels its 96 kHz altsetting */
                        if (rate == 48000 && nr_rates == 1 &&
 -                          chip->usb_id == USB_ID(0x0d8c, 0x0201) &&
 +                          (chip->usb_id == USB_ID(0x0d8c, 0x0201) ||
 +                           chip->usb_id == USB_ID(0x0d8c, 0x0102)) &&
                            fp->altsetting == 5 && fp->maxpacksize == 392)
                                rate = 96000;
 -                      fp->rate_table[r] = rate;
 -                      nonzero_rates |= rate;
 -                      if (rate < fp->rate_min)
 +                      fp->rate_table[fp->nr_rates] = rate;
 +                      if (!fp->rate_min || rate < fp->rate_min)
                                fp->rate_min = rate;
 -                      else if (rate > fp->rate_max)
 +                      if (!fp->rate_max || rate > fp->rate_max)
                                fp->rate_max = rate;
                        fp->rates |= snd_pcm_rate_to_rate_bit(rate);
 +                      fp->nr_rates++;
                }
 -              if (!nonzero_rates) {
 +              if (!fp->nr_rates) {
                        hwc_debug("All rates were zero. Skipping format!\n");
                        return -1;
                }
@@@ -2621,7 -2606,7 +2608,7 @@@ static int parse_audio_format_ii(struc
                fp->format = SNDRV_PCM_FORMAT_MPEG;
                break;
        default:
-               snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected.  processed as MPEG.\n",
+               snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n",
                           chip->dev->devnum, fp->iface, fp->altsetting, format);
                fp->format = SNDRV_PCM_FORMAT_MPEG;
                break;
@@@ -2819,7 -2804,7 +2806,7 @@@ static int parse_audio_endpoints(struc
                        continue;
                }
  
-               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
+               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
                err = add_audio_endpoint(chip, stream, fp);
                if (err < 0) {
                        kfree(fp->rate_table);
@@@ -2968,7 -2953,6 +2955,7 @@@ static int create_fixed_stream_quirk(st
                return -EINVAL;
        }
        alts = &iface->altsetting[fp->altset_idx];
 +      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);
        init_usb_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max);
@@@ -3466,10 -3450,10 +3453,10 @@@ static int snd_usb_audio_create(struct 
                return -ENXIO;
        }
  
 -      card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0);
 -      if (card == NULL) {
 +      err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
 +      if (err < 0) {
                snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
 -              return -ENOMEM;
 +              return err;
        }
  
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
@@@ -3766,7 -3750,7 +3753,7 @@@ static int usb_audio_resume(struct usb_
  
  static int __init snd_usb_audio_init(void)
  {
-       if (nrpacks < MIN_PACKS_URB || nrpacks > MAX_PACKS) {
+       if (nrpacks < 1 || nrpacks > MAX_PACKS) {
                printk(KERN_WARNING "invalid nrpacks value.\n");
                return -EINVAL;
        }
diff --combined sound/usb/usbmixer.c
index 2bde79216fa560e674565bc450cd7720f7b34286,6615cd3b4079a927ab262a821cee90f083906cc5..ecb58e7a6245f5bea88294093628a23c54744643
@@@ -66,6 -66,7 +66,7 @@@ static const struct rc_config 
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
+       { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
  };
  
  struct usb_mixer_interface {
@@@ -78,6 -79,7 +79,6 @@@
  
        /* Sound Blaster remote control stuff */
        const struct rc_config *rc_cfg;
 -      unsigned long rc_hwdep_open;
        u32 rc_code;
        wait_queue_head_t rc_waitq;
        struct urb *rc_urb;
@@@ -109,6 -111,8 +110,8 @@@ struct mixer_build 
        const struct usbmix_selector_map *selector_map;
  };
  
+ #define MAX_CHANNELS  10      /* max logical channels */
  struct usb_mixer_elem_info {
        struct usb_mixer_interface *mixer;
        struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
        int channels;
        int val_type;
        int min, max, res;
+       int cached;
+       int cache_val[MAX_CHANNELS];
        u8 initialized;
  };
  
@@@ -180,8 -186,6 +185,6 @@@ enum 
        USB_PROC_DCR_RELEASE = 6,
  };
  
- #define MAX_CHANNELS  10      /* max logical channels */
  
  /*
   * manual mapping of mixer names
@@@ -218,7 -222,10 +221,10 @@@ static int check_ignored_ctl(struct mix
        for (p = state->map; p->id; p++) {
                if (p->id == unitid && ! p->name &&
                    (! control || ! p->control || control == p->control)) {
-                       // printk("ignored control %d:%d\n", unitid, control);
+                       /*
+                       printk(KERN_DEBUG "ignored control %d:%d\n",
+                              unitid, control);
+                       */
                        return 1;
                }
        }
@@@ -375,11 -382,35 +381,35 @@@ static int get_cur_ctl_value(struct usb
  }
  
  /* channel = 0: master, 1 = first channel */
- static inline int get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int *value)
+ static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
+                                 int channel, int *value)
  {
        return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
  }
  
+ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
+                            int channel, int index, int *value)
+ {
+       int err;
+       if (cval->cached & (1 << channel)) {
+               *value = cval->cache_val[index];
+               return 0;
+       }
+       err = get_cur_mix_raw(cval, channel, value);
+       if (err < 0) {
+               if (!cval->mixer->ignore_ctl_error)
+                       snd_printd(KERN_ERR "cannot get current value for "
+                                  "control %d ch %d: err = %d\n",
+                                  cval->control, channel, err);
+               return err;
+       }
+       cval->cached |= 1 << channel;
+       cval->cache_val[index] = *value;
+       return 0;
+ }
  /*
   * set a mixer value
   */
@@@ -411,9 -442,17 +441,17 @@@ static int set_cur_ctl_value(struct usb
        return set_ctl_value(cval, SET_CUR, validx, value);
  }
  
- static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int value)
+ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
+                            int index, int value)
  {
-       return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
+       int err;
+       err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel,
+                           value);
+       if (err < 0)
+               return err;
+       cval->cached |= 1 << channel;
+       cval->cache_val[index] = value;
+       return 0;
  }
  
  /*
@@@ -717,7 -756,7 +755,7 @@@ static int get_min_max(struct usb_mixer
                if (cval->min + cval->res < cval->max) {
                        int last_valid_res = cval->res;
                        int saved, test, check;
-                       get_cur_mix_value(cval, minchn, &saved);
+                       get_cur_mix_raw(cval, minchn, &saved);
                        for (;;) {
                                test = saved;
                                if (test < cval->max)
                                else
                                        test -= cval->res;
                                if (test < cval->min || test > cval->max ||
-                                   set_cur_mix_value(cval, minchn, test) ||
-                                   get_cur_mix_value(cval, minchn, &check)) {
+                                   set_cur_mix_value(cval, minchn, 0, test) ||
+                                   get_cur_mix_raw(cval, minchn, &check)) {
                                        cval->res = last_valid_res;
                                        break;
                                }
                                        break;
                                cval->res *= 2;
                        }
-                       set_cur_mix_value(cval, minchn, saved);
+                       set_cur_mix_value(cval, minchn, 0, saved);
                }
  
                cval->initialized = 1;
@@@ -774,35 -813,25 +812,25 @@@ static int mixer_ctl_feature_get(struc
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
        int c, cnt, val, err;
  
+       ucontrol->value.integer.value[0] = cval->min;
        if (cval->cmask) {
                cnt = 0;
                for (c = 0; c < MAX_CHANNELS; c++) {
-                       if (cval->cmask & (1 << c)) {
-                               err = get_cur_mix_value(cval, c + 1, &val);
-                               if (err < 0) {
-                                       if (cval->mixer->ignore_ctl_error) {
-                                               ucontrol->value.integer.value[0] = cval->min;
-                                               return 0;
-                                       }
-                                       snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
-                                       return err;
-                               }
-                               val = get_relative_value(cval, val);
-                               ucontrol->value.integer.value[cnt] = val;
-                               cnt++;
-                       }
+                       if (!(cval->cmask & (1 << c)))
+                               continue;
+                       err = get_cur_mix_value(cval, c + 1, cnt, &val);
+                       if (err < 0)
+                               return cval->mixer->ignore_ctl_error ? 0 : err;
+                       val = get_relative_value(cval, val);
+                       ucontrol->value.integer.value[cnt] = val;
+                       cnt++;
                }
+               return 0;
        } else {
                /* master channel */
-               err = get_cur_mix_value(cval, 0, &val);
-               if (err < 0) {
-                       if (cval->mixer->ignore_ctl_error) {
-                               ucontrol->value.integer.value[0] = cval->min;
-                               return 0;
-                       }
-                       snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err);
-                       return err;
-               }
+               err = get_cur_mix_value(cval, 0, 0, &val);
+               if (err < 0)
+                       return cval->mixer->ignore_ctl_error ? 0 : err;
                val = get_relative_value(cval, val);
                ucontrol->value.integer.value[0] = val;
        }
@@@ -819,34 -848,28 +847,28 @@@ static int mixer_ctl_feature_put(struc
        if (cval->cmask) {
                cnt = 0;
                for (c = 0; c < MAX_CHANNELS; c++) {
-                       if (cval->cmask & (1 << c)) {
-                               err = get_cur_mix_value(cval, c + 1, &oval);
-                               if (err < 0) {
-                                       if (cval->mixer->ignore_ctl_error)
-                                               return 0;
-                                       return err;
-                               }
-                               val = ucontrol->value.integer.value[cnt];
-                               val = get_abs_value(cval, val);
-                               if (oval != val) {
-                                       set_cur_mix_value(cval, c + 1, val);
-                                       changed = 1;
-                               }
-                               get_cur_mix_value(cval, c + 1, &val);
-                               cnt++;
+                       if (!(cval->cmask & (1 << c)))
+                               continue;
+                       err = get_cur_mix_value(cval, c + 1, cnt, &oval);
+                       if (err < 0)
+                               return cval->mixer->ignore_ctl_error ? 0 : err;
+                       val = ucontrol->value.integer.value[cnt];
+                       val = get_abs_value(cval, val);
+                       if (oval != val) {
+                               set_cur_mix_value(cval, c + 1, cnt, val);
+                               changed = 1;
                        }
+                       cnt++;
                }
        } else {
                /* master channel */
-               err = get_cur_mix_value(cval, 0, &oval);
-               if (err < 0 && cval->mixer->ignore_ctl_error)
-                       return 0;
+               err = get_cur_mix_value(cval, 0, 0, &oval);
                if (err < 0)
-                       return err;
+                       return cval->mixer->ignore_ctl_error ? 0 : err;
                val = ucontrol->value.integer.value[0];
                val = get_abs_value(cval, val);
                if (val != oval) {
-                       set_cur_mix_value(cval, 0, val);
+                       set_cur_mix_value(cval, 0, 0, val);
                        changed = 1;
                }
        }
@@@ -1705,7 -1728,8 +1727,8 @@@ static void snd_usb_mixer_memory_change
                break;
        /* live24ext: 4 = line-in jack */
        case 3: /* hp-out jack (may actuate Mute) */
-               if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+               if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                   mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
                        snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
                break;
        default:
@@@ -1796,6 -1820,24 +1819,6 @@@ static void snd_usb_soundblaster_remote
        wake_up(&mixer->rc_waitq);
  }
  
 -static int snd_usb_sbrc_hwdep_open(struct snd_hwdep *hw, struct file *file)
 -{
 -      struct usb_mixer_interface *mixer = hw->private_data;
 -
 -      if (test_and_set_bit(0, &mixer->rc_hwdep_open))
 -              return -EBUSY;
 -      return 0;
 -}
 -
 -static int snd_usb_sbrc_hwdep_release(struct snd_hwdep *hw, struct file *file)
 -{
 -      struct usb_mixer_interface *mixer = hw->private_data;
 -
 -      clear_bit(0, &mixer->rc_hwdep_open);
 -      smp_mb__after_clear_bit();
 -      return 0;
 -}
 -
  static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf,
                                     long count, loff_t *offset)
  {
@@@ -1848,8 -1890,9 +1871,8 @@@ static int snd_usb_soundblaster_remote_
        hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;
        hwdep->private_data = mixer;
        hwdep->ops.read = snd_usb_sbrc_hwdep_read;
 -      hwdep->ops.open = snd_usb_sbrc_hwdep_open;
 -      hwdep->ops.release = snd_usb_sbrc_hwdep_release;
        hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;
 +      hwdep->exclusive = 1;
  
        mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!mixer->rc_urb)
@@@ -1936,8 -1979,9 +1959,9 @@@ static int snd_audigy2nx_controls_creat
        int i, err;
  
        for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
-               if (i > 1 &&  /* Live24ext has 2 LEDs only */
-                       mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+               if (i > 1 && /* Live24ext has 2 LEDs only */
+                       (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                        mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
                        break; 
                err = snd_ctl_add(mixer->chip->card,
                                  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
@@@ -1974,7 -2018,8 +1998,8 @@@ static void snd_audigy2nx_proc_read(str
        snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
                jacks = jacks_audigy2nx;
-       else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+       else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
                jacks = jacks_live24ext;
        else
                return;
@@@ -2024,7 -2069,8 +2049,8 @@@ int snd_usb_create_mixer(struct snd_usb
                goto _error;
  
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
-           mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) {
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
                struct snd_info_entry *entry;
  
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
diff --combined sound/usb/usbquirks.h
index 5d8ef09b9dcc17d01f85d2ca27047a7faa30fe4f,d59323ecd571d0121379b404db59b3f261da1b4a..647ef502965179ec6f1eec15c042990a950aedf6
        .idProduct = prod, \
        .bInterfaceClass = USB_CLASS_VENDOR_SPEC
  
+ /* Creative/Toshiba Multimedia Center SB-0500 */
+ {
+       USB_DEVICE(0x041e, 0x3048),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Toshiba",
+               .product_name = "SB-0500",
+               .ifnum = QUIRK_NO_INTERFACE
+       }
+ },
  /* Creative/E-Mu devices */
  {
        USB_DEVICE(0x041e, 0x3010),
        .bInterfaceClass = USB_CLASS_AUDIO,
        .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
  },
 +{
 +      USB_DEVICE(0x046d, 0x0990),
 +      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 +              .vendor_name = "Logitech, Inc.",
 +              .product_name = "QuickCam Pro 9000",
 +              .ifnum = QUIRK_NO_INTERFACE
 +      }
 +},
  
  /*
   * Yamaha devices