cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

power.c (2558B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *   UAC3 Power Domain state management functions
      4 */
      5
      6#include <linux/slab.h>
      7#include <linux/usb.h>
      8#include <linux/usb/audio.h>
      9#include <linux/usb/audio-v2.h>
     10#include <linux/usb/audio-v3.h>
     11
     12#include "usbaudio.h"
     13#include "helper.h"
     14#include "power.h"
     15
     16struct snd_usb_power_domain *
     17snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
     18			  unsigned char id)
     19{
     20	struct snd_usb_power_domain *pd;
     21	void *p;
     22
     23	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
     24	if (!pd)
     25		return NULL;
     26
     27	p = NULL;
     28	while ((p = snd_usb_find_csint_desc(ctrl_iface->extra,
     29					    ctrl_iface->extralen,
     30					    p, UAC3_POWER_DOMAIN)) != NULL) {
     31		struct uac3_power_domain_descriptor *pd_desc = p;
     32		int i;
     33
     34		if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3))
     35			continue;
     36		for (i = 0; i < pd_desc->bNrEntities; i++) {
     37			if (pd_desc->baEntityID[i] == id) {
     38				pd->pd_id = pd_desc->bPowerDomainID;
     39				pd->pd_d1d0_rec =
     40					le16_to_cpu(pd_desc->waRecoveryTime1);
     41				pd->pd_d2d0_rec =
     42					le16_to_cpu(pd_desc->waRecoveryTime2);
     43				return pd;
     44			}
     45		}
     46	}
     47
     48	kfree(pd);
     49	return NULL;
     50}
     51
     52int snd_usb_power_domain_set(struct snd_usb_audio *chip,
     53			     struct snd_usb_power_domain *pd,
     54			     unsigned char state)
     55{
     56	struct usb_device *dev = chip->dev;
     57	unsigned char current_state;
     58	int err, idx;
     59
     60	idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
     61
     62	err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
     63			      UAC2_CS_CUR,
     64			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
     65			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
     66			      &current_state, sizeof(current_state));
     67	if (err < 0) {
     68		dev_err(&dev->dev, "Can't get UAC3 power state for id %d\n",
     69			pd->pd_id);
     70		return err;
     71	}
     72
     73	if (current_state == state) {
     74		dev_dbg(&dev->dev, "UAC3 power domain id %d already in state %d\n",
     75			pd->pd_id, state);
     76		return 0;
     77	}
     78
     79	err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
     80			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
     81			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
     82			      &state, sizeof(state));
     83	if (err < 0) {
     84		dev_err(&dev->dev, "Can't set UAC3 power state to %d for id %d\n",
     85			state, pd->pd_id);
     86		return err;
     87	}
     88
     89	if (state == UAC3_PD_STATE_D0) {
     90		switch (current_state) {
     91		case UAC3_PD_STATE_D2:
     92			udelay(pd->pd_d2d0_rec * 50);
     93			break;
     94		case UAC3_PD_STATE_D1:
     95			udelay(pd->pd_d1d0_rec * 50);
     96			break;
     97		default:
     98			return -EINVAL;
     99		}
    100	}
    101
    102	dev_dbg(&dev->dev, "UAC3 power domain id %d change to state %d\n",
    103		pd->pd_id, state);
    104
    105	return 0;
    106}