Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 288673be authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: usb-audio: Add resume support for MicroII SPDIF ctls



Like the previous fixes, the mixer accessors are converted to use
usb_mixer_elem_list objects.  In addition, the proper shutdown check
are put in get and put callbacks.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 0b4e9cfc
Loading
Loading
Loading
Loading
+93 −42
Original line number Diff line number Diff line
@@ -1509,7 +1509,8 @@ static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
	struct snd_usb_audio *chip = list->mixer->chip;
	int err;
	struct usb_interface *iface;
	struct usb_host_interface *alts;
@@ -1517,17 +1518,23 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
	unsigned char data[3];
	int rate;

	down_read(&chip->shutdown_rwsem);
	if (chip->shutdown) {
		err = -ENODEV;
		goto end;
	}

	ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
	ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
	ucontrol->value.iec958.status[2] = 0x00;

	/* use known values for that card: interface#1 altsetting#1 */
	iface = usb_ifnum_to_if(mixer->chip->dev, 1);
	iface = usb_ifnum_to_if(chip->dev, 1);
	alts = &iface->altsetting[1];
	ep = get_endpoint(alts, 0)->bEndpointAddress;

	err = snd_usb_ctl_msg(mixer->chip->dev,
			usb_rcvctrlpipe(mixer->chip->dev, 0),
	err = snd_usb_ctl_msg(chip->dev,
			usb_rcvctrlpipe(chip->dev, 0),
			UAC_GET_CUR,
			USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
			UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
@@ -1543,21 +1550,26 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,

	err = 0;
 end:
	up_read(&chip->shutdown_rwsem);
	return err;
}

static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list)
{
	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
	int err;
	struct snd_usb_audio *chip = list->mixer->chip;
	unsigned int pval = list->kctl->private_value;
	u8 reg;
	unsigned long priv_backup = kcontrol->private_value;
	int err;

	reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
			(ucontrol->value.iec958.status[0] & 0x0f);
	err = snd_usb_ctl_msg(mixer->chip->dev,
			usb_sndctrlpipe(mixer->chip->dev, 0),
	down_read(&chip->shutdown_rwsem);
	if (chip->shutdown) {
		err = -ENODEV;
		goto end;
	}

	reg = ((pval >> 4) & 0xf0) | (pval & 0x0f);
	err = snd_usb_ctl_msg(chip->dev,
			usb_sndctrlpipe(chip->dev, 0),
			UAC_SET_CUR,
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
			reg,
@@ -1567,15 +1579,10 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
	if (err < 0)
		goto end;

	kcontrol->private_value &= 0xfffff0f0;
	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
	kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);

	reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
			0xa0 : 0x20;
	reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
	err = snd_usb_ctl_msg(mixer->chip->dev,
			usb_sndctrlpipe(mixer->chip->dev, 0),
	reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20;
	reg |= (pval >> 12) & 0x0f;
	err = snd_usb_ctl_msg(chip->dev,
			usb_sndctrlpipe(chip->dev, 0),
			UAC_SET_CUR,
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
			reg,
@@ -1585,16 +1592,36 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
	if (err < 0)
		goto end;

	kcontrol->private_value &= 0xffff0fff;
	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
 end:
	up_read(&chip->shutdown_rwsem);
	return err;
}

static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
	unsigned int pval, pval_old;
	int err;

	pval = pval_old = kcontrol->private_value;
	pval &= 0xfffff0f0;
	pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
	pval |= (ucontrol->value.iec958.status[0] & 0x0f);

	pval &= 0xffff0fff;
	pval |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;

	/* The frequency bits in AES3 cannot be set via register access. */

	/* Silently ignore any bits from the request that cannot be set. */

	err = (priv_backup != kcontrol->private_value);
end:
	return err;
	if (pval == pval_old)
		return 0;

	kcontrol->private_value = pval;
	err = snd_microii_spdif_default_update(list);
	return err < 0 ? err : 1;
}

static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
@@ -1616,15 +1643,20 @@ static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
	return 0;
}

static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list)
{
	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
	struct snd_usb_audio *chip = list->mixer->chip;
	u8 reg = list->kctl->private_value;
	int err;
	u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;

	err = snd_usb_ctl_msg(mixer->chip->dev,
			usb_sndctrlpipe(mixer->chip->dev, 0),
	down_read(&chip->shutdown_rwsem);
	if (chip->shutdown) {
		err = -ENODEV;
		goto end;
	}

	err = snd_usb_ctl_msg(chip->dev,
			usb_sndctrlpipe(chip->dev, 0),
			UAC_SET_CUR,
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
			reg,
@@ -1632,13 +1664,25 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
			NULL,
			0);

	if (!err) {
		err = (reg != (kcontrol->private_value & 0x0ff));
		if (err)
			kcontrol->private_value = reg;
 end:
	up_read(&chip->shutdown_rwsem);
	return err;
}

	return err;
static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
	u8 reg;
	int err;

	reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
	if (reg != list->kctl->private_value)
		return 0;

	kcontrol->private_value = reg;
	err = snd_microii_spdif_switch_update(list);
	return err < 0 ? err : 1;
}

static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
@@ -1670,10 +1714,17 @@ static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
{
	int err, i;
	static usb_mixer_elem_resume_func_t resume_funcs[] = {
		snd_microii_spdif_default_update,
		NULL,
		snd_microii_spdif_switch_update
	};

	for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
		err = snd_ctl_add(mixer->chip->card,
			snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
		err = add_single_ctl_with_resume(mixer, 0,
						 resume_funcs[i],
						 &snd_microii_mixer_spdif[i],
						 NULL);
		if (err < 0)
			return err;
	}