Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
a6d4b685
K
Kernel
项目概览
openeuler
/
Kernel
大约 2 年 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
a6d4b685
编写于
3月 21, 2022
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-next' into for-linus
Pull 5.18 development branch Signed-off-by:
N
Takashi Iwai
<
tiwai@suse.de
>
上级
efb6402c
8a580a26
变更
38
隐藏空白更改
内联
并排
Showing
38 changed file
with
1582 addition
and
493 deletion
+1582
-493
Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.yaml
...ntation/devicetree/bindings/sound/nvidia,tegra30-hda.yaml
+3
-0
Documentation/sound/designs/control-names.rst
Documentation/sound/designs/control-names.rst
+1
-1
MAINTAINERS
MAINTAINERS
+2
-2
drivers/acpi/scan.c
drivers/acpi/scan.c
+10
-6
drivers/platform/x86/Kconfig
drivers/platform/x86/Kconfig
+6
-6
drivers/platform/x86/Makefile
drivers/platform/x86/Makefile
+1
-1
drivers/platform/x86/i2c-multi-instantiate.c
drivers/platform/x86/i2c-multi-instantiate.c
+0
-174
drivers/platform/x86/serial-multi-instantiate.c
drivers/platform/x86/serial-multi-instantiate.c
+348
-0
drivers/spi/spi.c
drivers/spi/spi.c
+121
-16
include/linux/spi/spi.h
include/linux/spi/spi.h
+20
-0
include/sound/hda_codec.h
include/sound/hda_codec.h
+10
-1
include/sound/hda_verbs.h
include/sound/hda_verbs.h
+1
-1
include/sound/hdaudio_ext.h
include/sound/hdaudio_ext.h
+1
-0
sound/core/Kconfig
sound/core/Kconfig
+1
-1
sound/core/oss/pcm_oss.c
sound/core/oss/pcm_oss.c
+15
-13
sound/core/seq/oss/seq_oss_init.c
sound/core/seq/oss/seq_oss_init.c
+2
-3
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_controller.c
+21
-10
sound/hda/hdac_i915.c
sound/hda/hdac_i915.c
+2
-2
sound/mips/snd-n64.c
sound/mips/snd-n64.c
+4
-5
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106.h
+9
-9
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_main.c
+35
-35
sound/pci/ca0106/ca0106_mixer.c
sound/pci/ca0106/ca0106_mixer.c
+8
-8
sound/pci/echoaudio/midi.c
sound/pci/echoaudio/midi.c
+1
-1
sound/pci/hda/Kconfig
sound/pci/hda/Kconfig
+10
-9
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.c
+67
-27
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.c
+20
-3
sound/pci/hda/hda_local.h
sound/pci/hda/hda_local.h
+0
-2
sound/pci/hda/hda_tegra.c
sound/pci/hda/hda_tegra.c
+31
-2
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_hdmi.c
+213
-62
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_realtek.c
+46
-1
sound/pci/lola/lola_mixer.c
sound/pci/lola/lola_mixer.c
+2
-0
sound/soc/codecs/hdac_hda.c
sound/soc/codecs/hdac_hda.c
+1
-1
sound/sound_core.c
sound/sound_core.c
+13
-17
sound/spi/at73c213.c
sound/spi/at73c213.c
+21
-6
sound/usb/mixer_s1810c.c
sound/usb/mixer_s1810c.c
+1
-1
sound/usb/mixer_scarlett_gen2.c
sound/usb/mixer_scarlett_gen2.c
+144
-33
sound/x86/intel_hdmi_audio.c
sound/x86/intel_hdmi_audio.c
+0
-13
tools/testing/selftests/alsa/mixer-test.c
tools/testing/selftests/alsa/mixer-test.c
+391
-21
未找到文件。
Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.yaml
浏览文件 @
a6d4b685
...
...
@@ -23,6 +23,7 @@ properties:
-
const
:
nvidia,tegra30-hda
-
items
:
-
enum
:
-
nvidia,tegra234-hda
-
nvidia,tegra194-hda
-
nvidia,tegra186-hda
-
nvidia,tegra210-hda
...
...
@@ -41,9 +42,11 @@ properties:
maxItems
:
1
clocks
:
minItems
:
2
maxItems
:
3
clock-names
:
minItems
:
2
items
:
-
const
:
hda
-
const
:
hda2hdmi
...
...
Documentation/sound/designs/control-names.rst
浏览文件 @
a6d4b685
...
...
@@ -34,7 +34,7 @@ CHANNEL
Front front left/right channels
Surround rear left/right in 4.0/5.1 surround
CLFE C/LFE channels
Center center cannel
Center center c
h
annel
LFE LFE channel
Side side left/right for 7.1 surround
============ ==================================================
...
...
MAINTAINERS
浏览文件 @
a6d4b685
...
...
@@ -388,11 +388,11 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/acpi/arm64
ACPI
I2C
MULTI INSTANTIATE DRIVER
ACPI
SERIAL
MULTI INSTANTIATE DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/
i2c
-multi-instantiate.c
F: drivers/platform/x86/
serial
-multi-instantiate.c
ACPI PCC(Platform Communication Channel) MAILBOX DRIVER
M: Sudeep Holla <sudeep.holla@arm.com>
...
...
drivers/acpi/scan.c
浏览文件 @
a6d4b685
...
...
@@ -1734,17 +1734,21 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
bool
is_serial_bus_slave
=
false
;
static
const
struct
acpi_device_id
ignore_serial_bus_ids
[]
=
{
/*
* These devices have multiple I2cSerialBus resources and an i2c-client
* must be instantiated for each, each with its own i2c_device_id.
* Normally we only instantiate an i2c-client for the first resource,
* using the ACPI HID as id. These special cases are handled by the
* drivers/platform/x86/i2c-multi-instantiate.c driver, which knows
* which i2c_device_id to use for each resource.
* These devices have multiple SerialBus resources and a client
* device must be instantiated for each of them, each with
* its own device id.
* Normally we only instantiate one client device for the first
* resource, using the ACPI HID as id. These special cases are handled
* by the drivers/platform/x86/serial-multi-instantiate.c driver, which
* knows which client device id to use for each resource.
*/
{
"BSG1160"
,
},
{
"BSG2150"
,
},
{
"CSC3551"
,
},
{
"INT33FE"
,
},
{
"INT3515"
,
},
/* Non-conforming _HID for Cirrus Logic already released */
{
"CLSA0100"
,
},
/*
* HIDs of device with an UartSerialBusV2 resource for which userspace
* expects a regular tty cdev to be created (instead of the in kernel
...
...
drivers/platform/x86/Kconfig
浏览文件 @
a6d4b685
...
...
@@ -990,16 +990,16 @@ config TOPSTAR_LAPTOP
If you have a Topstar laptop, say Y or M here.
config
I2C
_MULTI_INSTANTIATE
tristate "
I2C
multi instantiate pseudo device driver"
depends on I2C && ACPI
config
SERIAL
_MULTI_INSTANTIATE
tristate "
Serial bus
multi instantiate pseudo device driver"
depends on I2C &&
SPI &&
ACPI
help
Some ACPI-based systems list multiple
i2c-
devices in a single ACPI
firmware-node. This driver will instantiate separate
i2c-
clients
Some ACPI-based systems list multiple devices in a single ACPI
firmware-node. This driver will instantiate separate clients
for each device in the firmware-node.
To compile this driver as a module, choose M here: the module
will be called
i2c
-multi-instantiate.
will be called
serial
-multi-instantiate.
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
...
...
drivers/platform/x86/Makefile
浏览文件 @
a6d4b685
...
...
@@ -110,7 +110,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
# Platform drivers
obj-$(CONFIG_FW_ATTR_CLASS)
+=
firmware_attributes_class.o
obj-$(CONFIG_
I2C_MULTI_INSTANTIATE)
+=
i2c
-multi-instantiate.o
obj-$(CONFIG_
SERIAL_MULTI_INSTANTIATE)
+=
serial
-multi-instantiate.o
obj-$(CONFIG_MLX_PLATFORM)
+=
mlx-platform.o
obj-$(CONFIG_TOUCHSCREEN_DMI)
+=
touchscreen_dmi.o
obj-$(CONFIG_WIRELESS_HOTKEY)
+=
wireless-hotkey.o
...
...
drivers/platform/x86/i2c-multi-instantiate.c
已删除
100644 → 0
浏览文件 @
efb6402c
// SPDX-License-Identifier: GPL-2.0+
/*
* I2C multi-instantiate driver, pseudo driver to instantiate multiple
* i2c-clients from a single fwnode.
*
* Copyright 2018 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
#define IRQ_RESOURCE_TYPE GENMASK(1, 0)
#define IRQ_RESOURCE_NONE 0
#define IRQ_RESOURCE_GPIO 1
#define IRQ_RESOURCE_APIC 2
struct
i2c_inst_data
{
const
char
*
type
;
unsigned
int
flags
;
int
irq_idx
;
};
struct
i2c_multi_inst_data
{
int
num_clients
;
struct
i2c_client
*
clients
[];
};
static
int
i2c_multi_inst_probe
(
struct
platform_device
*
pdev
)
{
struct
i2c_multi_inst_data
*
multi
;
const
struct
i2c_inst_data
*
inst_data
;
struct
i2c_board_info
board_info
=
{};
struct
device
*
dev
=
&
pdev
->
dev
;
struct
acpi_device
*
adev
;
char
name
[
32
];
int
i
,
ret
;
inst_data
=
device_get_match_data
(
dev
);
if
(
!
inst_data
)
{
dev_err
(
dev
,
"Error ACPI match data is missing
\n
"
);
return
-
ENODEV
;
}
adev
=
ACPI_COMPANION
(
dev
);
/* Count number of clients to instantiate */
ret
=
i2c_acpi_client_count
(
adev
);
if
(
ret
<
0
)
return
ret
;
multi
=
devm_kmalloc
(
dev
,
struct_size
(
multi
,
clients
,
ret
),
GFP_KERNEL
);
if
(
!
multi
)
return
-
ENOMEM
;
multi
->
num_clients
=
ret
;
for
(
i
=
0
;
i
<
multi
->
num_clients
&&
inst_data
[
i
].
type
;
i
++
)
{
memset
(
&
board_info
,
0
,
sizeof
(
board_info
));
strlcpy
(
board_info
.
type
,
inst_data
[
i
].
type
,
I2C_NAME_SIZE
);
snprintf
(
name
,
sizeof
(
name
),
"%s-%s.%d"
,
dev_name
(
dev
),
inst_data
[
i
].
type
,
i
);
board_info
.
dev_name
=
name
;
switch
(
inst_data
[
i
].
flags
&
IRQ_RESOURCE_TYPE
)
{
case
IRQ_RESOURCE_GPIO
:
ret
=
acpi_dev_gpio_irq_get
(
adev
,
inst_data
[
i
].
irq_idx
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Error requesting irq at index %d: %d
\n
"
,
inst_data
[
i
].
irq_idx
,
ret
);
goto
error
;
}
board_info
.
irq
=
ret
;
break
;
case
IRQ_RESOURCE_APIC
:
ret
=
platform_get_irq
(
pdev
,
inst_data
[
i
].
irq_idx
);
if
(
ret
<
0
)
{
dev_dbg
(
dev
,
"Error requesting irq at index %d: %d
\n
"
,
inst_data
[
i
].
irq_idx
,
ret
);
goto
error
;
}
board_info
.
irq
=
ret
;
break
;
default:
board_info
.
irq
=
0
;
break
;
}
multi
->
clients
[
i
]
=
i2c_acpi_new_device
(
dev
,
i
,
&
board_info
);
if
(
IS_ERR
(
multi
->
clients
[
i
]))
{
ret
=
dev_err_probe
(
dev
,
PTR_ERR
(
multi
->
clients
[
i
]),
"Error creating i2c-client, idx %d
\n
"
,
i
);
goto
error
;
}
}
if
(
i
<
multi
->
num_clients
)
{
dev_err
(
dev
,
"Error finding driver, idx %d
\n
"
,
i
);
ret
=
-
ENODEV
;
goto
error
;
}
platform_set_drvdata
(
pdev
,
multi
);
return
0
;
error:
while
(
--
i
>=
0
)
i2c_unregister_device
(
multi
->
clients
[
i
]);
return
ret
;
}
static
int
i2c_multi_inst_remove
(
struct
platform_device
*
pdev
)
{
struct
i2c_multi_inst_data
*
multi
=
platform_get_drvdata
(
pdev
);
int
i
;
for
(
i
=
0
;
i
<
multi
->
num_clients
;
i
++
)
i2c_unregister_device
(
multi
->
clients
[
i
]);
return
0
;
}
static
const
struct
i2c_inst_data
bsg1160_data
[]
=
{
{
"bmc150_accel"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"bmc150_magn"
},
{
"bmg160"
},
{}
};
static
const
struct
i2c_inst_data
bsg2150_data
[]
=
{
{
"bmc150_accel"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"bmc150_magn"
},
/* The resources describe a 3th client, but it is not really there. */
{
"bsg2150_dummy_dev"
},
{}
};
static
const
struct
i2c_inst_data
int3515_data
[]
=
{
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
0
},
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
1
},
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
2
},
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
3
},
{}
};
/*
* Note new device-ids must also be added to i2c_multi_instantiate_ids in
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
*/
static
const
struct
acpi_device_id
i2c_multi_inst_acpi_ids
[]
=
{
{
"BSG1160"
,
(
unsigned
long
)
bsg1160_data
},
{
"BSG2150"
,
(
unsigned
long
)
bsg2150_data
},
{
"INT3515"
,
(
unsigned
long
)
int3515_data
},
{
}
};
MODULE_DEVICE_TABLE
(
acpi
,
i2c_multi_inst_acpi_ids
);
static
struct
platform_driver
i2c_multi_inst_driver
=
{
.
driver
=
{
.
name
=
"I2C multi instantiate pseudo device driver"
,
.
acpi_match_table
=
i2c_multi_inst_acpi_ids
,
},
.
probe
=
i2c_multi_inst_probe
,
.
remove
=
i2c_multi_inst_remove
,
};
module_platform_driver
(
i2c_multi_inst_driver
);
MODULE_DESCRIPTION
(
"I2C multi instantiate pseudo device driver"
);
MODULE_AUTHOR
(
"Hans de Goede <hdegoede@redhat.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/platform/x86/serial-multi-instantiate.c
0 → 100644
浏览文件 @
a6d4b685
// SPDX-License-Identifier: GPL-2.0+
/*
* Serial multi-instantiate driver, pseudo driver to instantiate multiple
* client devices from a single fwnode.
*
* Copyright 2018 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#define IRQ_RESOURCE_TYPE GENMASK(1, 0)
#define IRQ_RESOURCE_NONE 0
#define IRQ_RESOURCE_GPIO 1
#define IRQ_RESOURCE_APIC 2
enum
smi_bus_type
{
SMI_I2C
,
SMI_SPI
,
SMI_AUTO_DETECT
,
};
struct
smi_instance
{
const
char
*
type
;
unsigned
int
flags
;
int
irq_idx
;
};
struct
smi_node
{
enum
smi_bus_type
bus_type
;
struct
smi_instance
instances
[];
};
struct
smi
{
int
i2c_num
;
int
spi_num
;
struct
i2c_client
**
i2c_devs
;
struct
spi_device
**
spi_devs
;
};
static
int
smi_get_irq
(
struct
platform_device
*
pdev
,
struct
acpi_device
*
adev
,
const
struct
smi_instance
*
inst
)
{
int
ret
;
switch
(
inst
->
flags
&
IRQ_RESOURCE_TYPE
)
{
case
IRQ_RESOURCE_GPIO
:
ret
=
acpi_dev_gpio_irq_get
(
adev
,
inst
->
irq_idx
);
break
;
case
IRQ_RESOURCE_APIC
:
ret
=
platform_get_irq
(
pdev
,
inst
->
irq_idx
);
break
;
default:
return
0
;
}
if
(
ret
<
0
)
dev_err_probe
(
&
pdev
->
dev
,
ret
,
"Error requesting irq at index %d: %d
\n
"
,
inst
->
irq_idx
,
ret
);
return
ret
;
}
static
void
smi_devs_unregister
(
struct
smi
*
smi
)
{
while
(
smi
->
i2c_num
>
0
)
i2c_unregister_device
(
smi
->
i2c_devs
[
--
smi
->
i2c_num
]);
while
(
smi
->
spi_num
>
0
)
spi_unregister_device
(
smi
->
spi_devs
[
--
smi
->
spi_num
]);
}
/**
* smi_spi_probe - Instantiate multiple SPI devices from inst array
* @pdev: Platform device
* @adev: ACPI device
* @smi: Internal struct for Serial multi instantiate driver
* @inst_array: Array of instances to probe
*
* Returns the number of SPI devices instantiate, Zero if none is found or a negative error code.
*/
static
int
smi_spi_probe
(
struct
platform_device
*
pdev
,
struct
acpi_device
*
adev
,
struct
smi
*
smi
,
const
struct
smi_instance
*
inst_array
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
spi_controller
*
ctlr
;
struct
spi_device
*
spi_dev
;
char
name
[
50
];
int
i
,
ret
,
count
;
ret
=
acpi_spi_count_resources
(
adev
);
if
(
ret
<
0
)
return
ret
;
else
if
(
!
ret
)
return
-
ENODEV
;
count
=
ret
;
smi
->
spi_devs
=
devm_kcalloc
(
dev
,
count
,
sizeof
(
*
smi
->
spi_devs
),
GFP_KERNEL
);
if
(
!
smi
->
spi_devs
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
count
&&
inst_array
[
i
].
type
;
i
++
)
{
spi_dev
=
acpi_spi_device_alloc
(
NULL
,
adev
,
i
);
if
(
IS_ERR
(
spi_dev
))
{
ret
=
PTR_ERR
(
spi_dev
);
dev_err_probe
(
dev
,
ret
,
"failed to allocate SPI device %s from ACPI: %d
\n
"
,
dev_name
(
&
adev
->
dev
),
ret
);
goto
error
;
}
ctlr
=
spi_dev
->
controller
;
strscpy
(
spi_dev
->
modalias
,
inst_array
[
i
].
type
,
sizeof
(
spi_dev
->
modalias
));
ret
=
smi_get_irq
(
pdev
,
adev
,
&
inst_array
[
i
]);
if
(
ret
<
0
)
{
spi_dev_put
(
spi_dev
);
goto
error
;
}
spi_dev
->
irq
=
ret
;
snprintf
(
name
,
sizeof
(
name
),
"%s-%s-%s.%d"
,
dev_name
(
&
ctlr
->
dev
),
dev_name
(
dev
),
inst_array
[
i
].
type
,
i
);
spi_dev
->
dev
.
init_name
=
name
;
ret
=
spi_add_device
(
spi_dev
);
if
(
ret
)
{
dev_err_probe
(
&
ctlr
->
dev
,
ret
,
"failed to add SPI device %s from ACPI: %d
\n
"
,
dev_name
(
&
adev
->
dev
),
ret
);
spi_dev_put
(
spi_dev
);
goto
error
;
}
dev_dbg
(
dev
,
"SPI device %s using chip select %u"
,
name
,
spi_dev
->
chip_select
);
smi
->
spi_devs
[
i
]
=
spi_dev
;
smi
->
spi_num
++
;
}
if
(
smi
->
spi_num
<
count
)
{
dev_dbg
(
dev
,
"Error finding driver, idx %d
\n
"
,
i
);
ret
=
-
ENODEV
;
goto
error
;
}
dev_info
(
dev
,
"Instantiated %d SPI devices.
\n
"
,
smi
->
spi_num
);
return
0
;
error:
smi_devs_unregister
(
smi
);
return
ret
;
}
/**
* smi_i2c_probe - Instantiate multiple I2C devices from inst array
* @pdev: Platform device
* @adev: ACPI device
* @smi: Internal struct for Serial multi instantiate driver
* @inst_array: Array of instances to probe
*
* Returns the number of I2C devices instantiate, Zero if none is found or a negative error code.
*/
static
int
smi_i2c_probe
(
struct
platform_device
*
pdev
,
struct
acpi_device
*
adev
,
struct
smi
*
smi
,
const
struct
smi_instance
*
inst_array
)
{
struct
i2c_board_info
board_info
=
{};
struct
device
*
dev
=
&
pdev
->
dev
;
char
name
[
32
];
int
i
,
ret
,
count
;
ret
=
i2c_acpi_client_count
(
adev
);
if
(
ret
<
0
)
return
ret
;
else
if
(
!
ret
)
return
-
ENODEV
;
count
=
ret
;
smi
->
i2c_devs
=
devm_kcalloc
(
dev
,
count
,
sizeof
(
*
smi
->
i2c_devs
),
GFP_KERNEL
);
if
(
!
smi
->
i2c_devs
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
count
&&
inst_array
[
i
].
type
;
i
++
)
{
memset
(
&
board_info
,
0
,
sizeof
(
board_info
));
strscpy
(
board_info
.
type
,
inst_array
[
i
].
type
,
I2C_NAME_SIZE
);
snprintf
(
name
,
sizeof
(
name
),
"%s-%s.%d"
,
dev_name
(
dev
),
inst_array
[
i
].
type
,
i
);
board_info
.
dev_name
=
name
;
ret
=
smi_get_irq
(
pdev
,
adev
,
&
inst_array
[
i
]);
if
(
ret
<
0
)
goto
error
;
board_info
.
irq
=
ret
;
smi
->
i2c_devs
[
i
]
=
i2c_acpi_new_device
(
dev
,
i
,
&
board_info
);
if
(
IS_ERR
(
smi
->
i2c_devs
[
i
]))
{
ret
=
dev_err_probe
(
dev
,
PTR_ERR
(
smi
->
i2c_devs
[
i
]),
"Error creating i2c-client, idx %d
\n
"
,
i
);
goto
error
;
}
smi
->
i2c_num
++
;
}
if
(
smi
->
i2c_num
<
count
)
{
dev_dbg
(
dev
,
"Error finding driver, idx %d
\n
"
,
i
);
ret
=
-
ENODEV
;
goto
error
;
}
dev_info
(
dev
,
"Instantiated %d I2C devices.
\n
"
,
smi
->
i2c_num
);
return
0
;
error:
smi_devs_unregister
(
smi
);
return
ret
;
}
static
int
smi_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
const
struct
smi_node
*
node
;
struct
acpi_device
*
adev
;
struct
smi
*
smi
;
adev
=
ACPI_COMPANION
(
dev
);
if
(
!
adev
)
return
-
ENODEV
;
node
=
device_get_match_data
(
dev
);
if
(
!
node
)
{
dev_dbg
(
dev
,
"Error ACPI match data is missing
\n
"
);
return
-
ENODEV
;
}
smi
=
devm_kzalloc
(
dev
,
sizeof
(
*
smi
),
GFP_KERNEL
);
if
(
!
smi
)
return
-
ENOMEM
;
platform_set_drvdata
(
pdev
,
smi
);
switch
(
node
->
bus_type
)
{
case
SMI_I2C
:
return
smi_i2c_probe
(
pdev
,
adev
,
smi
,
node
->
instances
);
case
SMI_SPI
:
return
smi_spi_probe
(
pdev
,
adev
,
smi
,
node
->
instances
);
case
SMI_AUTO_DETECT
:
if
(
i2c_acpi_client_count
(
adev
)
>
0
)
return
smi_i2c_probe
(
pdev
,
adev
,
smi
,
node
->
instances
);
else
return
smi_spi_probe
(
pdev
,
adev
,
smi
,
node
->
instances
);
default:
return
-
EINVAL
;
}
return
0
;
/* never reached */
}
static
int
smi_remove
(
struct
platform_device
*
pdev
)
{
struct
smi
*
smi
=
platform_get_drvdata
(
pdev
);
smi_devs_unregister
(
smi
);
return
0
;
}
static
const
struct
smi_node
bsg1160_data
=
{
.
instances
=
{
{
"bmc150_accel"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"bmc150_magn"
},
{
"bmg160"
},
{}
},
.
bus_type
=
SMI_I2C
,
};
static
const
struct
smi_node
bsg2150_data
=
{
.
instances
=
{
{
"bmc150_accel"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"bmc150_magn"
},
/* The resources describe a 3th client, but it is not really there. */
{
"bsg2150_dummy_dev"
},
{}
},
.
bus_type
=
SMI_I2C
,
};
static
const
struct
smi_node
int3515_data
=
{
.
instances
=
{
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
0
},
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
1
},
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
2
},
{
"tps6598x"
,
IRQ_RESOURCE_APIC
,
3
},
{}
},
.
bus_type
=
SMI_I2C
,
};
static
const
struct
smi_node
cs35l41_hda
=
{
.
instances
=
{
{
"cs35l41-hda"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"cs35l41-hda"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"cs35l41-hda"
,
IRQ_RESOURCE_GPIO
,
0
},
{
"cs35l41-hda"
,
IRQ_RESOURCE_GPIO
,
0
},
{}
},
.
bus_type
=
SMI_AUTO_DETECT
,
};
/*
* Note new device-ids must also be added to ignore_serial_bus_ids in
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
*/
static
const
struct
acpi_device_id
smi_acpi_ids
[]
=
{
{
"BSG1160"
,
(
unsigned
long
)
&
bsg1160_data
},
{
"BSG2150"
,
(
unsigned
long
)
&
bsg2150_data
},
{
"INT3515"
,
(
unsigned
long
)
&
int3515_data
},
{
"CSC3551"
,
(
unsigned
long
)
&
cs35l41_hda
},
/* Non-conforming _HID for Cirrus Logic already released */
{
"CLSA0100"
,
(
unsigned
long
)
&
cs35l41_hda
},
{
}
};
MODULE_DEVICE_TABLE
(
acpi
,
smi_acpi_ids
);
static
struct
platform_driver
smi_driver
=
{
.
driver
=
{
.
name
=
"Serial bus multi instantiate pseudo device driver"
,
.
acpi_match_table
=
smi_acpi_ids
,
},
.
probe
=
smi_probe
,
.
remove
=
smi_remove
,
};
module_platform_driver
(
smi_driver
);
MODULE_DESCRIPTION
(
"Serial multi instantiate pseudo device driver"
);
MODULE_AUTHOR
(
"Hans de Goede <hdegoede@redhat.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/spi/spi.c
浏览文件 @
a6d4b685
...
...
@@ -532,7 +532,7 @@ static DEFINE_MUTEX(board_lock);
*
* Return: a pointer to the new device, or NULL.
*/
st
atic
st
ruct
spi_device
*
spi_alloc_device
(
struct
spi_controller
*
ctlr
)
struct
spi_device
*
spi_alloc_device
(
struct
spi_controller
*
ctlr
)
{
struct
spi_device
*
spi
;
...
...
@@ -557,6 +557,7 @@ static struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
device_initialize
(
&
spi
->
dev
);
return
spi
;
}
EXPORT_SYMBOL_GPL
(
spi_alloc_device
);
static
void
spi_dev_set_name
(
struct
spi_device
*
spi
)
{
...
...
@@ -652,7 +653,7 @@ static int __spi_add_device(struct spi_device *spi)
*
* Return: 0 on success; negative errno on failure
*/
static
int
spi_add_device
(
struct
spi_device
*
spi
)
int
spi_add_device
(
struct
spi_device
*
spi
)
{
struct
spi_controller
*
ctlr
=
spi
->
controller
;
struct
device
*
dev
=
ctlr
->
dev
.
parent
;
...
...
@@ -673,6 +674,7 @@ static int spi_add_device(struct spi_device *spi)
mutex_unlock
(
&
ctlr
->
add_lock
);
return
status
;
}
EXPORT_SYMBOL_GPL
(
spi_add_device
);
static
int
spi_add_device_locked
(
struct
spi_device
*
spi
)
{
...
...
@@ -2318,8 +2320,50 @@ struct acpi_spi_lookup {
int
irq
;
u8
bits_per_word
;
u8
chip_select
;
int
n
;
int
index
;
};
static
int
acpi_spi_count
(
struct
acpi_resource
*
ares
,
void
*
data
)
{
struct
acpi_resource_spi_serialbus
*
sb
;
int
*
count
=
data
;
if
(
ares
->
type
!=
ACPI_RESOURCE_TYPE_SERIAL_BUS
)
return
1
;
sb
=
&
ares
->
data
.
spi_serial_bus
;
if
(
sb
->
type
!=
ACPI_RESOURCE_SERIAL_TYPE_SPI
)
return
1
;
*
count
=
*
count
+
1
;
return
1
;
}
/**
* acpi_spi_count_resources - Count the number of SpiSerialBus resources
* @adev: ACPI device
*
* Returns the number of SpiSerialBus resources in the ACPI-device's
* resource-list; or a negative error code.
*/
int
acpi_spi_count_resources
(
struct
acpi_device
*
adev
)
{
LIST_HEAD
(
r
);
int
count
=
0
;
int
ret
;
ret
=
acpi_dev_get_resources
(
adev
,
&
r
,
acpi_spi_count
,
&
count
);
if
(
ret
<
0
)
return
ret
;
acpi_dev_free_resource_list
(
&
r
);
return
count
;
}
EXPORT_SYMBOL_GPL
(
acpi_spi_count_resources
);
static
void
acpi_spi_parse_apple_properties
(
struct
acpi_device
*
dev
,
struct
acpi_spi_lookup
*
lookup
)
{
...
...
@@ -2349,6 +2393,8 @@ static void acpi_spi_parse_apple_properties(struct acpi_device *dev,
lookup
->
mode
|=
SPI_CPHA
;
}
static
struct
spi_controller
*
acpi_spi_find_controller_by_adev
(
struct
acpi_device
*
adev
);
static
int
acpi_spi_add_resource
(
struct
acpi_resource
*
ares
,
void
*
data
)
{
struct
acpi_spi_lookup
*
lookup
=
data
;
...
...
@@ -2362,14 +2408,35 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
sb
=
&
ares
->
data
.
spi_serial_bus
;
if
(
sb
->
type
==
ACPI_RESOURCE_SERIAL_TYPE_SPI
)
{
if
(
lookup
->
index
!=
-
1
&&
lookup
->
n
++
!=
lookup
->
index
)
return
1
;
if
(
lookup
->
index
==
-
1
&&
!
ctlr
)
return
-
ENODEV
;
status
=
acpi_get_handle
(
NULL
,
sb
->
resource_source
.
string_ptr
,
&
parent_handle
);
if
(
ACPI_FAILURE
(
status
)
||
ACPI_HANDLE
(
ctlr
->
dev
.
parent
)
!=
parent_handle
)
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
if
(
ctlr
)
{
if
(
ACPI_HANDLE
(
ctlr
->
dev
.
parent
)
!=
parent_handle
)
return
-
ENODEV
;
}
else
{
struct
acpi_device
*
adev
;
if
(
acpi_bus_get_device
(
parent_handle
,
&
adev
))
return
-
ENODEV
;
ctlr
=
acpi_spi_find_controller_by_adev
(
adev
);
if
(
!
ctlr
)
return
-
ENODEV
;
lookup
->
ctlr
=
ctlr
;
}
/*
* ACPI DeviceSelection numbering is handled by the
* host controller driver in Windows and can vary
...
...
@@ -2408,8 +2475,25 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
return
1
;
}
static
acpi_status
acpi_register_spi_device
(
struct
spi_controller
*
ctlr
,
struct
acpi_device
*
adev
)
/**
* acpi_spi_device_alloc - Allocate a spi device, and fill it in with ACPI information
* @ctlr: controller to which the spi device belongs
* @adev: ACPI Device for the spi device
* @index: Index of the spi resource inside the ACPI Node
*
* This should be used to allocate a new spi device from and ACPI Node.
* The caller is responsible for calling spi_add_device to register the spi device.
*
* If ctlr is set to NULL, the Controller for the spi device will be looked up
* using the resource.
* If index is set to -1, index is not used.
* Note: If index is -1, ctlr must be set.
*
* Return: a pointer to the new device, or ERR_PTR on error.
*/
struct
spi_device
*
acpi_spi_device_alloc
(
struct
spi_controller
*
ctlr
,
struct
acpi_device
*
adev
,
int
index
)
{
acpi_handle
parent_handle
=
NULL
;
struct
list_head
resource_list
;
...
...
@@ -2417,12 +2501,13 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
struct
spi_device
*
spi
;
int
ret
;
if
(
acpi_bus_get_status
(
adev
)
||
!
adev
->
status
.
present
||
acpi_device_enumerated
(
adev
))
return
AE_OK
;
if
(
!
ctlr
&&
index
==
-
1
)
return
ERR_PTR
(
-
EINVAL
);
lookup
.
ctlr
=
ctlr
;
lookup
.
irq
=
-
1
;
lookup
.
index
=
index
;
lookup
.
n
=
0
;
INIT_LIST_HEAD
(
&
resource_list
);
ret
=
acpi_dev_get_resources
(
adev
,
&
resource_list
,
...
...
@@ -2431,26 +2516,25 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
if
(
ret
<
0
)
/* found SPI in _CRS but it points to another controller */
return
AE_OK
;
return
ERR_PTR
(
-
ENODEV
)
;
if
(
!
lookup
.
max_speed_hz
&&
ACPI_SUCCESS
(
acpi_get_parent
(
adev
->
handle
,
&
parent_handle
))
&&
ACPI_HANDLE
(
ctlr
->
dev
.
parent
)
==
parent_handle
)
{
ACPI_HANDLE
(
lookup
.
ctlr
->
dev
.
parent
)
==
parent_handle
)
{
/* Apple does not use _CRS but nested devices for SPI slaves */
acpi_spi_parse_apple_properties
(
adev
,
&
lookup
);
}
if
(
!
lookup
.
max_speed_hz
)
return
AE_OK
;
return
ERR_PTR
(
-
ENODEV
)
;
spi
=
spi_alloc_device
(
ctlr
);
spi
=
spi_alloc_device
(
lookup
.
ctlr
);
if
(
!
spi
)
{
dev_err
(
&
ctlr
->
dev
,
"failed to allocate SPI device for %s
\n
"
,
dev_err
(
&
lookup
.
ctlr
->
dev
,
"failed to allocate SPI device for %s
\n
"
,
dev_name
(
&
adev
->
dev
));
return
AE_NO_MEMORY
;
return
ERR_PTR
(
-
ENOMEM
)
;
}
ACPI_COMPANION_SET
(
&
spi
->
dev
,
adev
);
spi
->
max_speed_hz
=
lookup
.
max_speed_hz
;
spi
->
mode
|=
lookup
.
mode
;
...
...
@@ -2458,6 +2542,27 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
spi
->
bits_per_word
=
lookup
.
bits_per_word
;
spi
->
chip_select
=
lookup
.
chip_select
;
return
spi
;
}
EXPORT_SYMBOL_GPL
(
acpi_spi_device_alloc
);
static
acpi_status
acpi_register_spi_device
(
struct
spi_controller
*
ctlr
,
struct
acpi_device
*
adev
)
{
struct
spi_device
*
spi
;
if
(
acpi_bus_get_status
(
adev
)
||
!
adev
->
status
.
present
||
acpi_device_enumerated
(
adev
))
return
AE_OK
;
spi
=
acpi_spi_device_alloc
(
ctlr
,
adev
,
-
1
);
if
(
IS_ERR
(
spi
))
{
if
(
PTR_ERR
(
spi
)
==
-
ENOMEM
)
return
AE_NO_MEMORY
;
else
return
AE_OK
;
}
acpi_set_modalias
(
adev
,
acpi_device_hid
(
adev
),
spi
->
modalias
,
sizeof
(
spi
->
modalias
));
...
...
include/linux/spi/spi.h
浏览文件 @
a6d4b685
...
...
@@ -16,6 +16,7 @@
#include <linux/gpio/consumer.h>
#include <uapi/linux/spi/spi.h>
#include <linux/acpi.h>
struct
dma_chan
;
struct
software_node
;
...
...
@@ -759,6 +760,13 @@ extern int devm_spi_register_controller(struct device *dev,
struct
spi_controller
*
ctlr
);
extern
void
spi_unregister_controller
(
struct
spi_controller
*
ctlr
);
#if IS_ENABLED(CONFIG_ACPI)
extern
struct
spi_device
*
acpi_spi_device_alloc
(
struct
spi_controller
*
ctlr
,
struct
acpi_device
*
adev
,
int
index
);
int
acpi_spi_count_resources
(
struct
acpi_device
*
adev
);
#endif
/*
* SPI resource management while processing a SPI message
*/
...
...
@@ -1452,7 +1460,19 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
* use spi_new_device() to describe each device. You can also call
* spi_unregister_device() to start making that device vanish, but
* normally that would be handled by spi_unregister_controller().
*
* You can also use spi_alloc_device() and spi_add_device() to use a two
* stage registration sequence for each spi_device. This gives the caller
* some more control over the spi_device structure before it is registered,
* but requires that caller to initialize fields that would otherwise
* be defined using the board info.
*/
extern
struct
spi_device
*
spi_alloc_device
(
struct
spi_controller
*
ctlr
);
extern
int
spi_add_device
(
struct
spi_device
*
spi
);
extern
struct
spi_device
*
spi_new_device
(
struct
spi_controller
*
,
struct
spi_board_info
*
);
...
...
include/sound/hda_codec.h
浏览文件 @
a6d4b685
...
...
@@ -306,12 +306,19 @@ struct hda_codec {
/*
* constructors
*/
__printf
(
3
,
4
)
struct
hda_codec
*
snd_hda_codec_device_init
(
struct
hda_bus
*
bus
,
unsigned
int
codec_addr
,
const
char
*
fmt
,
...);
int
snd_hda_codec_new
(
struct
hda_bus
*
bus
,
struct
snd_card
*
card
,
unsigned
int
codec_addr
,
struct
hda_codec
**
codecp
);
int
snd_hda_codec_device_new
(
struct
hda_bus
*
bus
,
struct
snd_card
*
card
,
unsigned
int
codec_addr
,
struct
hda_codec
*
codec
);
unsigned
int
codec_addr
,
struct
hda_codec
*
codec
,
bool
snddev_managed
);
int
snd_hda_codec_configure
(
struct
hda_codec
*
codec
);
int
snd_hda_codec_update_widgets
(
struct
hda_codec
*
codec
);
void
snd_hda_codec_register
(
struct
hda_codec
*
codec
);
void
snd_hda_codec_unregister
(
struct
hda_codec
*
codec
);
void
snd_hda_codec_cleanup_for_unbind
(
struct
hda_codec
*
codec
);
/*
* low level functions
...
...
@@ -490,9 +497,11 @@ int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
#define snd_hda_power_down(codec) snd_hdac_power_down(&(codec)->core)
#define snd_hda_power_down_pm(codec) snd_hdac_power_down_pm(&(codec)->core)
#ifdef CONFIG_PM
void
snd_hda_codec_set_power_save
(
struct
hda_codec
*
codec
,
int
delay
);
void
snd_hda_set_power_save
(
struct
hda_bus
*
bus
,
int
delay
);
void
snd_hda_update_power_acct
(
struct
hda_codec
*
codec
);
#else
static
inline
void
snd_hda_codec_set_power_save
(
struct
hda_codec
*
codec
,
int
delay
)
{}
static
inline
void
snd_hda_set_power_save
(
struct
hda_bus
*
bus
,
int
delay
)
{}
#endif
...
...
include/sound/hda_verbs.h
浏览文件 @
a6d4b685
...
...
@@ -461,7 +461,7 @@ enum {
#define AC_DE_ELDV (1<<1)
#define AC_DE_IA (1<<2)
/* device
device
types (0x0-0xf) */
/* device types (0x0-0xf) */
enum
{
AC_JACK_LINE_OUT
,
AC_JACK_SPEAKER
,
...
...
include/sound/hdaudio_ext.h
浏览文件 @
a6d4b685
...
...
@@ -28,6 +28,7 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip,
bool
enable
,
int
index
);
int
snd_hdac_ext_bus_get_ml_capabilities
(
struct
hdac_bus
*
bus
);
struct
hdac_ext_link
*
snd_hdac_ext_bus_link_at
(
struct
hdac_bus
*
bus
,
int
addr
);
struct
hdac_ext_link
*
snd_hdac_ext_bus_get_link
(
struct
hdac_bus
*
bus
,
const
char
*
codec_name
);
...
...
sound/core/Kconfig
浏览文件 @
a6d4b685
...
...
@@ -84,7 +84,7 @@ config SND_PCM_TIMER
help
If you disable this option, pcm timer will be unavailable, so
those stubs that use pcm timer (e.g. dmix, dsnoop & co) may work
incorrectl
l
y.
incorrectly.
For some embedded devices, we may disable it to reduce memory
footprint, about 20KB on x86_64 platform.
...
...
sound/core/oss/pcm_oss.c
浏览文件 @
a6d4b685
...
...
@@ -842,6 +842,17 @@ static void unlock_params(struct snd_pcm_runtime *runtime)
mutex_unlock
(
&
runtime
->
oss
.
params_lock
);
}
static
void
snd_pcm_oss_release_buffers
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
kvfree
(
runtime
->
oss
.
buffer
);
runtime
->
oss
.
buffer
=
NULL
;
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
snd_pcm_oss_plugin_clear
(
substream
);
#endif
}
/* call with params_lock held */
static
int
snd_pcm_oss_change_params_locked
(
struct
snd_pcm_substream
*
substream
)
{
...
...
@@ -972,12 +983,10 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
snd_pcm_oss_plugin_clear
(
substream
);
if
(
!
direct
)
{
/* add necessary plugins */
snd_pcm_oss_plugin_clear
(
substream
);
err
=
snd_pcm_plug_format_plugins
(
substream
,
params
,
sparams
);
if
(
err
<
0
)
{
pcm_dbg
(
substream
->
pcm
,
"snd_pcm_plug_format_plugins failed: %i
\n
"
,
err
);
snd_pcm_oss_plugin_clear
(
substream
);
goto
failure
;
}
if
(
runtime
->
oss
.
plugin_first
)
{
...
...
@@ -986,7 +995,6 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
if
(
err
<
0
)
{
pcm_dbg
(
substream
->
pcm
,
"snd_pcm_plugin_build_io failed: %i
\n
"
,
err
);
snd_pcm_oss_plugin_clear
(
substream
);
goto
failure
;
}
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
...
...
@@ -994,10 +1002,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
}
else
{
err
=
snd_pcm_plugin_insert
(
plugin
);
}
if
(
err
<
0
)
{
snd_pcm_oss_plugin_clear
(
substream
);
if
(
err
<
0
)
goto
failure
;
}
}
}
#endif
...
...
@@ -1086,6 +1092,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
err
=
0
;
failure:
if
(
err
)
snd_pcm_oss_release_buffers
(
substream
);
kfree
(
sw_params
);
kfree
(
params
);
kfree
(
sparams
);
...
...
@@ -2355,13 +2363,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
static
void
snd_pcm_oss_release_substream
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
;
runtime
=
substream
->
runtime
;
kvfree
(
runtime
->
oss
.
buffer
);
runtime
->
oss
.
buffer
=
NULL
;
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
snd_pcm_oss_plugin_clear
(
substream
);
#endif
snd_pcm_oss_release_buffers
(
substream
);
substream
->
oss
.
oss
=
0
;
}
...
...
sound/core/seq/oss/seq_oss_init.c
浏览文件 @
a6d4b685
...
...
@@ -66,7 +66,7 @@ snd_seq_oss_create_client(void)
struct
snd_seq_port_info
*
port
;
struct
snd_seq_port_callback
port_callback
;
port
=
k
m
alloc
(
sizeof
(
*
port
),
GFP_KERNEL
);
port
=
k
z
alloc
(
sizeof
(
*
port
),
GFP_KERNEL
);
if
(
!
port
)
{
rc
=
-
ENOMEM
;
goto
__error
;
...
...
@@ -80,8 +80,7 @@ snd_seq_oss_create_client(void)
system_client
=
rc
;
/* create annoucement receiver port */
memset
(
port
,
0
,
sizeof
(
*
port
));
/* create announcement receiver port */
strcpy
(
port
->
name
,
"Receiver"
);
port
->
addr
.
client
=
system_client
;
port
->
capability
=
SNDRV_SEQ_PORT_CAP_WRITE
;
/* receive only */
...
...
sound/hda/ext/hdac_ext_controller.c
浏览文件 @
a6d4b685
...
...
@@ -132,6 +132,26 @@ void snd_hdac_link_free_all(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL
(
snd_hdac_link_free_all
);
/**
* snd_hdac_ext_bus_link_at - get link at specified address
* @bus: link's parent bus device
* @addr: codec device address
*
* Returns link object or NULL if matching link is not found.
*/
struct
hdac_ext_link
*
snd_hdac_ext_bus_link_at
(
struct
hdac_bus
*
bus
,
int
addr
)
{
struct
hdac_ext_link
*
hlink
;
int
i
;
list_for_each_entry
(
hlink
,
&
bus
->
hlink_list
,
list
)
for
(
i
=
0
;
i
<
HDA_MAX_CODECS
;
i
++
)
if
(
hlink
->
lsdiid
&
(
0x1
<<
addr
))
return
hlink
;
return
NULL
;
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_bus_link_at
);
/**
* snd_hdac_ext_bus_get_link - get link based on codec name
* @bus: the pointer to HDAC bus object
...
...
@@ -140,8 +160,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
struct
hdac_ext_link
*
snd_hdac_ext_bus_get_link
(
struct
hdac_bus
*
bus
,
const
char
*
codec_name
)
{
int
i
;
struct
hdac_ext_link
*
hlink
=
NULL
;
int
bus_idx
,
addr
;
if
(
sscanf
(
codec_name
,
"ehdaudio%dD%d"
,
&
bus_idx
,
&
addr
)
!=
2
)
...
...
@@ -151,14 +169,7 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
if
(
addr
<
0
||
addr
>
31
)
return
NULL
;
list_for_each_entry
(
hlink
,
&
bus
->
hlink_list
,
list
)
{
for
(
i
=
0
;
i
<
HDA_MAX_CODECS
;
i
++
)
{
if
(
hlink
->
lsdiid
&
(
0x1
<<
addr
))
return
hlink
;
}
}
return
NULL
;
return
snd_hdac_ext_bus_link_at
(
bus
,
addr
);
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_bus_get_link
);
...
...
sound/hda/hdac_i915.c
浏览文件 @
a6d4b685
...
...
@@ -160,8 +160,8 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
if
(
!
IS_ENABLED
(
CONFIG_MODULES
)
||
!
request_module
(
"i915"
))
{
/* 60s timeout */
wait_for_completion_timeout
(
&
acomp
->
master_bind_complete
,
msecs_to_jiffies
(
60
*
1000
));
wait_for_completion_
killable_
timeout
(
&
acomp
->
master_bind_complete
,
msecs_to_jiffies
(
60
*
1000
));
}
}
if
(
!
acomp
->
ops
)
{
...
...
sound/mips/snd-n64.c
浏览文件 @
a6d4b685
...
...
@@ -289,8 +289,7 @@ static int __init n64audio_probe(struct platform_device *pdev)
struct
snd_card
*
card
;
struct
snd_pcm
*
pcm
;
struct
n64audio
*
priv
;
struct
resource
*
res
;
int
err
;
int
err
,
irq
;
err
=
snd_card_new
(
&
pdev
->
dev
,
SNDRV_DEFAULT_IDX1
,
SNDRV_DEFAULT_STR1
,
...
...
@@ -337,12 +336,12 @@ static int __init n64audio_probe(struct platform_device *pdev)
strcpy
(
card
->
shortname
,
"N64 Audio"
);
strcpy
(
card
->
longname
,
"N64 Audio"
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_IRQ
,
0
);
if
(
!
res
)
{
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
err
=
-
EINVAL
;
goto
fail_dma_alloc
;
}
if
(
devm_request_irq
(
&
pdev
->
dev
,
res
->
start
,
n64audio_isr
,
if
(
devm_request_irq
(
&
pdev
->
dev
,
irq
,
n64audio_isr
,
IRQF_SHARED
,
"N64 Audio"
,
priv
))
{
err
=
-
EBUSY
;
goto
fail_dma_alloc
;
...
...
sound/pci/ca0106/ca0106.h
浏览文件 @
a6d4b685
...
...
@@ -59,15 +59,15 @@
/* PCI function 0 registers, address = <val> + PCIBASE0 */
/************************************************************************************************/
#define
PTR
0x00
/* Indexed register set pointer register */
#define
CA0106_PTR
0x00
/* Indexed register set pointer register */
/* NOTE: The CHANNELNUM and ADDRESS words can */
/* be modified independently of each other. */
/* CNL[1:0], ADDR[27:16] */
#define
DATA
0x04
/* Indexed register set data register */
#define
CA0106_DATA
0x04
/* Indexed register set data register */
/* DATA[31:0] */
#define
IPR
0x08
/* Global interrupt pending register */
#define
CA0106_IPR
0x08
/* Global interrupt pending register */
/* Clear pending interrupts by writing a 1 to */
/* the relevant bits and zero to the other bits */
#define IPR_MIDI_RX_B 0x00020000
/* MIDI UART-B Receive buffer non-empty */
...
...
@@ -88,7 +88,7 @@
#define IPR_MIDI_TX_A 0x00000002
/* MIDI UART-A Transmit buffer empty */
#define IPR_PCI 0x00000001
/* PCI Bus error */
#define
INTE
0x0c
/* Interrupt enable register */
#define
CA0106_INTE
0x0c
/* Interrupt enable register */
#define INTE_MIDI_RX_B 0x00020000
/* MIDI UART-B Receive buffer non-empty */
#define INTE_MIDI_TX_B 0x00010000
/* MIDI UART-B Transmit buffer empty */
...
...
@@ -108,8 +108,8 @@
#define INTE_MIDI_TX_A 0x00000002
/* MIDI UART-A Transmit buffer empty */
#define INTE_PCI 0x00000001
/* PCI Bus error */
#define
UNKNOWN10
0x10
/* Unknown ??. Defaults to 0 */
#define
HCFG
0x14
/* Hardware config register */
#define
CA0106_UNKNOWN10
0x10
/* Unknown ??. Defaults to 0 */
#define
CA0106_HCFG
0x14
/* Hardware config register */
/* 0x1000 causes AC3 to fails. It adds a dither bit. */
#define HCFG_STAC 0x10000000
/* Special mode for STAC9460 Codec. */
...
...
@@ -133,7 +133,7 @@
#define HCFG_AUDIOENABLE 0x00000001
/* 0 = CODECs transmit zero-valued samples */
/* Should be set to 1 when the EMU10K1 is */
/* completely initialized. */
#define
GPIO
0x18
/* Defaults: 005f03a3-Analog, 005f02a2-SPDIF. */
#define
CA0106_GPIO
0x18
/* Defaults: 005f03a3-Analog, 005f02a2-SPDIF. */
/* Here pins 0,1,2,3,4,,6 are output. 5,7 are input */
/* For the Audigy LS, pin 0 (or bit 8) controls the SPDIF/Analog jack. */
/* SB Live 24bit:
...
...
@@ -152,9 +152,9 @@
* GPO [15:8] Default 0x9. (Default to SPDIF jack enabled for SPDIF)
* GPO Enable [23:16] Default 0x0f. Setting a bit to 1, causes the pin to be an output pin.
*/
#define AC97DATA 0x1c
/* AC97 register set data register (16 bit) */
#define
CA0106_
AC97DATA 0x1c
/* AC97 register set data register (16 bit) */
#define
AC97ADDRESS
0x1e
/* AC97 register set address register (8 bit) */
#define
CA0106_AC97ADDRESS
0x1e
/* AC97 register set address register (8 bit) */
/********************************************************************************************************/
/* CA0106 pointer-offset register set, accessed through the PTR and DATA registers */
...
...
sound/pci/ca0106/ca0106_main.c
浏览文件 @
a6d4b685
...
...
@@ -338,8 +338,8 @@ unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu,
regptr
=
(
reg
<<
16
)
|
chn
;
spin_lock_irqsave
(
&
emu
->
emu_lock
,
flags
);
outl
(
regptr
,
emu
->
port
+
PTR
);
val
=
inl
(
emu
->
port
+
DATA
);
outl
(
regptr
,
emu
->
port
+
CA0106_
PTR
);
val
=
inl
(
emu
->
port
+
CA0106_
DATA
);
spin_unlock_irqrestore
(
&
emu
->
emu_lock
,
flags
);
return
val
;
}
...
...
@@ -355,8 +355,8 @@ void snd_ca0106_ptr_write(struct snd_ca0106 *emu,
regptr
=
(
reg
<<
16
)
|
chn
;
spin_lock_irqsave
(
&
emu
->
emu_lock
,
flags
);
outl
(
regptr
,
emu
->
port
+
PTR
);
outl
(
data
,
emu
->
port
+
DATA
);
outl
(
regptr
,
emu
->
port
+
CA0106_
PTR
);
outl
(
data
,
emu
->
port
+
CA0106_
DATA
);
spin_unlock_irqrestore
(
&
emu
->
emu_lock
,
flags
);
}
...
...
@@ -455,8 +455,8 @@ static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb)
unsigned
int
intr_enable
;
spin_lock_irqsave
(
&
emu
->
emu_lock
,
flags
);
intr_enable
=
inl
(
emu
->
port
+
INTE
)
|
intrenb
;
outl
(
intr_enable
,
emu
->
port
+
INTE
);
intr_enable
=
inl
(
emu
->
port
+
CA0106_
INTE
)
|
intrenb
;
outl
(
intr_enable
,
emu
->
port
+
CA0106_
INTE
);
spin_unlock_irqrestore
(
&
emu
->
emu_lock
,
flags
);
}
...
...
@@ -466,8 +466,8 @@ static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb
unsigned
int
intr_enable
;
spin_lock_irqsave
(
&
emu
->
emu_lock
,
flags
);
intr_enable
=
inl
(
emu
->
port
+
INTE
)
&
~
intrenb
;
outl
(
intr_enable
,
emu
->
port
+
INTE
);
intr_enable
=
inl
(
emu
->
port
+
CA0106_
INTE
)
&
~
intrenb
;
outl
(
intr_enable
,
emu
->
port
+
CA0106_
INTE
);
spin_unlock_irqrestore
(
&
emu
->
emu_lock
,
flags
);
}
...
...
@@ -786,9 +786,9 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
hcfg_set
=
0
;
break
;
}
hcfg
=
inl
(
emu
->
port
+
HCFG
)
;
hcfg
=
inl
(
emu
->
port
+
CA0106_
HCFG
)
;
hcfg
=
(
hcfg
&
~
hcfg_mask
)
|
hcfg_set
;
outl
(
hcfg
,
emu
->
port
+
HCFG
);
outl
(
hcfg
,
emu
->
port
+
CA0106_
HCFG
);
reg40
=
snd_ca0106_ptr_read
(
emu
,
0x40
,
0
);
reg40
=
(
reg40
&
~
reg40_mask
)
|
reg40_set
;
snd_ca0106_ptr_write
(
emu
,
0x40
,
0
,
reg40
);
...
...
@@ -888,9 +888,9 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
hcfg_set
=
0
;
break
;
}
hcfg
=
inl
(
emu
->
port
+
HCFG
)
;
hcfg
=
inl
(
emu
->
port
+
CA0106_
HCFG
)
;
hcfg
=
(
hcfg
&
~
hcfg_mask
)
|
hcfg_set
;
outl
(
hcfg
,
emu
->
port
+
HCFG
);
outl
(
hcfg
,
emu
->
port
+
CA0106_
HCFG
);
reg71
=
snd_ca0106_ptr_read
(
emu
,
0x71
,
0
);
reg71
=
(
reg71
&
~
reg71_mask
)
|
reg71_set
;
snd_ca0106_ptr_write
(
emu
,
0x71
,
0
,
reg71
);
...
...
@@ -1142,8 +1142,8 @@ static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97,
unsigned
short
val
;
spin_lock_irqsave
(
&
emu
->
emu_lock
,
flags
);
outb
(
reg
,
emu
->
port
+
AC97ADDRESS
);
val
=
inw
(
emu
->
port
+
AC97DATA
);
outb
(
reg
,
emu
->
port
+
CA0106_
AC97ADDRESS
);
val
=
inw
(
emu
->
port
+
CA0106_
AC97DATA
);
spin_unlock_irqrestore
(
&
emu
->
emu_lock
,
flags
);
return
val
;
}
...
...
@@ -1155,8 +1155,8 @@ static void snd_ca0106_ac97_write(struct snd_ac97 *ac97,
unsigned
long
flags
;
spin_lock_irqsave
(
&
emu
->
emu_lock
,
flags
);
outb
(
reg
,
emu
->
port
+
AC97ADDRESS
);
outw
(
val
,
emu
->
port
+
AC97DATA
);
outb
(
reg
,
emu
->
port
+
CA0106_
AC97ADDRESS
);
outw
(
val
,
emu
->
port
+
CA0106_
AC97DATA
);
spin_unlock_irqrestore
(
&
emu
->
emu_lock
,
flags
);
}
...
...
@@ -1200,7 +1200,7 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
unsigned
int
stat76
;
struct
snd_ca0106_channel
*
pchannel
;
status
=
inl
(
chip
->
port
+
IPR
);
status
=
inl
(
chip
->
port
+
CA0106_
IPR
);
if
(
!
status
)
return
IRQ_NONE
;
...
...
@@ -1255,7 +1255,7 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
}
// acknowledge the interrupt if necessary
outl
(
status
,
chip
->
port
+
IPR
);
outl
(
status
,
chip
->
port
+
CA0106_
IPR
);
return
IRQ_HANDLED
;
}
...
...
@@ -1383,7 +1383,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
int
ch
;
unsigned
int
def_bits
;
outl
(
0
,
chip
->
port
+
INTE
);
outl
(
0
,
chip
->
port
+
CA0106_
INTE
);
/*
* Init to 0x02109204 :
...
...
@@ -1420,8 +1420,8 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
snd_ca0106_ptr_write
(
chip
,
CAPTURE_MUTE
,
0
,
0x00fc0000
);
/* Write 0x8000 to AC97_REC_GAIN to mute it. */
outb
(
AC97_REC_GAIN
,
chip
->
port
+
AC97ADDRESS
);
outw
(
0x8000
,
chip
->
port
+
AC97DATA
);
outb
(
AC97_REC_GAIN
,
chip
->
port
+
CA0106_
AC97ADDRESS
);
outw
(
0x8000
,
chip
->
port
+
CA0106_
AC97DATA
);
#if 0 /* FIXME: what are these? */
snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006);
snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006);
...
...
@@ -1495,30 +1495,30 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
/* FIXME: Still need to find out what the other GPIO bits do.
* E.g. For digital spdif out.
*/
outl
(
0x0
,
chip
->
port
+
GPIO
);
/* outl(0x00f0e000, chip->port
+
GPIO); */
/* Analog */
outl
(
0x005f5301
,
chip
->
port
+
GPIO
);
/* Analog */
outl
(
0x0
,
chip
->
port
+
CA0106_
GPIO
);
/* outl(0x00f0e000, chip->port
+ CA0106_
GPIO); */
/* Analog */
outl
(
0x005f5301
,
chip
->
port
+
CA0106_
GPIO
);
/* Analog */
}
else
if
(
chip
->
details
->
gpio_type
==
1
)
{
/* The SB0410 and SB0413 use GPIO differently. */
/* FIXME: Still need to find out what the other GPIO bits do.
* E.g. For digital spdif out.
*/
outl
(
0x0
,
chip
->
port
+
GPIO
);
/* outl(0x00f0e000, chip->port
+
GPIO); */
/* Analog */
outl
(
0x005f5301
,
chip
->
port
+
GPIO
);
/* Analog */
outl
(
0x0
,
chip
->
port
+
CA0106_
GPIO
);
/* outl(0x00f0e000, chip->port
+ CA0106_
GPIO); */
/* Analog */
outl
(
0x005f5301
,
chip
->
port
+
CA0106_
GPIO
);
/* Analog */
}
else
{
outl
(
0x0
,
chip
->
port
+
GPIO
);
outl
(
0x005f03a3
,
chip
->
port
+
GPIO
);
/* Analog */
/* outl(0x005f02a2, chip->port
+
GPIO); */
/* SPDIF */
outl
(
0x0
,
chip
->
port
+
CA0106_
GPIO
);
outl
(
0x005f03a3
,
chip
->
port
+
CA0106_
GPIO
);
/* Analog */
/* outl(0x005f02a2, chip->port
+ CA0106_
GPIO); */
/* SPDIF */
}
snd_ca0106_intr_enable
(
chip
,
0x105
);
/* Win2000 uses 0x1e0 */
/* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */
/* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */
/* outl(0x00001409, chip->port
+
HCFG); */
/* outl(0x00000009, chip->port
+
HCFG); */
/* outl(0x00001409, chip->port
+ CA0106_
HCFG); */
/* outl(0x00000009, chip->port
+ CA0106_
HCFG); */
/* AC97 2.0, Enable outputs. */
outl
(
HCFG_AC97
|
HCFG_AUDIOENABLE
,
chip
->
port
+
HCFG
);
outl
(
HCFG_AC97
|
HCFG_AUDIOENABLE
,
chip
->
port
+
CA0106_
HCFG
);
if
(
chip
->
details
->
i2c_adc
==
1
)
{
/* The SB0410 and SB0413 use I2C to control ADC. */
...
...
@@ -1560,12 +1560,12 @@ static void ca0106_stop_chip(struct snd_ca0106 *chip)
{
/* disable interrupts */
snd_ca0106_ptr_write
(
chip
,
BASIC_INTERRUPT
,
0
,
0
);
outl
(
0
,
chip
->
port
+
INTE
);
outl
(
0
,
chip
->
port
+
CA0106_
INTE
);
snd_ca0106_ptr_write
(
chip
,
EXTENDED_INT_MASK
,
0
,
0
);
udelay
(
1000
);
/* disable audio */
/* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */
outl
(
0
,
chip
->
port
+
HCFG
);
outl
(
0
,
chip
->
port
+
CA0106_
HCFG
);
/* FIXME: We need to stop and DMA transfers here.
* But as I am not sure how yet, we cannot from the dma pages.
* So we can fix: snd-malloc: Memory leak? pages not freed = 8
...
...
sound/pci/ca0106/ca0106_mixer.c
浏览文件 @
a6d4b685
...
...
@@ -70,8 +70,8 @@ static void ca0106_spdif_enable(struct snd_ca0106 *emu)
snd_ca0106_ptr_write
(
emu
,
SPDIF_SELECT2
,
0
,
0x0b000000
);
val
=
snd_ca0106_ptr_read
(
emu
,
CAPTURE_CONTROL
,
0
)
&
~
0x1000
;
snd_ca0106_ptr_write
(
emu
,
CAPTURE_CONTROL
,
0
,
val
);
val
=
inl
(
emu
->
port
+
GPIO
)
&
~
0x101
;
outl
(
val
,
emu
->
port
+
GPIO
);
val
=
inl
(
emu
->
port
+
CA0106_
GPIO
)
&
~
0x101
;
outl
(
val
,
emu
->
port
+
CA0106_
GPIO
);
}
else
{
/* Analog */
...
...
@@ -79,8 +79,8 @@ static void ca0106_spdif_enable(struct snd_ca0106 *emu)
snd_ca0106_ptr_write
(
emu
,
SPDIF_SELECT2
,
0
,
0x000f0000
);
val
=
snd_ca0106_ptr_read
(
emu
,
CAPTURE_CONTROL
,
0
)
|
0x1000
;
snd_ca0106_ptr_write
(
emu
,
CAPTURE_CONTROL
,
0
,
val
);
val
=
inl
(
emu
->
port
+
GPIO
)
|
0x101
;
outl
(
val
,
emu
->
port
+
GPIO
);
val
=
inl
(
emu
->
port
+
CA0106_
GPIO
)
|
0x101
;
outl
(
val
,
emu
->
port
+
CA0106_
GPIO
);
}
}
...
...
@@ -119,14 +119,14 @@ static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
if
(
emu
->
capture_mic_line_in
)
{
/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */
/* Mute input */
tmp
=
inl
(
emu
->
port
+
GPIO
)
&
~
0x400
;
tmp
=
inl
(
emu
->
port
+
CA0106_
GPIO
)
&
~
0x400
;
tmp
=
tmp
|
0x400
;
outl
(
tmp
,
emu
->
port
+
GPIO
);
outl
(
tmp
,
emu
->
port
+
CA0106_
GPIO
);
/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */
}
else
{
/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */
/* Mute input */
tmp
=
inl
(
emu
->
port
+
GPIO
)
&
~
0x400
;
outl
(
tmp
,
emu
->
port
+
GPIO
);
tmp
=
inl
(
emu
->
port
+
CA0106_
GPIO
)
&
~
0x400
;
outl
(
tmp
,
emu
->
port
+
CA0106_
GPIO
);
/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */
}
}
...
...
sound/pci/echoaudio/midi.c
浏览文件 @
a6d4b685
...
...
@@ -208,7 +208,7 @@ static void snd_echo_midi_output_write(struct timer_list *t)
/* No interrupts are involved: we have to check at regular intervals
if the card's output buffer has room for new data. */
sent
=
bytes
=
0
;
sent
=
0
;
spin_lock_irqsave
(
&
chip
->
lock
,
flags
);
chip
->
midi_full
=
0
;
if
(
!
snd_rawmidi_transmit_empty
(
chip
->
midi_out
))
{
...
...
sound/pci/hda/Kconfig
浏览文件 @
a6d4b685
...
...
@@ -285,15 +285,16 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
bool "Enable Silent Stream always for HDMI"
depends on SND_HDA_INTEL
help
Intel hardware has a feature called 'silent stream', that
keeps external HDMI receiver's analog circuitry powered on
avoiding 2-3 sec silence during playback start. This mechanism
relies on setting channel_id as 0xf, sending info packet and
preventing codec D3 entry (increasing platform static power
consumption when HDMI receiver is plugged-in). 2-3 sec silence
at the playback start is expected whenever there is format change.
(default is 2 channel format).
Say Y to enable Silent Stream feature.
Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
for HDMI on hardware that supports the feature.
When enabled, the HDMI/DisplayPort codec will continue to provide
a continuous clock and a valid but silent data stream to
any connected external receiver. This allows to avoid gaps
at start of playback. Many receivers require multiple seconds
to start playing audio after the clock has been stopped.
This feature can impact power consumption as resources
are kept reserved both at transmitter and receiver.
endif
...
...
sound/pci/hda/hda_codec.c
浏览文件 @
a6d4b685
...
...
@@ -766,6 +766,10 @@ static void codec_release_pcms(struct hda_codec *codec)
}
}
/**
* snd_hda_codec_cleanup_for_unbind - Prepare codec for removal
* @codec: codec device to cleanup
*/
void
snd_hda_codec_cleanup_for_unbind
(
struct
hda_codec
*
codec
)
{
if
(
codec
->
registered
)
{
...
...
@@ -813,7 +817,12 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable)
snd_hdac_display_power
(
&
codec
->
bus
->
core
,
codec
->
addr
,
enable
);
}
/* also called from hda_bind.c */
/**
* snd_hda_codec_register - Finalize codec initialization
* @codec: codec device to register
*
* Also called from hda_bind.c
*/
void
snd_hda_codec_register
(
struct
hda_codec
*
codec
)
{
if
(
codec
->
registered
)
...
...
@@ -826,6 +835,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
codec
->
registered
=
1
;
}
}
EXPORT_SYMBOL_GPL
(
snd_hda_codec_register
);
static
int
snd_hda_codec_dev_register
(
struct
snd_device
*
device
)
{
...
...
@@ -833,10 +843,12 @@ static int snd_hda_codec_dev_register(struct snd_device *device)
return
0
;
}
static
int
snd_hda_codec_dev_free
(
struct
snd_device
*
device
)
/**
* snd_hda_codec_unregister - Unregister specified codec device
* @codec: codec device to unregister
*/
void
snd_hda_codec_unregister
(
struct
hda_codec
*
codec
)
{
struct
hda_codec
*
codec
=
device
->
device_data
;
codec
->
in_freeing
=
1
;
/*
* snd_hda_codec_device_new() is used by legacy HDA and ASoC driver.
...
...
@@ -853,7 +865,12 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
*/
if
(
codec
->
core
.
type
==
HDA_DEV_LEGACY
)
put_device
(
hda_codec_dev
(
codec
));
}
EXPORT_SYMBOL_GPL
(
snd_hda_codec_unregister
);
static
int
snd_hda_codec_dev_free
(
struct
snd_device
*
device
)
{
snd_hda_codec_unregister
(
device
->
device_data
);
return
0
;
}
...
...
@@ -877,36 +894,48 @@ static void snd_hda_codec_dev_release(struct device *dev)
#define DEV_NAME_LEN 31
static
int
snd_hda_codec_device_init
(
struct
hda_bus
*
bus
,
struct
snd_card
*
card
,
unsigned
int
codec_addr
,
struct
hda_codec
**
codecp
)
/**
* snd_hda_codec_device_init - allocate HDA codec device
* @bus: codec's parent bus
* @codec_addr: the codec address on the parent bus
* @fmt: format string for the device's name
*
* Returns newly allocated codec device or ERR_PTR() on failure.
*/
struct
hda_codec
*
snd_hda_codec_device_init
(
struct
hda_bus
*
bus
,
unsigned
int
codec_addr
,
const
char
*
fmt
,
...)
{
va_list
vargs
;
char
name
[
DEV_NAME_LEN
];
struct
hda_codec
*
codec
;
int
err
;
dev_dbg
(
card
->
dev
,
"%s: entry
\n
"
,
__func__
);
if
(
snd_BUG_ON
(
!
bus
))
return
-
EINVAL
;
return
ERR_PTR
(
-
EINVAL
)
;
if
(
snd_BUG_ON
(
codec_addr
>
HDA_MAX_CODEC_ADDRESS
))
return
-
EINVAL
;
return
ERR_PTR
(
-
EINVAL
)
;
codec
=
kzalloc
(
sizeof
(
*
codec
),
GFP_KERNEL
);
if
(
!
codec
)
return
-
ENOMEM
;
return
ERR_PTR
(
-
ENOMEM
);
va_start
(
vargs
,
fmt
);
vsprintf
(
name
,
fmt
,
vargs
);
va_end
(
vargs
);
sprintf
(
name
,
"hdaudioC%dD%d"
,
card
->
number
,
codec_addr
);
err
=
snd_hdac_device_init
(
&
codec
->
core
,
&
bus
->
core
,
name
,
codec_addr
);
if
(
err
<
0
)
{
kfree
(
codec
);
return
err
;
return
ERR_PTR
(
err
)
;
}
codec
->
bus
=
bus
;
codec
->
core
.
type
=
HDA_DEV_LEGACY
;
*
codecp
=
codec
;
return
err
;
return
codec
;
}
EXPORT_SYMBOL_GPL
(
snd_hda_codec_device_init
);
/**
* snd_hda_codec_new - create a HDA codec
...
...
@@ -920,18 +949,21 @@ static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card,
int
snd_hda_codec_new
(
struct
hda_bus
*
bus
,
struct
snd_card
*
card
,
unsigned
int
codec_addr
,
struct
hda_codec
**
codecp
)
{
int
ret
;
struct
hda_codec
*
codec
;
ret
=
snd_hda_codec_device_init
(
bus
,
card
,
codec_addr
,
codecp
);
if
(
ret
<
0
)
return
ret
;
codec
=
snd_hda_codec_device_init
(
bus
,
codec_addr
,
"hdaudioC%dD%d"
,
card
->
number
,
codec_addr
);
if
(
IS_ERR
(
codec
))
return
PTR_ERR
(
codec
);
*
codecp
=
codec
;
return
snd_hda_codec_device_new
(
bus
,
card
,
codec_addr
,
*
codecp
);
return
snd_hda_codec_device_new
(
bus
,
card
,
codec_addr
,
*
codecp
,
true
);
}
EXPORT_SYMBOL_GPL
(
snd_hda_codec_new
);
int
snd_hda_codec_device_new
(
struct
hda_bus
*
bus
,
struct
snd_card
*
card
,
unsigned
int
codec_addr
,
struct
hda_codec
*
codec
)
unsigned
int
codec_addr
,
struct
hda_codec
*
codec
,
bool
snddev_managed
)
{
char
component
[
31
];
hda_nid_t
fg
;
...
...
@@ -951,7 +983,6 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
codec
->
core
.
dev
.
release
=
snd_hda_codec_dev_release
;
codec
->
core
.
exec_verb
=
codec_exec_verb
;
codec
->
bus
=
bus
;
codec
->
card
=
card
;
codec
->
addr
=
codec_addr
;
mutex_init
(
&
codec
->
spdif_mutex
);
...
...
@@ -1007,9 +1038,12 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
codec
->
core
.
subsystem_id
,
codec
->
core
.
revision_id
);
snd_component_add
(
card
,
component
);
err
=
snd_device_new
(
card
,
SNDRV_DEV_CODEC
,
codec
,
&
dev_ops
);
if
(
err
<
0
)
goto
error
;
if
(
snddev_managed
)
{
/* ASoC features component management instead */
err
=
snd_device_new
(
card
,
SNDRV_DEV_CODEC
,
codec
,
&
dev_ops
);
if
(
err
<
0
)
goto
error
;
}
/* PM runtime needs to be enabled later after binding codec */
pm_runtime_forbid
(
&
codec
->
core
.
dev
);
...
...
@@ -3371,7 +3405,12 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
EXPORT_SYMBOL_GPL
(
snd_hda_add_new_ctls
);
#ifdef CONFIG_PM
static
void
codec_set_power_save
(
struct
hda_codec
*
codec
,
int
delay
)
/**
* snd_hda_codec_set_power_save - Configure codec's runtime PM
* @codec: codec device to configure
* @delay: autosuspend delay
*/
void
snd_hda_codec_set_power_save
(
struct
hda_codec
*
codec
,
int
delay
)
{
struct
device
*
dev
=
hda_codec_dev
(
codec
);
...
...
@@ -3389,6 +3428,7 @@ static void codec_set_power_save(struct hda_codec *codec, int delay)
pm_runtime_forbid
(
dev
);
}
}
EXPORT_SYMBOL_GPL
(
snd_hda_codec_set_power_save
);
/**
* snd_hda_set_power_save - reprogram autosuspend for the given delay
...
...
@@ -3402,7 +3442,7 @@ void snd_hda_set_power_save(struct hda_bus *bus, int delay)
struct
hda_codec
*
c
;
list_for_each_codec
(
c
,
bus
)
codec_set_power_save
(
c
,
delay
);
snd_hda_
codec_set_power_save
(
c
,
delay
);
}
EXPORT_SYMBOL_GPL
(
snd_hda_set_power_save
);
...
...
sound/pci/hda/hda_intel.c
浏览文件 @
a6d4b685
...
...
@@ -2066,14 +2066,16 @@ static const struct hda_controller_ops pci_hda_ops = {
.
position_check
=
azx_position_check
,
};
static
DECLARE_BITMAP
(
probed_devs
,
SNDRV_CARDS
);
static
int
azx_probe
(
struct
pci_dev
*
pci
,
const
struct
pci_device_id
*
pci_id
)
{
static
int
dev
;
struct
snd_card
*
card
;
struct
hda_intel
*
hda
;
struct
azx
*
chip
;
bool
schedule_probe
;
int
dev
;
int
err
;
if
(
pci_match_id
(
driver_denylist
,
pci
))
{
...
...
@@ -2081,10 +2083,11 @@ static int azx_probe(struct pci_dev *pci,
return
-
ENODEV
;
}
dev
=
find_first_zero_bit
(
probed_devs
,
SNDRV_CARDS
);
if
(
dev
>=
SNDRV_CARDS
)
return
-
ENODEV
;
if
(
!
enable
[
dev
])
{
dev
++
;
set_bit
(
dev
,
probed_devs
)
;
return
-
ENOENT
;
}
...
...
@@ -2151,7 +2154,7 @@ static int azx_probe(struct pci_dev *pci,
if
(
schedule_probe
)
schedule_delayed_work
(
&
hda
->
probe_work
,
0
);
dev
++
;
set_bit
(
dev
,
probed_devs
)
;
if
(
chip
->
disabled
)
complete_all
(
&
hda
->
probe_wait
);
return
0
;
...
...
@@ -2374,6 +2377,7 @@ static void azx_remove(struct pci_dev *pci)
cancel_delayed_work_sync
(
&
hda
->
probe_work
);
device_lock
(
&
pci
->
dev
);
clear_bit
(
chip
->
dev_index
,
probed_devs
);
pci_set_drvdata
(
pci
,
NULL
);
snd_card_free
(
card
);
}
...
...
@@ -2495,6 +2499,8 @@ static const struct pci_device_id azx_ids[] = {
/* Alderlake-P */
{
PCI_DEVICE
(
0x8086
,
0x51c8
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x51c9
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x51cd
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
/* Alderlake-M */
...
...
@@ -2508,6 +2514,17 @@ static const struct pci_device_id azx_ids[] = {
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x4b58
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
/* Raptor Lake */
{
PCI_DEVICE
(
0x8086
,
0x7a50
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x51ca
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x51cb
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x51ce
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
{
PCI_DEVICE
(
0x8086
,
0x51cf
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_SKYLAKE
},
/* Broxton-P(Apollolake) */
{
PCI_DEVICE
(
0x8086
,
0x5a98
),
.
driver_data
=
AZX_DRIVER_SKL
|
AZX_DCAPS_INTEL_BROXTON
},
...
...
sound/pci/hda/hda_local.h
浏览文件 @
a6d4b685
...
...
@@ -135,8 +135,6 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \
__snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL)
int
snd_hda_codec_reset
(
struct
hda_codec
*
codec
);
void
snd_hda_codec_register
(
struct
hda_codec
*
codec
);
void
snd_hda_codec_cleanup_for_unbind
(
struct
hda_codec
*
codec
);
void
snd_hda_codec_disconnect_pcms
(
struct
hda_codec
*
codec
);
#define snd_hda_regmap_sync(codec) snd_hdac_regmap_sync(&(codec)->core)
...
...
sound/pci/hda/hda_tegra.c
浏览文件 @
a6d4b685
...
...
@@ -70,6 +70,7 @@
struct
hda_tegra_soc
{
bool
has_hda2codec_2x_reset
;
bool
has_hda2hdmi
;
};
struct
hda_tegra
{
...
...
@@ -314,6 +315,18 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
* hardcoded value
*/
chip
->
capture_streams
=
(
gcap
>>
8
)
&
0x0f
;
/* The GCAP register on Tegra234 implies no Input Streams(ISS) support,
* but the HW output stream descriptor programming should start with
* offset 0x20*4 from base stream descriptor address. This will be a
* problem while calculating the offset for output stream descriptor
* which will be considering input stream also. So here output stream
* starts with offset 0 which is wrong as HW register for output stream
* offset starts with 4.
*/
if
(
of_device_is_compatible
(
np
,
"nvidia,tegra234-hda"
))
chip
->
capture_streams
=
4
;
chip
->
playback_streams
=
(
gcap
>>
12
)
&
0x0f
;
if
(
!
chip
->
playback_streams
&&
!
chip
->
capture_streams
)
{
/* gcap didn't give any info, switching to old method */
...
...
@@ -435,15 +448,23 @@ static int hda_tegra_create(struct snd_card *card,
static
const
struct
hda_tegra_soc
tegra30_data
=
{
.
has_hda2codec_2x_reset
=
true
,
.
has_hda2hdmi
=
true
,
};
static
const
struct
hda_tegra_soc
tegra194_data
=
{
.
has_hda2codec_2x_reset
=
false
,
.
has_hda2hdmi
=
true
,
};
static
const
struct
hda_tegra_soc
tegra234_data
=
{
.
has_hda2codec_2x_reset
=
true
,
.
has_hda2hdmi
=
false
,
};
static
const
struct
of_device_id
hda_tegra_match
[]
=
{
{
.
compatible
=
"nvidia,tegra30-hda"
,
.
data
=
&
tegra30_data
},
{
.
compatible
=
"nvidia,tegra194-hda"
,
.
data
=
&
tegra194_data
},
{
.
compatible
=
"nvidia,tegra234-hda"
,
.
data
=
&
tegra234_data
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
hda_tegra_match
);
...
...
@@ -473,7 +494,14 @@ static int hda_tegra_probe(struct platform_device *pdev)
}
hda
->
resets
[
hda
->
nresets
++
].
id
=
"hda"
;
hda
->
resets
[
hda
->
nresets
++
].
id
=
"hda2hdmi"
;
/*
* "hda2hdmi" is not applicable for Tegra234. This is because the
* codec is separate IP and not under display SOR partition now.
*/
if
(
hda
->
soc
->
has_hda2hdmi
)
hda
->
resets
[
hda
->
nresets
++
].
id
=
"hda2hdmi"
;
/*
* "hda2codec_2x" reset is not present on Tegra194. Though DT would
* be updated to reflect this, but to have backward compatibility
...
...
@@ -488,7 +516,8 @@ static int hda_tegra_probe(struct platform_device *pdev)
goto
out_free
;
hda
->
clocks
[
hda
->
nclocks
++
].
id
=
"hda"
;
hda
->
clocks
[
hda
->
nclocks
++
].
id
=
"hda2hdmi"
;
if
(
hda
->
soc
->
has_hda2hdmi
)
hda
->
clocks
[
hda
->
nclocks
++
].
id
=
"hda2hdmi"
;
hda
->
clocks
[
hda
->
nclocks
++
].
id
=
"hda2codec_2x"
;
err
=
devm_clk_bulk_get
(
&
pdev
->
dev
,
hda
->
nclocks
,
hda
->
clocks
);
...
...
sound/pci/hda/patch_hdmi.c
浏览文件 @
a6d4b685
...
...
@@ -120,6 +120,12 @@ struct hdmi_pcm {
struct
snd_kcontrol
*
eld_ctl
;
};
enum
{
SILENT_STREAM_OFF
=
0
,
SILENT_STREAM_KAE
,
/* use standard HDA Keep-Alive */
SILENT_STREAM_I915
,
/* Intel i915 extension */
};
struct
hdmi_spec
{
struct
hda_codec
*
codec
;
int
num_cvts
;
...
...
@@ -162,6 +168,8 @@ struct hdmi_spec {
bool
dyn_pin_out
;
bool
dyn_pcm_assign
;
bool
dyn_pcm_no_legacy
;
/* hdmi interrupt trigger control flag for Nvidia codec */
bool
hdmi_intr_trig_ctrl
;
bool
intel_hsw_fixup
;
/* apply Intel platform-specific fixups */
/*
* Non-generic VIA/NVIDIA specific
...
...
@@ -179,7 +187,7 @@ struct hdmi_spec {
hda_nid_t
vendor_nid
;
const
int
*
port_map
;
int
port_num
;
bool
send_silent_stream
;
/* Flag to enable silent stream feature */
int
silent_stream_type
;
};
#ifdef CONFIG_SND_HDA_COMPONENT
...
...
@@ -1665,18 +1673,71 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
#define I915_SILENT_FORMAT_BITS 16
#define I915_SILENT_FMT_MASK 0xf
static
void
silent_stream_enable_i915
(
struct
hda_codec
*
codec
,
struct
hdmi_spec_per_pin
*
per_pin
)
{
unsigned
int
format
;
snd_hdac_sync_audio_rate
(
&
codec
->
core
,
per_pin
->
pin_nid
,
per_pin
->
dev_id
,
I915_SILENT_RATE
);
/* trigger silent stream generation in hw */
format
=
snd_hdac_calc_stream_format
(
I915_SILENT_RATE
,
I915_SILENT_CHANNELS
,
I915_SILENT_FORMAT
,
I915_SILENT_FORMAT_BITS
,
0
);
snd_hda_codec_setup_stream
(
codec
,
per_pin
->
cvt_nid
,
I915_SILENT_FMT_MASK
,
I915_SILENT_FMT_MASK
,
format
);
usleep_range
(
100
,
200
);
snd_hda_codec_setup_stream
(
codec
,
per_pin
->
cvt_nid
,
I915_SILENT_FMT_MASK
,
0
,
format
);
per_pin
->
channels
=
I915_SILENT_CHANNELS
;
hdmi_setup_audio_infoframe
(
codec
,
per_pin
,
per_pin
->
non_pcm
);
}
static
void
silent_stream_set_kae
(
struct
hda_codec
*
codec
,
struct
hdmi_spec_per_pin
*
per_pin
,
bool
enable
)
{
unsigned
int
param
;
codec_dbg
(
codec
,
"HDMI: KAE %d cvt-NID=0x%x
\n
"
,
enable
,
per_pin
->
cvt_nid
);
param
=
snd_hda_codec_read
(
codec
,
per_pin
->
cvt_nid
,
0
,
AC_VERB_GET_DIGI_CONVERT_1
,
0
);
param
=
(
param
>>
16
)
&
0xff
;
if
(
enable
)
param
|=
AC_DIG3_KAE
;
else
param
&=
~
AC_DIG3_KAE
;
snd_hda_codec_write
(
codec
,
per_pin
->
cvt_nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_3
,
param
);
}
static
void
silent_stream_enable
(
struct
hda_codec
*
codec
,
struct
hdmi_spec_per_pin
*
per_pin
)
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec_per_cvt
*
per_cvt
;
int
cvt_idx
,
pin_idx
,
err
;
unsigned
int
format
;
int
keep_power
=
0
;
/*
* Power-up will call hdmi_present_sense, so the PM calls
* have to be done without mutex held.
*/
err
=
snd_hda_power_up_pm
(
codec
);
if
(
err
<
0
&&
err
!=
-
EACCES
)
{
codec_err
(
codec
,
"Failed to power up codec for silent stream enable ret=[%d]
\n
"
,
err
);
snd_hda_power_down_pm
(
codec
);
return
;
}
mutex_lock
(
&
per_pin
->
lock
);
if
(
per_pin
->
setup
)
{
codec_dbg
(
codec
,
"hdmi: PCM already open, no silent stream
\n
"
);
err
=
-
EBUSY
;
goto
unlock_out
;
}
...
...
@@ -1703,22 +1764,23 @@ static void silent_stream_enable(struct hda_codec *codec,
/* configure unused pins to choose other converters */
pin_cvt_fixup
(
codec
,
per_pin
,
0
);
snd_hdac_sync_audio_rate
(
&
codec
->
core
,
per_pin
->
pin_nid
,
per_pin
->
dev_id
,
I915_SILENT_RATE
);
/* trigger silent stream generation in hw */
format
=
snd_hdac_calc_stream_format
(
I915_SILENT_RATE
,
I915_SILENT_CHANNELS
,
I915_SILENT_FORMAT
,
I915_SILENT_FORMAT_BITS
,
0
);
snd_hda_codec_setup_stream
(
codec
,
per_pin
->
cvt_nid
,
I915_SILENT_FMT_MASK
,
I915_SILENT_FMT_MASK
,
format
);
usleep_range
(
100
,
200
);
snd_hda_codec_setup_stream
(
codec
,
per_pin
->
cvt_nid
,
I915_SILENT_FMT_MASK
,
0
,
format
);
per_pin
->
channels
=
I915_SILENT_CHANNELS
;
hdmi_setup_audio_infoframe
(
codec
,
per_pin
,
per_pin
->
non_pcm
);
switch
(
spec
->
silent_stream_type
)
{
case
SILENT_STREAM_KAE
:
silent_stream_set_kae
(
codec
,
per_pin
,
true
);
break
;
case
SILENT_STREAM_I915
:
silent_stream_enable_i915
(
codec
,
per_pin
);
keep_power
=
1
;
break
;
default:
break
;
}
unlock_out:
mutex_unlock
(
&
per_pin
->
lock
);
if
(
err
||
!
keep_power
)
snd_hda_power_down_pm
(
codec
);
}
static
void
silent_stream_disable
(
struct
hda_codec
*
codec
,
...
...
@@ -1726,7 +1788,16 @@ static void silent_stream_disable(struct hda_codec *codec,
{
struct
hdmi_spec
*
spec
=
codec
->
spec
;
struct
hdmi_spec_per_cvt
*
per_cvt
;
int
cvt_idx
;
int
cvt_idx
,
err
;
err
=
snd_hda_power_up_pm
(
codec
);
if
(
err
<
0
&&
err
!=
-
EACCES
)
{
codec_err
(
codec
,
"Failed to power up codec for silent stream disable ret=[%d]
\n
"
,
err
);
snd_hda_power_down_pm
(
codec
);
return
;
}
mutex_lock
(
&
per_pin
->
lock
);
if
(
!
per_pin
->
silent_stream
)
...
...
@@ -1741,11 +1812,20 @@ static void silent_stream_disable(struct hda_codec *codec,
per_cvt
->
assigned
=
0
;
}
if
(
spec
->
silent_stream_type
==
SILENT_STREAM_I915
)
{
/* release ref taken in silent_stream_enable() */
snd_hda_power_down_pm
(
codec
);
}
else
if
(
spec
->
silent_stream_type
==
SILENT_STREAM_KAE
)
{
silent_stream_set_kae
(
codec
,
per_pin
,
false
);
}
per_pin
->
cvt_nid
=
0
;
per_pin
->
silent_stream
=
false
;
unlock_out:
mutex_unlock
(
&
per_pin
->
lock
);
snd_hda_power_down_pm
(
codec
);
}
/* update ELD and jack state via audio component */
...
...
@@ -1767,29 +1847,11 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
monitor_next
=
per_pin
->
sink_eld
.
monitor_present
;
mutex_unlock
(
&
per_pin
->
lock
);
/*
* Power-up will call hdmi_present_sense, so the PM calls
* have to be done without mutex held.
*/
if
(
spec
->
send_silent_stream
)
{
int
pm_ret
;
if
(
!
monitor_prev
&&
monitor_next
)
{
pm_ret
=
snd_hda_power_up_pm
(
codec
);
if
(
pm_ret
<
0
)
codec_err
(
codec
,
"Monitor plugged-in, Failed to power up codec ret=[%d]
\n
"
,
pm_ret
);
if
(
spec
->
silent_stream_type
)
{
if
(
!
monitor_prev
&&
monitor_next
)
silent_stream_enable
(
codec
,
per_pin
);
}
else
if
(
monitor_prev
&&
!
monitor_next
)
{
else
if
(
monitor_prev
&&
!
monitor_next
)
silent_stream_disable
(
codec
,
per_pin
);
pm_ret
=
snd_hda_power_down_pm
(
codec
);
if
(
pm_ret
<
0
)
codec_err
(
codec
,
"Monitor plugged-out, Failed to power down codec ret=[%d]
\n
"
,
pm_ret
);
}
}
}
...
...
@@ -2982,7 +3044,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
* module param or Kconfig option
*/
if
(
send_silent_stream
)
spec
->
s
end_silent_stream
=
true
;
spec
->
s
ilent_stream_type
=
SILENT_STREAM_I915
;
return
parse_intel_hdmi
(
codec
);
}
...
...
@@ -3035,6 +3097,22 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec)
return
ret
;
}
static
int
patch_i915_adlp_hdmi
(
struct
hda_codec
*
codec
)
{
struct
hdmi_spec
*
spec
;
int
res
;
res
=
patch_i915_tgl_hdmi
(
codec
);
if
(
!
res
)
{
spec
=
codec
->
spec
;
if
(
spec
->
silent_stream_type
)
spec
->
silent_stream_type
=
SILENT_STREAM_KAE
;
}
return
res
;
}
/* Intel Baytrail and Braswell; with eld notifier */
static
int
patch_i915_byt_hdmi
(
struct
hda_codec
*
codec
)
{
...
...
@@ -3721,8 +3799,11 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec)
* +-----------------------------------|
*
* Note that for the trigger bit to take effect it needs to change value
* (i.e. it needs to be toggled).
* (i.e. it needs to be toggled). The trigger bit is not applicable from
* TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
* trigger to hdmi.
*/
#define NVIDIA_SET_HOST_INTR 0xf80
#define NVIDIA_GET_SCRATCH0 0xfa6
#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7
#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8
...
...
@@ -3741,25 +3822,38 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec)
* The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
* the format is invalidated so that the HDMI codec can be disabled.
*/
static
void
tegra_hdmi_set_format
(
struct
hda_codec
*
codec
,
unsigned
int
format
)
static
void
tegra_hdmi_set_format
(
struct
hda_codec
*
codec
,
hda_nid_t
cvt_nid
,
unsigned
int
format
)
{
unsigned
int
value
;
unsigned
int
nid
=
NVIDIA_AFG_NID
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
/*
* Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
* This resulted in moving scratch registers from audio function
* group to converter widget context. So CVT NID should be used for
* scratch register read/write for DP MST supported Tegra HDA codec.
*/
if
(
codec
->
dp_mst
)
nid
=
cvt_nid
;
/* bits [31:30] contain the trigger and valid bits */
value
=
snd_hda_codec_read
(
codec
,
NVIDIA_AFG_NID
,
0
,
value
=
snd_hda_codec_read
(
codec
,
nid
,
0
,
NVIDIA_GET_SCRATCH0
,
0
);
value
=
(
value
>>
24
)
&
0xff
;
/* bits [15:0] are used to store the HDA format */
snd_hda_codec_write
(
codec
,
NVIDIA_AFG_NID
,
0
,
snd_hda_codec_write
(
codec
,
nid
,
0
,
NVIDIA_SET_SCRATCH0_BYTE0
,
(
format
>>
0
)
&
0xff
);
snd_hda_codec_write
(
codec
,
NVIDIA_AFG_NID
,
0
,
snd_hda_codec_write
(
codec
,
nid
,
0
,
NVIDIA_SET_SCRATCH0_BYTE1
,
(
format
>>
8
)
&
0xff
);
/* bits [16:24] are unused */
snd_hda_codec_write
(
codec
,
NVIDIA_AFG_NID
,
0
,
snd_hda_codec_write
(
codec
,
nid
,
0
,
NVIDIA_SET_SCRATCH0_BYTE2
,
0
);
/*
...
...
@@ -3771,15 +3865,28 @@ static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format)
else
value
|=
NVIDIA_SCRATCH_VALID
;
/*
* Whenever the trigger bit is toggled, an interrupt is raised in the
* HDMI codec. The HDMI driver will use that as trigger to update its
* configuration.
*/
value
^=
NVIDIA_SCRATCH_TRIGGER
;
if
(
spec
->
hdmi_intr_trig_ctrl
)
{
/*
* For Tegra HDA Codec design from TEGRA234 onwards, the
* Interrupt to hdmi driver is triggered by writing
* non-zero values to verb 0xF80 instead of 31st bit of
* scratch register.
*/
snd_hda_codec_write
(
codec
,
nid
,
0
,
NVIDIA_SET_SCRATCH0_BYTE3
,
value
);
snd_hda_codec_write
(
codec
,
nid
,
0
,
NVIDIA_SET_HOST_INTR
,
0x1
);
}
else
{
/*
* Whenever the 31st trigger bit is toggled, an interrupt is raised
* in the HDMI codec. The HDMI driver will use that as trigger
* to update its configuration.
*/
value
^=
NVIDIA_SCRATCH_TRIGGER
;
snd_hda_codec_write
(
codec
,
NVIDIA_AFG_NID
,
0
,
NVIDIA_SET_SCRATCH0_BYTE3
,
value
);
snd_hda_codec_write
(
codec
,
nid
,
0
,
NVIDIA_SET_SCRATCH0_BYTE3
,
value
);
}
}
static
int
tegra_hdmi_pcm_prepare
(
struct
hda_pcm_stream
*
hinfo
,
...
...
@@ -3796,7 +3903,7 @@ static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
return
err
;
/* notify the HDMI codec of the format change */
tegra_hdmi_set_format
(
codec
,
format
);
tegra_hdmi_set_format
(
codec
,
hinfo
->
nid
,
format
);
return
0
;
}
...
...
@@ -3806,7 +3913,7 @@ static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct
snd_pcm_substream
*
substream
)
{
/* invalidate the format in the HDMI codec */
tegra_hdmi_set_format
(
codec
,
0
);
tegra_hdmi_set_format
(
codec
,
hinfo
->
nid
,
0
);
return
generic_hdmi_playback_pcm_cleanup
(
hinfo
,
codec
,
substream
);
}
...
...
@@ -3851,17 +3958,29 @@ static int tegra_hdmi_build_pcms(struct hda_codec *codec)
return
0
;
}
static
int
patch_tegra_hdmi
(
struct
hda_codec
*
codec
)
static
int
tegra_hdmi_init
(
struct
hda_codec
*
codec
)
{
struct
hdmi_spec
*
spec
;
int
err
;
struct
hdmi_spec
*
spec
=
codec
->
spec
;
int
i
,
err
;
err
=
patch_generic_hdmi
(
codec
);
if
(
err
)
err
=
hdmi_parse_codec
(
codec
);
if
(
err
<
0
)
{
generic_spec_free
(
codec
);
return
err
;
}
for
(
i
=
0
;
i
<
spec
->
num_cvts
;
i
++
)
snd_hda_codec_write
(
codec
,
spec
->
cvt_nids
[
i
],
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
AC_DIG1_ENABLE
);
generic_hdmi_init_per_pins
(
codec
);
codec
->
patch_ops
.
build_pcms
=
tegra_hdmi_build_pcms
;
spec
=
codec
->
spec
;
spec
->
chmap
.
ops
.
chmap_cea_alloc_validate_get_type
=
nvhdmi_chmap_cea_alloc_validate_get_type
;
spec
->
chmap
.
ops
.
chmap_validate
=
nvhdmi_chmap_validate
;
spec
->
chmap
.
ops
.
chmap_cea_alloc_validate_get_type
=
nvhdmi_chmap_cea_alloc_validate_get_type
;
spec
->
chmap
.
ops
.
chmap_validate
=
nvhdmi_chmap_validate
;
...
...
@@ -3869,6 +3988,36 @@ static int patch_tegra_hdmi(struct hda_codec *codec)
return
0
;
}
static
int
patch_tegra_hdmi
(
struct
hda_codec
*
codec
)
{
int
err
;
err
=
alloc_generic_hdmi
(
codec
);
if
(
err
<
0
)
return
err
;
return
tegra_hdmi_init
(
codec
);
}
static
int
patch_tegra234_hdmi
(
struct
hda_codec
*
codec
)
{
struct
hdmi_spec
*
spec
;
int
err
;
err
=
alloc_generic_hdmi
(
codec
);
if
(
err
<
0
)
return
err
;
codec
->
dp_mst
=
true
;
codec
->
mst_no_extra_pcms
=
true
;
spec
=
codec
->
spec
;
spec
->
dyn_pin_out
=
true
;
spec
->
dyn_pcm_assign
=
true
;
spec
->
hdmi_intr_trig_ctrl
=
true
;
return
tegra_hdmi_init
(
codec
);
}
/*
* ATI/AMD-specific implementations
*/
...
...
@@ -4322,6 +4471,7 @@ HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
HDA_CODEC_ENTRY
(
0x10de002e
,
"Tegra186 HDMI/DP1"
,
patch_tegra_hdmi
),
HDA_CODEC_ENTRY
(
0x10de002f
,
"Tegra194 HDMI/DP2"
,
patch_tegra_hdmi
),
HDA_CODEC_ENTRY
(
0x10de0030
,
"Tegra194 HDMI/DP3"
,
patch_tegra_hdmi
),
HDA_CODEC_ENTRY
(
0x10de0031
,
"Tegra234 HDMI/DP"
,
patch_tegra234_hdmi
),
HDA_CODEC_ENTRY
(
0x10de0040
,
"GPU 40 HDMI/DP"
,
patch_nvhdmi
),
HDA_CODEC_ENTRY
(
0x10de0041
,
"GPU 41 HDMI/DP"
,
patch_nvhdmi
),
HDA_CODEC_ENTRY
(
0x10de0042
,
"GPU 42 HDMI/DP"
,
patch_nvhdmi
),
...
...
@@ -4390,10 +4540,11 @@ HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
HDA_CODEC_ENTRY
(
0x80862814
,
"DG1 HDMI"
,
patch_i915_tgl_hdmi
),
HDA_CODEC_ENTRY
(
0x80862815
,
"Alderlake HDMI"
,
patch_i915_tgl_hdmi
),
HDA_CODEC_ENTRY
(
0x80862816
,
"Rocketlake HDMI"
,
patch_i915_tgl_hdmi
),
HDA_CODEC_ENTRY
(
0x80862819
,
"DG2 HDMI"
,
patch_i915_tgl_hdmi
),
HDA_CODEC_ENTRY
(
0x80862818
,
"Raptorlake HDMI"
,
patch_i915_tgl_hdmi
),
HDA_CODEC_ENTRY
(
0x80862819
,
"DG2 HDMI"
,
patch_i915_adlp_hdmi
),
HDA_CODEC_ENTRY
(
0x8086281a
,
"Jasperlake HDMI"
,
patch_i915_icl_hdmi
),
HDA_CODEC_ENTRY
(
0x8086281b
,
"Elkhartlake HDMI"
,
patch_i915_icl_hdmi
),
HDA_CODEC_ENTRY
(
0x8086281c
,
"Alderlake-P HDMI"
,
patch_i915_
tgl
_hdmi
),
HDA_CODEC_ENTRY
(
0x8086281c
,
"Alderlake-P HDMI"
,
patch_i915_
adlp
_hdmi
),
HDA_CODEC_ENTRY
(
0x80862880
,
"CedarTrail HDMI"
,
patch_generic_hdmi
),
HDA_CODEC_ENTRY
(
0x80862882
,
"Valleyview2 HDMI"
,
patch_i915_byt_hdmi
),
HDA_CODEC_ENTRY
(
0x80862883
,
"Braswell HDMI"
,
patch_i915_byt_hdmi
),
...
...
sound/pci/hda/patch_realtek.c
浏览文件 @
a6d4b685
...
...
@@ -6662,6 +6662,16 @@ static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup
cs35l41_generic_fixup
(
cdc
,
action
,
"i2c"
,
"CSC3551"
,
2
);
}
static
void
cs35l41_fixup_spi_two
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
{
cs35l41_generic_fixup
(
codec
,
action
,
"spi0"
,
"CSC3551"
,
2
);
}
static
void
cs35l41_fixup_spi_four
(
struct
hda_codec
*
codec
,
const
struct
hda_fixup
*
fix
,
int
action
)
{
cs35l41_generic_fixup
(
codec
,
action
,
"spi0"
,
"CSC3551"
,
4
);
}
static
void
alc287_legion_16achg6_playback_hook
(
struct
hda_pcm_stream
*
hinfo
,
struct
hda_codec
*
cdc
,
struct
snd_pcm_substream
*
sub
,
int
action
)
{
...
...
@@ -6999,6 +7009,9 @@ enum {
ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE
,
ALC287_FIXUP_LEGION_16ACHG6
,
ALC287_FIXUP_CS35L41_I2C_2
,
ALC245_FIXUP_CS35L41_SPI_2
,
ALC245_FIXUP_CS35L41_SPI_4
,
ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED
,
ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED
,
};
...
...
@@ -8750,6 +8763,20 @@ static const struct hda_fixup alc269_fixups[] = {
.
type
=
HDA_FIXUP_FUNC
,
.
v
.
func
=
cs35l41_fixup_i2c_two
,
},
[
ALC245_FIXUP_CS35L41_SPI_2
]
=
{
.
type
=
HDA_FIXUP_FUNC
,
.
v
.
func
=
cs35l41_fixup_spi_two
,
},
[
ALC245_FIXUP_CS35L41_SPI_4
]
=
{
.
type
=
HDA_FIXUP_FUNC
,
.
v
.
func
=
cs35l41_fixup_spi_four
,
},
[
ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED
]
=
{
.
type
=
HDA_FIXUP_FUNC
,
.
v
.
func
=
cs35l41_fixup_spi_four
,
.
chained
=
true
,
.
chain_id
=
ALC285_FIXUP_HP_GPIO_LED
,
},
[
ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED
]
=
{
.
type
=
HDA_FIXUP_VERBS
,
.
v
.
verbs
=
(
const
struct
hda_verb
[])
{
...
...
@@ -8977,7 +9004,25 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK
(
0x103c
,
0x8896
,
"HP EliteBook 855 G8 Notebook PC"
,
ALC285_FIXUP_HP_MUTE_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x8898
,
"HP EliteBook 845 G8 Notebook PC"
,
ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST
),
SND_PCI_QUIRK
(
0x103c
,
0x88d0
,
"HP Pavilion 15-eh1xxx (mainboard 88D0)"
,
ALC287_FIXUP_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x89c3
,
"HP"
,
ALC285_FIXUP_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x896e
,
"HP EliteBook x360 830 G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8971
,
"HP EliteBook 830 G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8972
,
"HP EliteBook 840 G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8973
,
"HP EliteBook 860 G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8974
,
"HP EliteBook 840 Aero G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8975
,
"HP EliteBook x360 840 Aero G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8981
,
"HP Elite Dragonfly G3"
,
ALC245_FIXUP_CS35L41_SPI_4
),
SND_PCI_QUIRK
(
0x103c
,
0x898e
,
"HP EliteBook 835 G9"
,
ALC287_FIXUP_CS35L41_I2C_2
),
SND_PCI_QUIRK
(
0x103c
,
0x898f
,
"HP EliteBook 835 G9"
,
ALC287_FIXUP_CS35L41_I2C_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8991
,
"HP EliteBook 845 G9"
,
ALC287_FIXUP_CS35L41_I2C_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8992
,
"HP EliteBook 845 G9"
,
ALC287_FIXUP_CS35L41_I2C_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8994
,
"HP EliteBook 855 G9"
,
ALC287_FIXUP_CS35L41_I2C_2
),
SND_PCI_QUIRK
(
0x103c
,
0x8995
,
"HP EliteBook 855 G9"
,
ALC287_FIXUP_CS35L41_I2C_2
),
SND_PCI_QUIRK
(
0x103c
,
0x89a4
,
"HP ProBook 440 G9"
,
ALC236_FIXUP_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x89a6
,
"HP ProBook 450 G9"
,
ALC236_FIXUP_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x89ac
,
"HP EliteBook 640 G9"
,
ALC236_FIXUP_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x89ae
,
"HP EliteBook 650 G9"
,
ALC236_FIXUP_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x89c3
,
"Zbook Studio G9"
,
ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED
),
SND_PCI_QUIRK
(
0x103c
,
0x89c6
,
"Zbook Fury 17 G9"
,
ALC245_FIXUP_CS35L41_SPI_2
),
SND_PCI_QUIRK
(
0x103c
,
0x89ca
,
"HP"
,
ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF
),
SND_PCI_QUIRK
(
0x1043
,
0x103e
,
"ASUS X540SA"
,
ALC256_FIXUP_ASUS_MIC
),
SND_PCI_QUIRK
(
0x1043
,
0x103f
,
"ASUS TX300"
,
ALC282_FIXUP_ASUS_TX300
),
...
...
sound/pci/lola/lola_mixer.c
浏览文件 @
a6d4b685
...
...
@@ -121,6 +121,8 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
/* reserve memory to copy mixer data for sleep mode transitions */
chip
->
mixer
.
array_saved
=
vmalloc
(
sizeof
(
struct
lola_mixer_array
));
if
(
!
chip
->
mixer
.
array_saved
)
return
-
ENOMEM
;
/* mixer matrix sources are physical input data and play streams */
chip
->
mixer
.
src_stream_outs
=
chip
->
pcm
[
PLAY
].
num_streams
;
...
...
sound/soc/codecs/hdac_hda.c
浏览文件 @
a6d4b685
...
...
@@ -413,7 +413,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
HDA_CODEC_IDX_CONTROLLER
,
true
);
ret
=
snd_hda_codec_device_new
(
hcodec
->
bus
,
component
->
card
->
snd_card
,
hdev
->
addr
,
hcodec
);
hdev
->
addr
,
hcodec
,
true
);
if
(
ret
<
0
)
{
dev_err
(
&
hdev
->
dev
,
"failed to create hda codec %d
\n
"
,
ret
);
goto
error_no_pm
;
...
...
sound/sound_core.c
浏览文件 @
a6d4b685
...
...
@@ -136,11 +136,7 @@ struct sound_unit
* All these clutters are scheduled to be removed along with
* sound-slot/service-* module aliases.
*/
#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
static
int
preclaim_oss
=
1
;
#else
static
int
preclaim_oss
=
0
;
#endif
static
int
preclaim_oss
=
IS_ENABLED
(
CONFIG_SOUND_OSS_CORE_PRECLAIM
);
module_param
(
preclaim_oss
,
int
,
0444
);
...
...
@@ -581,20 +577,20 @@ static int soundcore_open(struct inode *inode, struct file *file)
new_fops
=
fops_get
(
s
->
unit_fops
);
}
spin_unlock
(
&
sound_loader_lock
);
if
(
new_fops
)
{
/*
* We rely upon the fact that we can't be unloaded while the
* subdriver is there.
*/
int
err
=
0
;
replace_fops
(
file
,
new_fops
);
if
(
file
->
f_op
->
open
)
err
=
file
->
f_op
->
open
(
inode
,
file
)
;
if
(
!
new_fops
)
return
-
ENODEV
;
return
err
;
}
return
-
ENODEV
;
/*
* We rely upon the fact that we can't be unloaded while the
* subdriver is there.
*/
replace_fops
(
file
,
new_fops
);
if
(
!
file
->
f_op
->
open
)
return
-
ENODEV
;
return
file
->
f_op
->
open
(
inode
,
file
);
}
MODULE_ALIAS_CHARDEV_MAJOR
(
SOUND_MAJOR
);
...
...
sound/spi/at73c213.c
浏览文件 @
a6d4b685
...
...
@@ -218,7 +218,9 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream)
runtime
->
hw
=
snd_at73c213_playback_hw
;
chip
->
substream
=
substream
;
clk_enable
(
chip
->
ssc
->
clk
);
err
=
clk_enable
(
chip
->
ssc
->
clk
);
if
(
err
)
return
err
;
return
0
;
}
...
...
@@ -776,7 +778,9 @@ static int snd_at73c213_chip_init(struct snd_at73c213 *chip)
goto
out
;
/* Enable DAC master clock. */
clk_enable
(
chip
->
board
->
dac_clk
);
retval
=
clk_enable
(
chip
->
board
->
dac_clk
);
if
(
retval
)
goto
out
;
/* Initialize at73c213 on SPI bus. */
retval
=
snd_at73c213_write_reg
(
chip
,
DAC_RST
,
0x04
);
...
...
@@ -889,7 +893,9 @@ static int snd_at73c213_dev_init(struct snd_card *card,
chip
->
card
=
card
;
chip
->
irq
=
-
1
;
clk_enable
(
chip
->
ssc
->
clk
);
retval
=
clk_enable
(
chip
->
ssc
->
clk
);
if
(
retval
)
return
retval
;
retval
=
request_irq
(
irq
,
snd_at73c213_interrupt
,
0
,
"at73c213"
,
chip
);
if
(
retval
)
{
...
...
@@ -1008,7 +1014,9 @@ static int snd_at73c213_remove(struct spi_device *spi)
int
retval
;
/* Stop playback. */
clk_enable
(
chip
->
ssc
->
clk
);
retval
=
clk_enable
(
chip
->
ssc
->
clk
);
if
(
retval
)
goto
out
;
ssc_writel
(
chip
->
ssc
->
regs
,
CR
,
SSC_BIT
(
CR_TXDIS
));
clk_disable
(
chip
->
ssc
->
clk
);
...
...
@@ -1088,9 +1096,16 @@ static int snd_at73c213_resume(struct device *dev)
{
struct
snd_card
*
card
=
dev_get_drvdata
(
dev
);
struct
snd_at73c213
*
chip
=
card
->
private_data
;
int
retval
;
clk_enable
(
chip
->
board
->
dac_clk
);
clk_enable
(
chip
->
ssc
->
clk
);
retval
=
clk_enable
(
chip
->
board
->
dac_clk
);
if
(
retval
)
return
retval
;
retval
=
clk_enable
(
chip
->
ssc
->
clk
);
if
(
retval
)
{
clk_disable
(
chip
->
board
->
dac_clk
);
return
retval
;
}
ssc_writel
(
chip
->
ssc
->
regs
,
CR
,
SSC_BIT
(
CR_TXEN
));
return
0
;
...
...
sound/usb/mixer_s1810c.c
浏览文件 @
a6d4b685
...
...
@@ -221,7 +221,7 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip)
e
=
0xbc
;
for
(
n
=
0
;
n
<
2
;
n
++
)
{
off
=
n
*
18
;
for
(
b
=
off
,
c
=
0
;
b
<
18
+
off
;
b
++
)
{
for
(
b
=
off
;
b
<
18
+
off
;
b
++
)
{
/* This channel to all outputs ? */
for
(
c
=
0
;
c
<=
8
;
c
++
)
{
snd_s1810c_send_ctl_packet
(
dev
,
a
,
b
,
c
,
0
,
e
);
...
...
sound/usb/mixer_scarlett_gen2.c
浏览文件 @
a6d4b685
...
...
@@ -6,7 +6,7 @@
* - 6i6/18i8/18i20 Gen 2
* - Solo/2i2/4i4/8i6/18i8/18i20 Gen 3
*
* Copyright (c) 2018-202
1
by Geoffrey D. Bennett <g at b4.vu>
* Copyright (c) 2018-202
2
by Geoffrey D. Bennett <g at b4.vu>
* Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com>
*
* Based on the Scarlett (Gen 1) Driver for ALSA:
...
...
@@ -60,6 +60,7 @@
* - phantom power, direct monitor, speaker switching, and talkback
* controls
* - disable/enable MSD mode
* - disable/enable standalone mode
*
* <ditaa>
* /--------------\ 18chn 20chn /--------------\
...
...
@@ -195,6 +196,16 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
/* Maximum number of meters (sum of output port counts) */
#define SCARLETT2_MAX_METERS 65
/* There are three different sets of configuration parameters across
* the devices
*/
enum
{
SCARLETT2_CONFIG_SET_NO_MIXER
=
0
,
SCARLETT2_CONFIG_SET_GEN_2
=
1
,
SCARLETT2_CONFIG_SET_GEN_3
=
2
,
SCARLETT2_CONFIG_SET_COUNT
=
3
};
/* Hardware port types:
* - None (no input to mux)
* - Analogue I/O
...
...
@@ -308,10 +319,8 @@ struct scarlett2_device_info {
*/
u8
has_msd_mode
;
/* Gen 3 devices without a mixer have a different
* configuration set
*/
u8
has_mixer
;
/* which set of configuration parameters the device uses */
u8
config_set
;
/* line out hw volume is sw controlled */
u8
line_out_hw_vol
;
...
...
@@ -403,6 +412,7 @@ struct scarlett2_data {
u8
talkback_switch
;
u8
talkback_map
[
SCARLETT2_OUTPUT_MIX_MAX
];
u8
msd_switch
;
u8
standalone_switch
;
struct
snd_kcontrol
*
sync_ctl
;
struct
snd_kcontrol
*
master_vol_ctl
;
struct
snd_kcontrol
*
vol_ctls
[
SCARLETT2_ANALOGUE_MAX
];
...
...
@@ -426,7 +436,7 @@ struct scarlett2_data {
static
const
struct
scarlett2_device_info
s6i6_gen2_info
=
{
.
usb_id
=
USB_ID
(
0x1235
,
0x8203
),
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_2
,
.
level_input_count
=
2
,
.
pad_input_count
=
2
,
...
...
@@ -472,7 +482,7 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
static
const
struct
scarlett2_device_info
s18i8_gen2_info
=
{
.
usb_id
=
USB_ID
(
0x1235
,
0x8204
),
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_2
,
.
level_input_count
=
2
,
.
pad_input_count
=
4
,
...
...
@@ -521,7 +531,7 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
static
const
struct
scarlett2_device_info
s18i20_gen2_info
=
{
.
usb_id
=
USB_ID
(
0x1235
,
0x8201
),
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_2
,
.
line_out_hw_vol
=
1
,
.
line_out_descrs
=
{
...
...
@@ -576,6 +586,7 @@ static const struct scarlett2_device_info solo_gen3_info = {
.
usb_id
=
USB_ID
(
0x1235
,
0x8211
),
.
has_msd_mode
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_NO_MIXER
,
.
level_input_count
=
1
,
.
level_input_first
=
1
,
.
air_input_count
=
1
,
...
...
@@ -588,6 +599,7 @@ static const struct scarlett2_device_info s2i2_gen3_info = {
.
usb_id
=
USB_ID
(
0x1235
,
0x8210
),
.
has_msd_mode
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_NO_MIXER
,
.
level_input_count
=
2
,
.
air_input_count
=
2
,
.
phantom_count
=
1
,
...
...
@@ -599,7 +611,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
.
usb_id
=
USB_ID
(
0x1235
,
0x8212
),
.
has_msd_mode
=
1
,
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_3
,
.
level_input_count
=
2
,
.
pad_input_count
=
2
,
.
air_input_count
=
2
,
...
...
@@ -645,7 +657,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
.
usb_id
=
USB_ID
(
0x1235
,
0x8213
),
.
has_msd_mode
=
1
,
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_3
,
.
level_input_count
=
2
,
.
pad_input_count
=
2
,
.
air_input_count
=
2
,
...
...
@@ -698,7 +710,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
.
usb_id
=
USB_ID
(
0x1235
,
0x8214
),
.
has_msd_mode
=
1
,
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_3
,
.
line_out_hw_vol
=
1
,
.
has_speaker_switching
=
1
,
.
level_input_count
=
2
,
...
...
@@ -768,7 +780,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
.
usb_id
=
USB_ID
(
0x1235
,
0x8215
),
.
has_msd_mode
=
1
,
.
has_mixer
=
1
,
.
config_set
=
SCARLETT2_CONFIG_SET_GEN_3
,
.
line_out_hw_vol
=
1
,
.
has_speaker_switching
=
1
,
.
has_talkback
=
1
,
...
...
@@ -926,13 +938,14 @@ enum {
SCARLETT2_CONFIG_PAD_SWITCH
=
5
,
SCARLETT2_CONFIG_MSD_SWITCH
=
6
,
SCARLETT2_CONFIG_AIR_SWITCH
=
7
,
SCARLETT2_CONFIG_PHANTOM_SWITCH
=
8
,
SCARLETT2_CONFIG_PHANTOM_PERSISTENCE
=
9
,
SCARLETT2_CONFIG_DIRECT_MONITOR
=
10
,
SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH
=
11
,
SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE
=
12
,
SCARLETT2_CONFIG_TALKBACK_MAP
=
13
,
SCARLETT2_CONFIG_COUNT
=
14
SCARLETT2_CONFIG_STANDALONE_SWITCH
=
8
,
SCARLETT2_CONFIG_PHANTOM_SWITCH
=
9
,
SCARLETT2_CONFIG_PHANTOM_PERSISTENCE
=
10
,
SCARLETT2_CONFIG_DIRECT_MONITOR
=
11
,
SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH
=
12
,
SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE
=
13
,
SCARLETT2_CONFIG_TALKBACK_MAP
=
14
,
SCARLETT2_CONFIG_COUNT
=
15
};
/* Location, size, and activation command number for the configuration
...
...
@@ -944,13 +957,11 @@ struct scarlett2_config {
u8
activate
;
};
/* scarlett2_config_items[0] is for devices without a mixer
* scarlett2_config_items[1] is for devices with a mixer
*/
static
const
struct
scarlett2_config
scarlett2_config_items
[
2
][
SCARLETT2_CONFIG_COUNT
]
=
scarlett2_config_items
[
SCARLETT2_CONFIG_SET_COUNT
]
[
SCARLETT2_CONFIG_COUNT
]
=
/* Devices without a mixer (
Solo and 2i2 Gen 3
) */
/* Devices without a mixer (
Gen 3 Solo and 2i2
) */
{
{
[
SCARLETT2_CONFIG_MSD_SWITCH
]
=
{
.
offset
=
0x04
,
.
size
=
8
,
.
activate
=
6
},
...
...
@@ -970,7 +981,30 @@ static const struct scarlett2_config
[
SCARLETT2_CONFIG_AIR_SWITCH
]
=
{
.
offset
=
0x09
,
.
size
=
1
,
.
activate
=
8
},
/* Devices with a mixer (Gen 2 and all other Gen 3) */
/* Gen 2 devices: 6i6, 18i8, 18i20 */
},
{
[
SCARLETT2_CONFIG_DIM_MUTE
]
=
{
.
offset
=
0x31
,
.
size
=
8
,
.
activate
=
2
},
[
SCARLETT2_CONFIG_LINE_OUT_VOLUME
]
=
{
.
offset
=
0x34
,
.
size
=
16
,
.
activate
=
1
},
[
SCARLETT2_CONFIG_MUTE_SWITCH
]
=
{
.
offset
=
0x5c
,
.
size
=
8
,
.
activate
=
1
},
[
SCARLETT2_CONFIG_SW_HW_SWITCH
]
=
{
.
offset
=
0x66
,
.
size
=
8
,
.
activate
=
3
},
[
SCARLETT2_CONFIG_LEVEL_SWITCH
]
=
{
.
offset
=
0x7c
,
.
size
=
8
,
.
activate
=
7
},
[
SCARLETT2_CONFIG_PAD_SWITCH
]
=
{
.
offset
=
0x84
,
.
size
=
8
,
.
activate
=
8
},
[
SCARLETT2_CONFIG_STANDALONE_SWITCH
]
=
{
.
offset
=
0x8d
,
.
size
=
8
,
.
activate
=
6
},
/* Gen 3 devices: 4i4, 8i6, 18i8, 18i20 */
},
{
[
SCARLETT2_CONFIG_DIM_MUTE
]
=
{
.
offset
=
0x31
,
.
size
=
8
,
.
activate
=
2
},
...
...
@@ -993,6 +1027,9 @@ static const struct scarlett2_config
[
SCARLETT2_CONFIG_AIR_SWITCH
]
=
{
.
offset
=
0x8c
,
.
size
=
8
,
.
activate
=
8
},
[
SCARLETT2_CONFIG_STANDALONE_SWITCH
]
=
{
.
offset
=
0x95
,
.
size
=
8
,
.
activate
=
6
},
[
SCARLETT2_CONFIG_PHANTOM_SWITCH
]
=
{
.
offset
=
0x9c
,
.
size
=
1
,
.
activate
=
8
},
...
...
@@ -1061,9 +1098,9 @@ static int scarlett2_usb(
{
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
struct
usb_device
*
dev
=
mixer
->
chip
->
dev
;
u16
req_buf_size
=
sizeof
(
struct
scarlett2_usb_packet
)
+
req_size
;
u16
resp_buf_size
=
sizeof
(
struct
scarlett2_usb_packet
)
+
resp_size
;
struct
scarlett2_usb_packet
*
req
,
*
resp
=
NULL
;
size_t
req_buf_size
=
struct_size
(
req
,
data
,
req_size
);
size_t
resp_buf_size
=
struct_size
(
resp
,
data
,
resp_size
);
int
err
;
req
=
kmalloc
(
req_buf_size
,
GFP_KERNEL
);
...
...
@@ -1111,7 +1148,7 @@ static int scarlett2_usb(
usb_audio_err
(
mixer
->
chip
,
"Scarlett Gen 2/3 USB response result cmd %x was %d "
"expected %
d
\n
"
,
"expected %
zu
\n
"
,
cmd
,
err
,
resp_buf_size
);
err
=
-
EINVAL
;
goto
unlock
;
...
...
@@ -1175,7 +1212,7 @@ static int scarlett2_usb_get_config(
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
const
struct
scarlett2_device_info
*
info
=
private
->
info
;
const
struct
scarlett2_config
*
config_item
=
&
scarlett2_config_items
[
info
->
has_mixer
][
config_item_num
];
&
scarlett2_config_items
[
info
->
config_set
][
config_item_num
];
int
size
,
err
,
i
;
u8
*
buf_8
;
u8
value
;
...
...
@@ -1235,7 +1272,7 @@ static int scarlett2_usb_set_config(
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
const
struct
scarlett2_device_info
*
info
=
private
->
info
;
const
struct
scarlett2_config
*
config_item
=
&
scarlett2_config_items
[
info
->
has_mixer
][
config_item_num
];
&
scarlett2_config_items
[
info
->
config_set
][
config_item_num
];
struct
{
__le32
offset
;
__le32
bytes
;
...
...
@@ -1692,7 +1729,7 @@ static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer)
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
/* devices without a mixer also don't support reporting sync status */
if
(
!
private
->
info
->
has_mixer
)
if
(
private
->
info
->
config_set
==
SCARLETT2_CONFIG_SET_NO_MIXER
)
return
0
;
return
scarlett2_add_new_ctl
(
mixer
,
&
scarlett2_sync_ctl
,
...
...
@@ -3399,7 +3436,7 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer)
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
/* devices without a mixer also don't support reporting levels */
if
(
!
private
->
info
->
has_mixer
)
if
(
private
->
info
->
config_set
==
SCARLETT2_CONFIG_SET_NO_MIXER
)
return
0
;
return
scarlett2_add_new_ctl
(
mixer
,
&
scarlett2_meter_ctl
,
...
...
@@ -3474,6 +3511,69 @@ static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer)
0
,
1
,
"MSD Mode Switch"
,
NULL
);
}
/*** Standalone Control ***/
static
int
scarlett2_standalone_ctl_get
(
struct
snd_kcontrol
*
kctl
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
usb_mixer_elem_info
*
elem
=
kctl
->
private_data
;
struct
scarlett2_data
*
private
=
elem
->
head
.
mixer
->
private_data
;
ucontrol
->
value
.
integer
.
value
[
0
]
=
private
->
standalone_switch
;
return
0
;
}
static
int
scarlett2_standalone_ctl_put
(
struct
snd_kcontrol
*
kctl
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
usb_mixer_elem_info
*
elem
=
kctl
->
private_data
;
struct
usb_mixer_interface
*
mixer
=
elem
->
head
.
mixer
;
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
int
oval
,
val
,
err
=
0
;
mutex_lock
(
&
private
->
data_mutex
);
oval
=
private
->
standalone_switch
;
val
=
!!
ucontrol
->
value
.
integer
.
value
[
0
];
if
(
oval
==
val
)
goto
unlock
;
private
->
standalone_switch
=
val
;
/* Send switch change to the device */
err
=
scarlett2_usb_set_config
(
mixer
,
SCARLETT2_CONFIG_STANDALONE_SWITCH
,
0
,
val
);
if
(
err
==
0
)
err
=
1
;
unlock:
mutex_unlock
(
&
private
->
data_mutex
);
return
err
;
}
static
const
struct
snd_kcontrol_new
scarlett2_standalone_ctl
=
{
.
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
,
.
name
=
""
,
.
info
=
snd_ctl_boolean_mono_info
,
.
get
=
scarlett2_standalone_ctl_get
,
.
put
=
scarlett2_standalone_ctl_put
,
};
static
int
scarlett2_add_standalone_ctl
(
struct
usb_mixer_interface
*
mixer
)
{
struct
scarlett2_data
*
private
=
mixer
->
private_data
;
if
(
private
->
info
->
config_set
==
SCARLETT2_CONFIG_SET_NO_MIXER
)
return
0
;
/* Add standalone control */
return
scarlett2_add_new_ctl
(
mixer
,
&
scarlett2_standalone_ctl
,
0
,
1
,
"Standalone Switch"
,
NULL
);
}
/*** Cleanup/Suspend Callbacks ***/
static
void
scarlett2_private_free
(
struct
usb_mixer_interface
*
mixer
)
...
...
@@ -3632,9 +3732,15 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
return
err
;
/* the rest of the configuration is for devices with a mixer */
if
(
!
info
->
has_mixer
)
if
(
info
->
config_set
==
SCARLETT2_CONFIG_SET_NO_MIXER
)
return
0
;
err
=
scarlett2_usb_get_config
(
mixer
,
SCARLETT2_CONFIG_STANDALONE_SWITCH
,
1
,
&
private
->
standalone_switch
);
if
(
err
<
0
)
return
err
;
err
=
scarlett2_update_sync
(
mixer
);
if
(
err
<
0
)
return
err
;
...
...
@@ -3957,6 +4063,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
if
(
err
<
0
)
return
err
;
/* Create the standalone control */
err
=
scarlett2_add_standalone_ctl
(
mixer
);
if
(
err
<
0
)
return
err
;
/* Set up the interrupt polling */
err
=
scarlett2_init_notify
(
mixer
);
if
(
err
<
0
)
...
...
sound/x86/intel_hdmi_audio.c
浏览文件 @
a6d4b685
...
...
@@ -1253,18 +1253,6 @@ static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
return
len
;
}
/*
* ALSA PCM mmap callback
*/
static
int
had_pcm_mmap
(
struct
snd_pcm_substream
*
substream
,
struct
vm_area_struct
*
vma
)
{
vma
->
vm_page_prot
=
pgprot_noncached
(
vma
->
vm_page_prot
);
return
remap_pfn_range
(
vma
,
vma
->
vm_start
,
substream
->
runtime
->
dma_addr
>>
PAGE_SHIFT
,
vma
->
vm_end
-
vma
->
vm_start
,
vma
->
vm_page_prot
);
}
/*
* ALSA PCM ops
*/
...
...
@@ -1276,7 +1264,6 @@ static const struct snd_pcm_ops had_pcm_ops = {
.
trigger
=
had_pcm_trigger
,
.
sync_stop
=
had_pcm_sync_stop
,
.
pointer
=
had_pcm_pointer
,
.
mmap
=
had_pcm_mmap
,
};
/* process mode change of the running stream; called in mutex */
...
...
tools/testing/selftests/alsa/mixer-test.c
浏览文件 @
a6d4b685
...
...
@@ -3,7 +3,7 @@
// kselftest for the ALSA mixer API
//
// Original author: Mark Brown <broonie@kernel.org>
// Copyright (c) 2021 Arm Limited
// Copyright (c) 2021
-2
Arm Limited
// This test will iterate over all cards detected in the system, exercising
// every mixer control it can find. This may conflict with other system
...
...
@@ -13,6 +13,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
...
...
@@ -26,11 +27,12 @@
#include "../kselftest.h"
#define TESTS_PER_CONTROL
3
#define TESTS_PER_CONTROL
6
struct
card_data
{
snd_ctl_t
*
handle
;
int
card
;
struct
pollfd
pollfd
;
int
num_ctls
;
snd_ctl_elem_list_t
*
ctls
;
struct
card_data
*
next
;
...
...
@@ -42,6 +44,8 @@ struct ctl_data {
snd_ctl_elem_info_t
*
info
;
snd_ctl_elem_value_t
*
def_val
;
int
elem
;
int
event_missing
;
int
event_spurious
;
struct
card_data
*
card
;
struct
ctl_data
*
next
;
};
...
...
@@ -67,7 +71,8 @@ struct ctl_data *ctl_list = NULL;
#endif
#ifndef LIB_HAS_LOAD_STRING
int
snd_config_load_string
(
snd_config_t
**
config
,
const
char
*
s
,
size_t
size
)
static
int
snd_config_load_string
(
snd_config_t
**
config
,
const
char
*
s
,
size_t
size
)
{
snd_input_t
*
input
;
snd_config_t
*
dst
;
...
...
@@ -95,7 +100,7 @@ int snd_config_load_string(snd_config_t **config, const char *s, size_t size)
}
#endif
void
find_controls
(
void
)
static
void
find_controls
(
void
)
{
char
name
[
32
];
int
card
,
ctl
,
err
;
...
...
@@ -148,6 +153,7 @@ void find_controls(void)
if
(
!
ctl_data
)
ksft_exit_fail_msg
(
"Out of memory
\n
"
);
memset
(
ctl_data
,
0
,
sizeof
(
*
ctl_data
));
ctl_data
->
card
=
card_data
;
ctl_data
->
elem
=
ctl
;
ctl_data
->
name
=
snd_ctl_elem_list_get_name
(
card_data
->
ctls
,
...
...
@@ -183,6 +189,26 @@ void find_controls(void)
ctl_list
=
ctl_data
;
}
/* Set up for events */
err
=
snd_ctl_subscribe_events
(
card_data
->
handle
,
true
);
if
(
err
<
0
)
{
ksft_exit_fail_msg
(
"snd_ctl_subscribe_events() failed for card %d: %d
\n
"
,
card
,
err
);
}
err
=
snd_ctl_poll_descriptors_count
(
card_data
->
handle
);
if
(
err
!=
1
)
{
ksft_exit_fail_msg
(
"Unexpected descriptor count %d for card %d
\n
"
,
err
,
card
);
}
err
=
snd_ctl_poll_descriptors
(
card_data
->
handle
,
&
card_data
->
pollfd
,
1
);
if
(
err
!=
1
)
{
ksft_exit_fail_msg
(
"snd_ctl_poll_descriptors() failed for %d
\n
"
,
card
,
err
);
}
next_card:
if
(
snd_card_next
(
&
card
)
<
0
)
{
ksft_print_msg
(
"snd_card_next"
);
...
...
@@ -193,8 +219,82 @@ void find_controls(void)
snd_config_delete
(
config
);
}
bool
ctl_value_index_valid
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
val
,
int
index
)
/*
* Block for up to timeout ms for an event, returns a negative value
* on error, 0 for no event and 1 for an event.
*/
static
int
wait_for_event
(
struct
ctl_data
*
ctl
,
int
timeout
)
{
unsigned
short
revents
;
snd_ctl_event_t
*
event
;
int
count
,
err
;
unsigned
int
mask
=
0
;
unsigned
int
ev_id
;
snd_ctl_event_alloca
(
&
event
);
do
{
err
=
poll
(
&
(
ctl
->
card
->
pollfd
),
1
,
timeout
);
if
(
err
<
0
)
{
ksft_print_msg
(
"poll() failed for %s: %s (%d)
\n
"
,
ctl
->
name
,
strerror
(
errno
),
errno
);
return
-
1
;
}
/* Timeout */
if
(
err
==
0
)
return
0
;
err
=
snd_ctl_poll_descriptors_revents
(
ctl
->
card
->
handle
,
&
(
ctl
->
card
->
pollfd
),
1
,
&
revents
);
if
(
err
<
0
)
{
ksft_print_msg
(
"snd_ctl_poll_descriptors_revents() failed for %s: %d
\n
"
,
ctl
->
name
,
err
);
return
err
;
}
if
(
revents
&
POLLERR
)
{
ksft_print_msg
(
"snd_ctl_poll_descriptors_revents() reported POLLERR for %s
\n
"
,
ctl
->
name
);
return
-
1
;
}
/* No read events */
if
(
!
(
revents
&
POLLIN
))
{
ksft_print_msg
(
"No POLLIN
\n
"
);
continue
;
}
err
=
snd_ctl_read
(
ctl
->
card
->
handle
,
event
);
if
(
err
<
0
)
{
ksft_print_msg
(
"snd_ctl_read() failed for %s: %d
\n
"
,
ctl
->
name
,
err
);
return
err
;
}
if
(
snd_ctl_event_get_type
(
event
)
!=
SND_CTL_EVENT_ELEM
)
continue
;
/* The ID returned from the event is 1 less than numid */
mask
=
snd_ctl_event_elem_get_mask
(
event
);
ev_id
=
snd_ctl_event_elem_get_numid
(
event
);
if
(
ev_id
!=
snd_ctl_elem_info_get_numid
(
ctl
->
info
))
{
ksft_print_msg
(
"Event for unexpected ctl %s
\n
"
,
snd_ctl_event_elem_get_name
(
event
));
continue
;
}
if
((
mask
&
SND_CTL_EVENT_MASK_REMOVE
)
==
SND_CTL_EVENT_MASK_REMOVE
)
{
ksft_print_msg
(
"Removal event for %s
\n
"
,
ctl
->
name
);
return
-
1
;
}
}
while
((
mask
&
SND_CTL_EVENT_MASK_VALUE
)
!=
SND_CTL_EVENT_MASK_VALUE
);
return
1
;
}
static
bool
ctl_value_index_valid
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
val
,
int
index
)
{
long
int_val
;
long
long
int64_val
;
...
...
@@ -305,7 +405,7 @@ bool ctl_value_index_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val,
* Check that the provided value meets the constraints for the
* provided control.
*/
bool
ctl_value_valid
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
val
)
static
bool
ctl_value_valid
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
val
)
{
int
i
;
bool
valid
=
true
;
...
...
@@ -321,7 +421,7 @@ bool ctl_value_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val)
* Check that we can read the default value and it is valid. Write
* tests use the read value to restore the default.
*/
void
test_ctl_get_value
(
struct
ctl_data
*
ctl
)
static
void
test_ctl_get_value
(
struct
ctl_data
*
ctl
)
{
int
err
;
...
...
@@ -356,9 +456,9 @@ void test_ctl_get_value(struct ctl_data *ctl)
ctl
->
card
->
card
,
ctl
->
elem
);
}
bool
show_mismatch
(
struct
ctl_data
*
ctl
,
int
index
,
snd_ctl_elem_value_t
*
read_val
,
snd_ctl_elem_value_t
*
expected_val
)
static
bool
show_mismatch
(
struct
ctl_data
*
ctl
,
int
index
,
snd_ctl_elem_value_t
*
read_val
,
snd_ctl_elem_value_t
*
expected_val
)
{
long
long
expected_int
,
read_int
;
...
...
@@ -421,13 +521,14 @@ bool show_mismatch(struct ctl_data *ctl, int index,
* the write to fail, for verifying that invalid writes don't corrupt
* anything.
*/
int
write_and_verify
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
write_val
,
snd_ctl_elem_value_t
*
expected_val
)
static
int
write_and_verify
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
write_val
,
snd_ctl_elem_value_t
*
expected_val
)
{
int
err
,
i
;
bool
error_expected
,
mismatch_shown
;
snd_ctl_elem_value_t
*
read_val
,
*
w_val
;
snd_ctl_elem_value_t
*
initial_val
,
*
read_val
,
*
w_val
;
snd_ctl_elem_value_alloca
(
&
initial_val
);
snd_ctl_elem_value_alloca
(
&
read_val
);
snd_ctl_elem_value_alloca
(
&
w_val
);
...
...
@@ -445,6 +546,18 @@ int write_and_verify(struct ctl_data *ctl,
snd_ctl_elem_value_copy
(
expected_val
,
write_val
);
}
/* Store the value before we write */
if
(
snd_ctl_elem_info_is_readable
(
ctl
->
info
))
{
snd_ctl_elem_value_set_id
(
initial_val
,
ctl
->
id
);
err
=
snd_ctl_elem_read
(
ctl
->
card
->
handle
,
initial_val
);
if
(
err
<
0
)
{
ksft_print_msg
(
"snd_ctl_elem_read() failed: %s
\n
"
,
snd_strerror
(
err
));
return
err
;
}
}
/*
* Do the write, if we have an expected value ignore the error
* and carry on to validate the expected value.
...
...
@@ -469,6 +582,30 @@ int write_and_verify(struct ctl_data *ctl,
return
err
;
}
/*
* Check for an event if the value changed, or confirm that
* there was none if it didn't. We rely on the kernel
* generating the notification before it returns from the
* write, this is currently true, should that ever change this
* will most likely break and need updating.
*/
if
(
!
snd_ctl_elem_info_is_volatile
(
ctl
->
info
))
{
err
=
wait_for_event
(
ctl
,
0
);
if
(
snd_ctl_elem_value_compare
(
initial_val
,
read_val
))
{
if
(
err
<
1
)
{
ksft_print_msg
(
"No event generated for %s
\n
"
,
ctl
->
name
);
ctl
->
event_missing
++
;
}
}
else
{
if
(
err
!=
0
)
{
ksft_print_msg
(
"Spurious event generated for %s
\n
"
,
ctl
->
name
);
ctl
->
event_spurious
++
;
}
}
}
/*
* Use the libray to compare values, if there's a mismatch
* carry on and try to provide a more useful diagnostic than
...
...
@@ -493,7 +630,7 @@ int write_and_verify(struct ctl_data *ctl,
* Make sure we can write the default value back to the control, this
* should validate that at least some write works.
*/
void
test_ctl_write_default
(
struct
ctl_data
*
ctl
)
static
void
test_ctl_write_default
(
struct
ctl_data
*
ctl
)
{
int
err
;
...
...
@@ -526,7 +663,7 @@ void test_ctl_write_default(struct ctl_data *ctl)
ctl
->
card
->
card
,
ctl
->
elem
);
}
bool
test_ctl_write_valid_boolean
(
struct
ctl_data
*
ctl
)
static
bool
test_ctl_write_valid_boolean
(
struct
ctl_data
*
ctl
)
{
int
err
,
i
,
j
;
bool
fail
=
false
;
...
...
@@ -547,7 +684,7 @@ bool test_ctl_write_valid_boolean(struct ctl_data *ctl)
return
!
fail
;
}
bool
test_ctl_write_valid_integer
(
struct
ctl_data
*
ctl
)
static
bool
test_ctl_write_valid_integer
(
struct
ctl_data
*
ctl
)
{
int
err
;
int
i
;
...
...
@@ -577,7 +714,7 @@ bool test_ctl_write_valid_integer(struct ctl_data *ctl)
return
!
fail
;
}
bool
test_ctl_write_valid_integer64
(
struct
ctl_data
*
ctl
)
static
bool
test_ctl_write_valid_integer64
(
struct
ctl_data
*
ctl
)
{
int
err
,
i
;
long
long
j
,
step
;
...
...
@@ -605,7 +742,7 @@ bool test_ctl_write_valid_integer64(struct ctl_data *ctl)
return
!
fail
;
}
bool
test_ctl_write_valid_enumerated
(
struct
ctl_data
*
ctl
)
static
bool
test_ctl_write_valid_enumerated
(
struct
ctl_data
*
ctl
)
{
int
err
,
i
,
j
;
bool
fail
=
false
;
...
...
@@ -626,7 +763,7 @@ bool test_ctl_write_valid_enumerated(struct ctl_data *ctl)
return
!
fail
;
}
void
test_ctl_write_valid
(
struct
ctl_data
*
ctl
)
static
void
test_ctl_write_valid
(
struct
ctl_data
*
ctl
)
{
bool
pass
;
int
err
;
...
...
@@ -679,6 +816,236 @@ void test_ctl_write_valid(struct ctl_data *ctl)
ctl
->
card
->
card
,
ctl
->
elem
);
}
static
bool
test_ctl_write_invalid_value
(
struct
ctl_data
*
ctl
,
snd_ctl_elem_value_t
*
val
)
{
int
err
;
long
val_read
;
/* Ideally this will fail... */
err
=
snd_ctl_elem_write
(
ctl
->
card
->
handle
,
val
);
if
(
err
<
0
)
return
false
;
/* ...but some devices will clamp to an in range value */
err
=
snd_ctl_elem_read
(
ctl
->
card
->
handle
,
val
);
if
(
err
<
0
)
{
ksft_print_msg
(
"%s failed to read: %s
\n
"
,
ctl
->
name
,
snd_strerror
(
err
));
return
true
;
}
return
!
ctl_value_valid
(
ctl
,
val
);
}
static
bool
test_ctl_write_invalid_boolean
(
struct
ctl_data
*
ctl
)
{
int
err
,
i
;
long
val_read
;
bool
fail
=
false
;
snd_ctl_elem_value_t
*
val
;
snd_ctl_elem_value_alloca
(
&
val
);
for
(
i
=
0
;
i
<
snd_ctl_elem_info_get_count
(
ctl
->
info
);
i
++
)
{
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_boolean
(
val
,
i
,
2
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
}
return
!
fail
;
}
static
bool
test_ctl_write_invalid_integer
(
struct
ctl_data
*
ctl
)
{
int
i
;
bool
fail
=
false
;
snd_ctl_elem_value_t
*
val
;
snd_ctl_elem_value_alloca
(
&
val
);
for
(
i
=
0
;
i
<
snd_ctl_elem_info_get_count
(
ctl
->
info
);
i
++
)
{
if
(
snd_ctl_elem_info_get_min
(
ctl
->
info
)
!=
LONG_MIN
)
{
/* Just under range */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer
(
val
,
i
,
snd_ctl_elem_info_get_min
(
ctl
->
info
)
-
1
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
/* Minimum representable value */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer
(
val
,
i
,
LONG_MIN
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
}
if
(
snd_ctl_elem_info_get_max
(
ctl
->
info
)
!=
LONG_MAX
)
{
/* Just over range */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer
(
val
,
i
,
snd_ctl_elem_info_get_max
(
ctl
->
info
)
+
1
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
/* Maximum representable value */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer
(
val
,
i
,
LONG_MAX
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
}
}
return
!
fail
;
}
static
bool
test_ctl_write_invalid_integer64
(
struct
ctl_data
*
ctl
)
{
int
i
;
bool
fail
=
false
;
snd_ctl_elem_value_t
*
val
;
snd_ctl_elem_value_alloca
(
&
val
);
for
(
i
=
0
;
i
<
snd_ctl_elem_info_get_count
(
ctl
->
info
);
i
++
)
{
if
(
snd_ctl_elem_info_get_min64
(
ctl
->
info
)
!=
LLONG_MIN
)
{
/* Just under range */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer64
(
val
,
i
,
snd_ctl_elem_info_get_min64
(
ctl
->
info
)
-
1
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
/* Minimum representable value */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer64
(
val
,
i
,
LLONG_MIN
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
}
if
(
snd_ctl_elem_info_get_max64
(
ctl
->
info
)
!=
LLONG_MAX
)
{
/* Just over range */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer64
(
val
,
i
,
snd_ctl_elem_info_get_max64
(
ctl
->
info
)
+
1
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
/* Maximum representable value */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_integer64
(
val
,
i
,
LLONG_MAX
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
}
}
return
!
fail
;
}
static
bool
test_ctl_write_invalid_enumerated
(
struct
ctl_data
*
ctl
)
{
int
err
,
i
;
unsigned
int
val_read
;
bool
fail
=
false
;
snd_ctl_elem_value_t
*
val
;
snd_ctl_elem_value_alloca
(
&
val
);
snd_ctl_elem_value_set_id
(
val
,
ctl
->
id
);
for
(
i
=
0
;
i
<
snd_ctl_elem_info_get_count
(
ctl
->
info
);
i
++
)
{
/* One beyond maximum */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_enumerated
(
val
,
i
,
snd_ctl_elem_info_get_items
(
ctl
->
info
));
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
/* Maximum representable value */
snd_ctl_elem_value_copy
(
val
,
ctl
->
def_val
);
snd_ctl_elem_value_set_enumerated
(
val
,
i
,
UINT_MAX
);
if
(
test_ctl_write_invalid_value
(
ctl
,
val
))
fail
=
true
;
}
return
!
fail
;
}
static
void
test_ctl_write_invalid
(
struct
ctl_data
*
ctl
)
{
bool
pass
;
int
err
;
/* If the control is turned off let's be polite */
if
(
snd_ctl_elem_info_is_inactive
(
ctl
->
info
))
{
ksft_print_msg
(
"%s is inactive
\n
"
,
ctl
->
name
);
ksft_test_result_skip
(
"write_invalid.%d.%d
\n
"
,
ctl
->
card
->
card
,
ctl
->
elem
);
return
;
}
if
(
!
snd_ctl_elem_info_is_writable
(
ctl
->
info
))
{
ksft_print_msg
(
"%s is not writeable
\n
"
,
ctl
->
name
);
ksft_test_result_skip
(
"write_invalid.%d.%d
\n
"
,
ctl
->
card
->
card
,
ctl
->
elem
);
return
;
}
switch
(
snd_ctl_elem_info_get_type
(
ctl
->
info
))
{
case
SND_CTL_ELEM_TYPE_BOOLEAN
:
pass
=
test_ctl_write_invalid_boolean
(
ctl
);
break
;
case
SND_CTL_ELEM_TYPE_INTEGER
:
pass
=
test_ctl_write_invalid_integer
(
ctl
);
break
;
case
SND_CTL_ELEM_TYPE_INTEGER64
:
pass
=
test_ctl_write_invalid_integer64
(
ctl
);
break
;
case
SND_CTL_ELEM_TYPE_ENUMERATED
:
pass
=
test_ctl_write_invalid_enumerated
(
ctl
);
break
;
default:
/* No tests for this yet */
ksft_test_result_skip
(
"write_invalid.%d.%d
\n
"
,
ctl
->
card
->
card
,
ctl
->
elem
);
return
;
}
/* Restore the default value to minimise disruption */
err
=
write_and_verify
(
ctl
,
ctl
->
def_val
,
NULL
);
if
(
err
<
0
)
pass
=
false
;
ksft_test_result
(
pass
,
"write_invalid.%d.%d
\n
"
,
ctl
->
card
->
card
,
ctl
->
elem
);
}
static
void
test_ctl_event_missing
(
struct
ctl_data
*
ctl
)
{
ksft_test_result
(
!
ctl
->
event_missing
,
"event_missing.%d.%d
\n
"
,
ctl
->
card
->
card
,
ctl
->
elem
);
}
static
void
test_ctl_event_spurious
(
struct
ctl_data
*
ctl
)
{
ksft_test_result
(
!
ctl
->
event_spurious
,
"event_spurious.%d.%d
\n
"
,
ctl
->
card
->
card
,
ctl
->
elem
);
}
int
main
(
void
)
{
struct
ctl_data
*
ctl
;
...
...
@@ -697,6 +1064,9 @@ int main(void)
test_ctl_get_value
(
ctl
);
test_ctl_write_default
(
ctl
);
test_ctl_write_valid
(
ctl
);
test_ctl_write_invalid
(
ctl
);
test_ctl_event_missing
(
ctl
);
test_ctl_event_spurious
(
ctl
);
}
ksft_exit_pass
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录