mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 17:22:07 +00:00
sound fixes for 6.9-rc2
A collection of device-specific small fixes: a series of fixes for TAS2781 HD-audio codec, ASoC SOF, Cirrus CS35L56 and a couple of legacy drivers. -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmYFLVMOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE+ixQ/+PXJZAqRA4ZZ1EAtfsEMs4aOwBkhVofS2A58j MdgJYGsjX9mX048hJ44e6nloVBJJNj7ZtxEC0haFJKLi/WOV7a4LUd1K7PLse1cF id+trvYmV3Bt9zHVMUlEorjg6ID/45mbYyeOYz3WKugZGZqgAZqocWaU45LmO7Xi YInDXAIk1InupAXikQUBVqjmqxR0w2fwnZ732YXfGyYzv9kdm8FaonZscPn48RHP N7Smrmoi37kQIRPpa5GwD2Xhqca254RAwohCn1S17WKRHpC4MSw4ArHAn3QhKyFL jJEOHSodwAIdfR1mPjfdBC8SVX+wkNrS3wlDeyJ4VFF7Dl+/2T/BOeWJ7vrDMjVh NAy6FCSBCuBY5kL9PA7USiioiIWgwoLEp5DSxcxUgoIPZ5U2nYCx6yMSHcth7u+r MY47xuHa9LSEPYRAxi33FgXmwepKgWk/3ywIslbbNF4efvghmdGPDdJL7+QVxvkt vnV66Q3OqUCP2QvkiUlGAhKX3GrQgiEvot6Xz8Y0hwpqnR/dEtubccxd8VHSQQq4 pzJ6WZI8z1VZd6p5Zi8vaG0LxNCPoSRAoE01ZeKzR350HoKTA7YCgKN2xD6PVwV5 hV6Zv9EMdrGMsaqb0a5kUAGnVyp9uJT069+95MCLVyGP/bvXTDMzHuNtHufDcn/0 /KyviuY= =g7xX -----END PGP SIGNATURE----- Merge tag 'sound-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound fixes from Takashi Iwai: "A collection of device-specific small fixes: a series of fixes for TAS2781 HD-audio codec, ASoC SOF, Cirrus CS35L56 and a couple of legacy drivers" * tag 'sound-6.9-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: ALSA: hda/tas2781: remove useless dev_dbg from playback_hook ALSA: hda/tas2781: add debug statements to kcontrols ALSA: hda/tas2781: add locks to kcontrols ALSA: hda/tas2781: remove digital gain kcontrol ALSA: aoa: avoid false-positive format truncation warning ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs ALSA: hda: cs35l56: Set the init_done flag before component_add() ALSA: hda: cs35l56: Raise device name message log level ASoC: SOF: ipc4-topology: support NHLT device type ALSA: hda: intel-nhlt: add intel_nhlt_ssp_device_type() function
This commit is contained in:
commit
529b10c009
@ -143,6 +143,9 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
|
||||
u32 bus_id, u8 link_type, u8 vbps, u8 bps,
|
||||
u8 num_ch, u32 rate, u8 dir, u8 dev_type);
|
||||
|
||||
int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt,
|
||||
u8 virtual_bus_id);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct nhlt_acpi_table *intel_nhlt_init(struct device *dev)
|
||||
@ -184,6 +187,13 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int intel_nhlt_ssp_device_type(struct device *dev,
|
||||
struct nhlt_acpi_table *nhlt,
|
||||
u8 virtual_bus_id)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -158,7 +158,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
||||
struct device_node *child, *sound = NULL;
|
||||
struct resource *r;
|
||||
int i, layout = 0, rlen, ok = force;
|
||||
char node_name[6];
|
||||
char node_name[8];
|
||||
static const char *rnames[] = { "i2sbus: %pOFn (control)",
|
||||
"i2sbus: %pOFn (tx)",
|
||||
"i2sbus: %pOFn (rx)" };
|
||||
|
@ -343,3 +343,29 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob);
|
||||
|
||||
int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt,
|
||||
u8 virtual_bus_id)
|
||||
{
|
||||
struct nhlt_endpoint *epnt;
|
||||
int i;
|
||||
|
||||
if (!nhlt)
|
||||
return -EINVAL;
|
||||
|
||||
epnt = (struct nhlt_endpoint *)nhlt->desc;
|
||||
for (i = 0; i < nhlt->endpoint_count; i++) {
|
||||
/* for SSP link the virtual bus id is the SSP port number */
|
||||
if (epnt->linktype == NHLT_LINK_SSP &&
|
||||
epnt->virtual_bus_id == virtual_bus_id) {
|
||||
dev_dbg(dev, "SSP%d: dev_type=%d\n", virtual_bus_id,
|
||||
epnt->device_type);
|
||||
return epnt->device_type;
|
||||
}
|
||||
|
||||
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(intel_nhlt_ssp_device_type);
|
||||
|
@ -1024,8 +1024,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
|
||||
cs35l56->system_name, cs35l56->amp_name);
|
||||
dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
|
||||
cs35l56->system_name, cs35l56->amp_name);
|
||||
|
||||
regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
|
||||
ARRAY_SIZE(cs35l56_hda_dai_config));
|
||||
@ -1045,14 +1045,14 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
|
||||
pm_runtime_mark_last_busy(cs35l56->base.dev);
|
||||
pm_runtime_enable(cs35l56->base.dev);
|
||||
|
||||
cs35l56->base.init_done = true;
|
||||
|
||||
ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
|
||||
if (ret) {
|
||||
dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
|
||||
goto pm_err;
|
||||
}
|
||||
|
||||
cs35l56->base.init_done = true;
|
||||
|
||||
return 0;
|
||||
|
||||
pm_err:
|
||||
|
@ -89,7 +89,7 @@ struct tas2781_hda {
|
||||
struct snd_kcontrol *dsp_prog_ctl;
|
||||
struct snd_kcontrol *dsp_conf_ctl;
|
||||
struct snd_kcontrol *prof_ctl;
|
||||
struct snd_kcontrol *snd_ctls[3];
|
||||
struct snd_kcontrol *snd_ctls[2];
|
||||
};
|
||||
|
||||
static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
|
||||
@ -161,8 +161,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(tas_hda->dev, "Playback action not supported: %d\n",
|
||||
action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -185,8 +183,15 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
|
||||
__func__, kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -200,11 +205,19 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
|
||||
|
||||
val = clamp(nr_profile, 0, max);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
|
||||
__func__, kcontrol->id.name,
|
||||
tas_priv->rcabin.profile_cfg_id, val);
|
||||
|
||||
if (tas_priv->rcabin.profile_cfg_id != val) {
|
||||
tas_priv->rcabin.profile_cfg_id = val;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -241,8 +254,15 @@ static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
ucontrol->value.integer.value[0] = tas_priv->cur_prog;
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
|
||||
__func__, kcontrol->id.name, tas_priv->cur_prog);
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -257,11 +277,18 @@ static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
|
||||
|
||||
val = clamp(nr_program, 0, max);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
|
||||
__func__, kcontrol->id.name, tas_priv->cur_prog, val);
|
||||
|
||||
if (tas_priv->cur_prog != val) {
|
||||
tas_priv->cur_prog = val;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -270,8 +297,15 @@ static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
ucontrol->value.integer.value[0] = tas_priv->cur_conf;
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
|
||||
__func__, kcontrol->id.name, tas_priv->cur_conf);
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -286,54 +320,39 @@ static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
|
||||
|
||||
val = clamp(nr_config, 0, max);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
|
||||
__func__, kcontrol->id.name, tas_priv->cur_conf, val);
|
||||
|
||||
if (tas_priv->cur_conf != val) {
|
||||
tas_priv->cur_conf = val;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* tas2781_digital_getvol - get the volum control
|
||||
* @kcontrol: control pointer
|
||||
* @ucontrol: User data
|
||||
* Customer Kcontrol for tas2781 is primarily for regmap booking, paging
|
||||
* depends on internal regmap mechanism.
|
||||
* tas2781 contains book and page two-level register map, especially
|
||||
* book switching will set the register BXXP00R7F, after switching to the
|
||||
* correct book, then leverage the mechanism for paging to access the
|
||||
* register.
|
||||
*/
|
||||
static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
|
||||
return tasdevice_digital_getvol(tas_priv, ucontrol, mc);
|
||||
}
|
||||
|
||||
static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
int ret;
|
||||
|
||||
return tasdevice_amp_getvol(tas_priv, ucontrol, mc);
|
||||
}
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
|
||||
|
||||
/* The check of the given value is in tasdevice_digital_putvol. */
|
||||
return tasdevice_digital_putvol(tas_priv, ucontrol, mc);
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",
|
||||
__func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
|
||||
@ -342,9 +361,19 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",
|
||||
__func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
|
||||
|
||||
/* The check of the given value is in tasdevice_amp_putvol. */
|
||||
return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
|
||||
ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc);
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
|
||||
@ -352,9 +381,13 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
|
||||
{
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
|
||||
dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
|
||||
tas_priv->force_fwload_status ? "ON" : "OFF");
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
|
||||
__func__, kcontrol->id.name, tas_priv->force_fwload_status);
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -365,14 +398,20 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
|
||||
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
|
||||
bool change, val = (bool)ucontrol->value.integer.value[0];
|
||||
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
||||
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
|
||||
__func__, kcontrol->id.name,
|
||||
tas_priv->force_fwload_status, val);
|
||||
|
||||
if (tas_priv->force_fwload_status == val)
|
||||
change = false;
|
||||
else {
|
||||
change = true;
|
||||
tas_priv->force_fwload_status = val;
|
||||
}
|
||||
dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
|
||||
tas_priv->force_fwload_status ? "ON" : "OFF");
|
||||
|
||||
mutex_unlock(&tas_priv->codec_lock);
|
||||
|
||||
return change;
|
||||
}
|
||||
@ -381,9 +420,6 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
|
||||
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
|
||||
1, 0, 20, 0, tas2781_amp_getvol,
|
||||
tas2781_amp_putvol, amp_vol_tlv),
|
||||
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL,
|
||||
0, 0, 200, 1, tas2781_digital_getvol,
|
||||
tas2781_digital_putvol, dvc_tlv),
|
||||
ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
|
||||
tas2781_force_fwload_get, tas2781_force_fwload_put),
|
||||
};
|
||||
|
@ -278,7 +278,8 @@ static void run_spu_dma(struct work_struct *work)
|
||||
dreamcastcard->clicks++;
|
||||
if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
|
||||
dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
|
||||
mod_timer(&dreamcastcard->timer, jiffies + 1);
|
||||
if (snd_pcm_running(dreamcastcard->substream))
|
||||
mod_timer(&dreamcastcard->timer, jiffies + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,6 +291,8 @@ static void aica_period_elapsed(struct timer_list *t)
|
||||
/*timer function - so cannot sleep */
|
||||
int play_period;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
if (!snd_pcm_running(substream))
|
||||
return;
|
||||
runtime = substream->runtime;
|
||||
dreamcastcard = substream->pcm->private_data;
|
||||
/* Have we played out an additional period? */
|
||||
@ -350,12 +353,19 @@ static int snd_aicapcm_pcm_open(struct snd_pcm_substream
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_aicapcm_pcm_sync_stop(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
|
||||
|
||||
del_timer_sync(&dreamcastcard->timer);
|
||||
cancel_work_sync(&dreamcastcard->spu_dma_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_aicapcm_pcm_close(struct snd_pcm_substream
|
||||
*substream)
|
||||
{
|
||||
struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
|
||||
flush_work(&(dreamcastcard->spu_dma_work));
|
||||
del_timer(&dreamcastcard->timer);
|
||||
dreamcastcard->substream = NULL;
|
||||
kfree(dreamcastcard->channel);
|
||||
spu_disable();
|
||||
@ -401,6 +411,7 @@ static const struct snd_pcm_ops snd_aicapcm_playback_ops = {
|
||||
.prepare = snd_aicapcm_pcm_prepare,
|
||||
.trigger = snd_aicapcm_pcm_trigger,
|
||||
.pointer = snd_aicapcm_pcm_pointer,
|
||||
.sync_stop = snd_aicapcm_pcm_sync_stop,
|
||||
};
|
||||
|
||||
/* TO DO: set up to handle more than one pcm instance */
|
||||
|
@ -1356,6 +1356,7 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
|
||||
int sample_rate, channel_count;
|
||||
int bit_depth, ret;
|
||||
u32 nhlt_type;
|
||||
int dev_type = 0;
|
||||
|
||||
/* convert to NHLT type */
|
||||
switch (linktype) {
|
||||
@ -1371,18 +1372,30 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
|
||||
&bit_depth);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We need to know the type of the external device attached to a SSP
|
||||
* port to retrieve the blob from NHLT. However, device type is not
|
||||
* specified in topology.
|
||||
* Query the type for the port and then pass that information back
|
||||
* to the blob lookup function.
|
||||
*/
|
||||
dev_type = intel_nhlt_ssp_device_type(sdev->dev, ipc4_data->nhlt,
|
||||
dai_index);
|
||||
if (dev_type < 0)
|
||||
return dev_type;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
|
||||
dai_index, nhlt_type, dir);
|
||||
dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d dev type %d\n",
|
||||
dai_index, nhlt_type, dir, dev_type);
|
||||
|
||||
/* find NHLT blob with matching params */
|
||||
cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
|
||||
bit_depth, bit_depth, channel_count, sample_rate,
|
||||
dir, 0);
|
||||
dir, dev_type);
|
||||
|
||||
if (!cfg) {
|
||||
dev_err(sdev->dev,
|
||||
|
Loading…
Reference in New Issue
Block a user