Merge branch 'topic/usb-audio' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Thu, 10 Sep 2009 13:33:07 +0000 (15:33 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 10 Sep 2009 13:33:07 +0000 (15:33 +0200)
* topic/usb-audio:
  ALSA: usb-audio - Fix types taken in min()
  sound: usb-audio: do not make URBs longer than sync packet interval
  sound: usb-audio: add MIDI drain callback
  sound: usb-audio: use multiple output URBs
  sound: usb-audio: use multiple input URBs
  sound: usb-audio: Xonar U1 digital output support

1  2 
sound/usb/usbaudio.c
sound/usb/usbmixer.c

diff --combined sound/usb/usbaudio.c
@@@ -1083,6 -1083,8 +1083,8 @@@ static int init_substream_urbs(struct s
        } else
                urb_packs = 1;
        urb_packs *= packs_per_ms;
+       if (subs->syncpipe)
+               urb_packs = min(urb_packs, 1U << subs->syncinterval);
  
        /* decide how many packets to be used */
        if (is_playback) {
@@@ -2124,8 -2126,8 +2126,8 @@@ 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: %#x (%d bits)\n",
 -                          fp->format, snd_pcm_format_width(fp->format));
 +              snd_iprintf(buffer, "    Format: %s\n",
 +                          snd_pcm_format_name(fp->format));
                snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
                            fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
diff --combined sound/usb/usbmixer.c
@@@ -86,6 -86,7 +86,7 @@@ struct usb_mixer_interface 
        u8 rc_buffer[6];
  
        u8 audigy2nx_leds[3];
+       u8 xonar_u1_status;
  };
  
  
@@@ -461,7 -462,7 +462,7 @@@ static int mixer_vol_tlv(struct snd_kco
                         unsigned int size, unsigned int __user *_tlv)
  {
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
 -      DECLARE_TLV_DB_SCALE(scale, 0, 0, 0);
 +      DECLARE_TLV_DB_MINMAX(scale, 0, 0);
  
        if (size < sizeof(scale))
                return -ENOMEM;
         * while ALSA TLV contains in 1/100 dB unit
         */
        scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
 -      scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256;
 +      scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
 +      if (scale[3] <= scale[2]) {
 +              /* something is wrong; assume it's either from/to 0dB */
 +              if (scale[2] < 0)
 +                      scale[3] = 0;
 +              else if (scale[2] > 0)
 +                      scale[2] = 0;
 +              else /* totally crap, return an error */
 +                      return -EINVAL;
 +      }
        if (copy_to_user(_tlv, scale, sizeof(scale)))
                return -EFAULT;
        return 0;
@@@ -999,35 -991,20 +1000,35 @@@ static void build_feature_ctl(struct mi
                break;
        }
  
 -      /* quirk for UDA1321/N101 */
 -      /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */
 -      /* is not very clear from datasheets */
 -      /* I hope that the min value is -15360 for newer firmware --jk */
 +      /* volume control quirks */
        switch (state->chip->usb_id) {
        case USB_ID(0x0471, 0x0101):
        case USB_ID(0x0471, 0x0104):
        case USB_ID(0x0471, 0x0105):
        case USB_ID(0x0672, 0x1041):
 +      /* quirk for UDA1321/N101.
 +       * note that detection between firmware 2.1.1.7 (N101)
 +       * and later 2.1.1.21 is not very clear from datasheets.
 +       * I hope that the min value is -15360 for newer firmware --jk
 +       */
                if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
                    cval->min == -15616) {
 -                      snd_printk(KERN_INFO "using volume control quirk for the UDA1321/N101 chip\n");
 +                      snd_printk(KERN_INFO
 +                               "set volume quirk for UDA1321/N101 chip\n");
                        cval->max = -256;
                }
 +              break;
 +
 +      case USB_ID(0x046d, 0x09a4):
 +              if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
 +                      snd_printk(KERN_INFO
 +                              "set volume quirk for QuickCam E3500\n");
 +                      cval->min = 6080;
 +                      cval->max = 8768;
 +                      cval->res = 192;
 +              }
 +              break;
 +
        }
  
        snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
@@@ -2042,6 -2019,58 +2043,58 @@@ static void snd_audigy2nx_proc_read(str
        }
  }
  
+ static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+ {
+       struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
+       return 0;
+ }
+ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+ {
+       struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+       u8 old_status, new_status;
+       int err, changed;
+       old_status = mixer->xonar_u1_status;
+       if (ucontrol->value.integer.value[0])
+               new_status = old_status | 0x02;
+       else
+               new_status = old_status & ~0x02;
+       changed = new_status != old_status;
+       err = snd_usb_ctl_msg(mixer->chip->dev,
+                             usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             50, 0, &new_status, 1, 100);
+       if (err < 0)
+               return err;
+       mixer->xonar_u1_status = new_status;
+       return changed;
+ }
+ static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Digital Playback Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = snd_xonar_u1_switch_get,
+       .put = snd_xonar_u1_switch_put,
+ };
+ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
+ {
+       int err;
+       err = snd_ctl_add(mixer->chip->card,
+                         snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
+       if (err < 0)
+               return err;
+       mixer->xonar_u1_status = 0x05;
+       return 0;
+ }
  int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                         int ignore_error)
  {
                                              snd_audigy2nx_proc_read);
        }
  
+       if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) ||
+           mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) {
+               err = snd_xonar_u1_controls_create(mixer);
+               if (err < 0)
+                       goto _error;
+       }
        err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
        if (err < 0)
                goto _error;