OSDN Git Service

ALSA: usb-audio - Fix missing mixer dB information
[android-x86/kernel.git] / sound / usb / mixer.c
index eab06ed..cdd19d7 100644 (file)
@@ -86,16 +86,6 @@ struct mixer_build {
        const struct usbmix_selector_map *selector_map;
 };
 
-enum {
-       USB_MIXER_BOOLEAN,
-       USB_MIXER_INV_BOOLEAN,
-       USB_MIXER_S8,
-       USB_MIXER_U8,
-       USB_MIXER_S16,
-       USB_MIXER_U16,
-};
-
-
 /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/
 enum {
        USB_XU_CLOCK_RATE               = 0xe301,
@@ -162,6 +152,7 @@ static inline void check_mapped_dB(const struct usbmix_name_map *p,
        if (p && p->dB) {
                cval->dBmin = p->dB->min;
                cval->dBmax = p->dB->max;
+               cval->initialized = 1;
        }
 }
 
@@ -535,20 +526,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou
  * if failed, give up and free the control instance.
  */
 
-static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl)
+int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+                             struct snd_kcontrol *kctl)
 {
        struct usb_mixer_elem_info *cval = kctl->private_data;
        int err;
 
-       while (snd_ctl_find_id(state->chip->card, &kctl->id))
+       while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
                kctl->id.index++;
-       if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
+       if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
                snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
                return err;
        }
        cval->elem_id = &kctl->id;
-       cval->next_id_elem = state->mixer->id_elems[cval->id];
-       state->mixer->id_elems[cval->id] = cval;
+       cval->next_id_elem = mixer->id_elems[cval->id];
+       mixer->id_elems[cval->id] = cval;
        return 0;
 }
 
@@ -984,6 +976,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = {
        .put = NULL,
 };
 
+/* This symbol is exported in order to allow the mixer quirks to
+ * hook up to the standard feature unit control mechanism */
+struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl;
 
 /*
  * build a feature control
@@ -1098,7 +1093,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                                " Switch" : " Volume");
                if (control == UAC_FU_VOLUME) {
                        check_mapped_dB(map, cval);
-                       if (cval->dBmin < cval->dBmax) {
+                       if (cval->dBmin < cval->dBmax || !cval->initialized) {
                                kctl->tlv.c = mixer_vol_tlv;
                                kctl->vd[0].access |= 
                                        SNDRV_CTL_ELEM_ACCESS_TLV_READ |
@@ -1176,7 +1171,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
 
        snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
-       add_control_to_empty(state, kctl);
+       snd_usb_mixer_add_control(state->mixer, kctl);
 }
 
 
@@ -1197,6 +1192,11 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
 
        if (state->mixer->protocol == UAC_VERSION_1) {
                csize = hdr->bControlSize;
+               if (!csize) {
+                       snd_printdd(KERN_ERR "usbaudio: unit %u: "
+                                   "invalid bControlSize == 0\n", unitid);
+                       return -EINVAL;
+               }
                channels = (hdr->bLength - 7) / csize - 1;
                bmaControls = hdr->bmaControls;
        } else {
@@ -1340,7 +1340,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
 
        snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
-       add_control_to_empty(state, kctl);
+       snd_usb_mixer_add_control(state->mixer, kctl);
 }
 
 
@@ -1641,7 +1641,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
 
                snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
                            cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
-               if ((err = add_control_to_empty(state, kctl)) < 0)
+               if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
                        return err;
        }
        return 0;
@@ -1858,7 +1858,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
 
        snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
                    cval->id, kctl->id.name, desc->bNrInPins);
-       if ((err = add_control_to_empty(state, kctl)) < 0)
+       if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
                return err;
 
        return 0;
@@ -1940,15 +1940,13 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        struct mixer_build state;
        int err;
        const struct usbmix_ctl_map *map;
-       struct usb_host_interface *hostif;
        void *p;
 
-       hostif = mixer->chip->ctrl_intf;
        memset(&state, 0, sizeof(state));
        state.chip = mixer->chip;
        state.mixer = mixer;
-       state.buffer = hostif->extra;
-       state.buflen = hostif->extralen;
+       state.buffer = mixer->hostif->extra;
+       state.buflen = mixer->hostif->extralen;
 
        /* check the mapping table */
        for (map = usbmix_ctl_maps; map->id; map++) {
@@ -1961,7 +1959,8 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        }
 
        p = NULL;
-       while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) {
+       while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen,
+                                           p, UAC_OUTPUT_TERMINAL)) != NULL) {
                if (mixer->protocol == UAC_VERSION_1) {
                        struct uac1_output_terminal_descriptor *desc = p;
 
@@ -2168,17 +2167,15 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
 /* create the handler for the optional status interrupt endpoint */
 static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
 {
-       struct usb_host_interface *hostif;
        struct usb_endpoint_descriptor *ep;
        void *transfer_buffer;
        int buffer_length;
        unsigned int epnum;
 
-       hostif = mixer->chip->ctrl_intf;
        /* we need one interrupt input endpoint */
-       if (get_iface_desc(hostif)->bNumEndpoints < 1)
+       if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1)
                return 0;
-       ep = get_endpoint(hostif, 0);
+       ep = get_endpoint(mixer->hostif, 0);
        if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))
                return 0;
 
@@ -2208,7 +2205,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        };
        struct usb_mixer_interface *mixer;
        struct snd_info_entry *entry;
-       struct usb_host_interface *host_iface;
        int err;
 
        strcpy(chip->card->mixername, "USB Mixer");
@@ -2225,8 +2221,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                return -ENOMEM;
        }
 
-       host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
-       switch (get_iface_desc(host_iface)->bInterfaceProtocol) {
+       mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
+       switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
        case UAC_VERSION_1:
        default:
                mixer->protocol = UAC_VERSION_1;