Commit 3360b84b authored by Takashi Iwai's avatar Takashi Iwai

ALSA: usb-audio: Allow quirks to handle own resume and proc dump

So far, we blindly assumed that the all usb-audio mixer elements
follow the standard and apply the standard resume method for the
registered elements in the id_elems[] list.  However, some quirks
really need the own resume and it's incomplete for now.

This patch enhances the resume handling in two folds:
- split some fields in struct usb_mixer_elem_info into a smaller
  header struct (usb_mixer_elem_list) for keeping the minimal
  information in the linked-list; the usb_mixer_elem_info embeds this
  header struct instead
- add resume and dump callbacks to usb_mixer_elem_list struct to allow
  quirks providing the own methods

For the standard mixer elements, these new callbacks are set to the
standard ones as default, thus there is no functional change by this
patch yet.

The dump and resume callbacks are typedef'ed for ease of later patches
using arrays of such function pointers.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 5aeee342
This diff is collapsed.
#ifndef __USBMIXER_H
#define __USBMIXER_H
#include <sound/info.h>
struct usb_mixer_interface {
struct snd_usb_audio *chip;
struct usb_host_interface *hostif;
......@@ -8,7 +10,7 @@ struct usb_mixer_interface {
unsigned int ignore_ctl_error;
struct urb *urb;
/* array[MAX_ID_ELEMS], indexed by unit id */
struct usb_mixer_elem_info **id_elems;
struct usb_mixer_elem_list **id_elems;
/* the usb audio specification version this interface complies to */
int protocol;
......@@ -36,11 +38,21 @@ enum {
USB_MIXER_U16,
};
struct usb_mixer_elem_info {
typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
struct usb_mixer_elem_list *list);
typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem);
struct usb_mixer_elem_list {
struct usb_mixer_interface *mixer;
struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
struct snd_ctl_elem_id *elem_id;
struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */
struct snd_kcontrol *kctl;
unsigned int id;
usb_mixer_elem_dump_func_t dump;
usb_mixer_elem_resume_func_t resume;
};
struct usb_mixer_elem_info {
struct usb_mixer_elem_list head;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
unsigned int idx_off; /* Control index offset */
......@@ -65,9 +77,13 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set);
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
struct snd_kcontrol *kctl);
void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
struct usb_mixer_interface *mixer,
int unitid);
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv);
......
......@@ -69,7 +69,6 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
const char *name,
snd_kcontrol_tlv_rw_t *tlv_callback)
{
int err;
struct usb_mixer_elem_info *cval;
struct snd_kcontrol *kctl;
......@@ -77,8 +76,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
if (!cval)
return -ENOMEM;
cval->id = unitid;
cval->mixer = mixer;
snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid);
cval->val_type = val_type;
cval->channels = 1;
cval->control = control;
......@@ -112,11 +110,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
}
/* Add control to mixer */
err = snd_usb_mixer_add_control(mixer, kctl);
if (err < 0)
return err;
return 0;
return snd_usb_mixer_add_control(&cval->head, kctl);
}
static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
......@@ -1206,7 +1200,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
int unitid = 12; /* SamleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) {
cval = mixer->id_elems[unitid];
cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid];
if (cval) {
snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
cval->control << 8,
......
......@@ -436,10 +436,10 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_info *elem = kctl->private_data;
struct snd_usb_audio *chip = elem->mixer->chip;
struct snd_usb_audio *chip = elem->head.mixer->chip;
unsigned char buf[2 * MAX_CHANNELS] = {0, };
int wValue = (elem->control << 8) | elem->idx_off;
int idx = snd_usb_ctrl_intf(chip) | (elem->id << 8);
int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
int err;
err = snd_usb_ctl_msg(chip->dev,
......@@ -528,10 +528,10 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
if (!elem)
return -ENOMEM;
elem->mixer = mixer;
elem->head.mixer = mixer;
elem->control = offset;
elem->idx_off = num;
elem->id = index;
elem->head.id = index;
elem->val_type = val_type;
elem->channels = channels;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment