Merge branch 'for-next' into for-linus

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai
2026-04-13 07:18:36 +02:00
88 changed files with 2333 additions and 687 deletions
@@ -2376,6 +2376,13 @@ quirk_flags
Skip the probe-time interface setup (usb_set_interface,
init_pitch, init_sample_rate); redundant with
snd_usb_endpoint_prepare() at stream-open time
* bit 27: ``mixer_playback_linear_vol``
Set linear volume mapping for devices where the playback volume
control value is mapped to voltage (instead of dB) level linearly.
In short: ``x(raw) = (raw - raw_min) / (raw_max - raw_min)``;
``V(x) = k * x``; ``dB(x) = 20 * log10(x)``. Overrides bit 24
* bit 28: ``mixer_capture_linear_vol``
Similar to bit 27 but for capture streams. Overrides bit 25
This module supports multiple devices, autoprobe and hotplugging.
+3
View File
@@ -133,6 +133,9 @@ struct snd_card {
#ifdef CONFIG_SND_DEBUG
struct dentry *debugfs_root; /* debugfs root for card */
#endif
#ifdef CONFIG_SND_CTL_DEBUG
struct snd_ctl_elem_value *value_buf; /* buffer for kctl->put() verification */
#endif
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
+8
View File
@@ -536,6 +536,7 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
struct snd_gf1_dma_block * block,
int atomic,
int synth);
void snd_gf1_dma_suspend(struct snd_gus_card *gus);
/* gus_volume.c */
@@ -552,6 +553,8 @@ struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, i
void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice);
int snd_gf1_start(struct snd_gus_card * gus);
int snd_gf1_stop(struct snd_gus_card * gus);
int snd_gf1_suspend(struct snd_gus_card *gus);
int snd_gf1_resume(struct snd_gus_card *gus);
/* gus_mixer.c */
@@ -572,6 +575,8 @@ int snd_gus_create(struct snd_card *card,
int effect,
struct snd_gus_card ** rgus);
int snd_gus_initialize(struct snd_gus_card * gus);
int snd_gus_suspend(struct snd_gus_card *gus);
int snd_gus_resume(struct snd_gus_card *gus);
/* gus_irq.c */
@@ -583,6 +588,8 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus);
/* gus_uart.c */
int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device);
void snd_gf1_uart_suspend(struct snd_gus_card *gus);
void snd_gf1_uart_resume(struct snd_gus_card *gus);
/* gus_dram.c */
int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr,
@@ -593,5 +600,6 @@ int snd_gus_dram_read(struct snd_gus_card *gus, char __user *ptr,
/* gus_timer.c */
void snd_gf1_timers_init(struct snd_gus_card *gus);
void snd_gf1_timers_done(struct snd_gus_card *gus);
void snd_gf1_timers_resume(struct snd_gus_card *gus);
#endif /* __SOUND_GUS_H */
+15
View File
@@ -336,6 +336,17 @@ snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
return snd_hdac_codec_write(&codec->core, nid, flags, verb, parm);
}
/* sync after write */
static inline int
snd_hda_codec_write_sync(struct hda_codec *codec, hda_nid_t nid, int flags,
unsigned int verb, unsigned int parm)
{
/* use snd_hda_codec_read() for writing;
* the returned value is usually discarded
*/
return snd_hdac_codec_read(&codec->core, nid, flags, verb, parm);
}
#define snd_hda_param_read(codec, nid, param) \
snd_hdac_read_parm(&(codec)->core, nid, param)
#define snd_hda_get_sub_nodes(codec, nid, start_nid) \
@@ -470,6 +481,10 @@ void snd_hda_unlock_devices(struct hda_bus *bus);
void snd_hda_bus_reset(struct hda_bus *bus);
void snd_hda_bus_reset_codecs(struct hda_bus *bus);
void snd_hda_codec_set_gpio(struct hda_codec *codec, unsigned int mask,
unsigned int dir, unsigned int data,
unsigned int delay);
int snd_hda_codec_set_name(struct hda_codec *codec, const char *name);
/*
+11 -1
View File
@@ -56,7 +56,12 @@ enum {
#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
/* f10-f1a: GPIO */
/* f10-f1a: GPI/GPO/GPIO */
#define AC_VERB_GET_GPI_DATA 0x0f10
#define AC_VERB_GET_GPI_WAKE_MASK 0x0f11
#define AC_VERB_GET_GPI_UNSOLICITED_RSP_MASK 0x0f12
#define AC_VERB_GET_GPI_STICKY_MASK 0x0f13
#define AC_VERB_GET_GPO_DATA 0x0f14
#define AC_VERB_GET_GPIO_DATA 0x0f15
#define AC_VERB_GET_GPIO_MASK 0x0f16
#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
@@ -99,6 +104,11 @@ enum {
#define AC_VERB_SET_DIGI_CONVERT_2 0x70e
#define AC_VERB_SET_DIGI_CONVERT_3 0x73e
#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f
#define AC_VERB_SET_GPI_DATA 0x710
#define AC_VERB_SET_GPI_WAKE_MASK 0x711
#define AC_VERB_SET_SPI_UNSOLICITED_RSP_MASK 0x712
#define AC_VERB_SET_GPI_STICKY_MASK 0x713
#define AC_VERB_SET_GPO_DATA 0x714
#define AC_VERB_SET_GPIO_DATA 0x715
#define AC_VERB_SET_GPIO_MASK 0x716
#define AC_VERB_SET_GPIO_DIRECTION 0x717
+4
View File
@@ -729,6 +729,10 @@ static inline void __snd_pcm_set_state(struct snd_pcm_runtime *runtime,
runtime->status->state = state; /* copy for mmap */
}
void snd_pcm_set_state(struct snd_pcm_substream *substream,
snd_pcm_state_t state);
snd_pcm_state_t snd_pcm_get_state(struct snd_pcm_substream *substream);
/**
* bytes_to_samples - Unit conversion of the size from bytes to samples
* @runtime: PCM runtime instance
+1
View File
@@ -12,5 +12,6 @@
int snd_tea6330t_detect(struct snd_i2c_bus *bus, int equalizer);
int snd_tea6330t_update_mixer(struct snd_card *card, struct snd_i2c_bus *bus,
int equalizer, int fader);
int snd_tea6330t_restore_mixer(struct snd_i2c_bus *bus);
#endif /* __SOUND_TEA6330T_H */
+1
View File
@@ -102,6 +102,7 @@ struct snd_timer_instance {
unsigned int slave_id;
struct list_head open_list;
struct list_head active_list;
struct list_head master_list;
struct list_head ack_list;
struct list_head slave_list_head;
struct list_head slave_active_head;
+1 -1
View File
@@ -48,7 +48,7 @@ struct aoa_codec {
u32 connected;
/* data the fabric can associate with this structure */
void *fabric_data;
const void *fabric_data;
/* private! */
struct list_head list;
+36 -5
View File
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <sound/asoundef.h>
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
@@ -514,8 +515,36 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
return 1;
}
static int onyx_set_spdif_pcm_rate(struct onyx *onyx, unsigned int rate)
{
u8 dig_info3, fs;
switch (rate) {
case 32000:
fs = IEC958_AES3_CON_FS_32000;
break;
case 44100:
fs = IEC958_AES3_CON_FS_44100;
break;
case 48000:
fs = IEC958_AES3_CON_FS_48000;
break;
default:
return -EINVAL;
}
if (onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &dig_info3))
return -EBUSY;
dig_info3 = (dig_info3 & ~IEC958_AES3_CON_FS) | fs;
if (onyx_write_register(onyx, ONYX_REG_DIG_INFO3, dig_info3))
return -EBUSY;
return 0;
}
static const struct snd_kcontrol_new onyx_spdif_ctrl = {
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = onyx_spdif_info,
@@ -695,9 +724,9 @@ static int onyx_prepare(struct codec_info_item *cii,
case 32000:
case 44100:
case 48000:
/* these rates are ok for all outputs */
/* FIXME: program spdif channel control bits here so that
* userspace doesn't have to if it only plays pcm! */
if (onyx->codec.connected & 2)
return onyx_set_spdif_pcm_rate(onyx,
substream->runtime->rate);
return 0;
default:
/* got some rate that the digital output can't do,
@@ -980,10 +1009,12 @@ static int onyx_i2c_probe(struct i2c_client *client)
onyx->codec.node = of_node_get(node);
if (aoa_codec_register(&onyx->codec)) {
goto fail;
goto fail_put;
}
printk(KERN_DEBUG PFX "created and attached onyx instance\n");
return 0;
fail_put:
of_node_put(onyx->codec.node);
fail:
kfree(onyx);
return -ENODEV;
+1
View File
@@ -872,6 +872,7 @@ static int tas_i2c_probe(struct i2c_client *client)
return 0;
fail:
mutex_destroy(&tas->mtx);
of_node_put(tas->codec.node);
kfree(tas);
return -EINVAL;
}
+14 -14
View File
@@ -55,7 +55,7 @@ struct codec_connection {
struct codec_connect_info {
char *name;
struct codec_connection *connections;
const struct codec_connection *connections;
};
#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
@@ -116,7 +116,7 @@ MODULE_ALIAS("aoa-device-id-35");
MODULE_ALIAS("aoa-device-id-44");
/* onyx with all but microphone connected */
static struct codec_connection onyx_connections_nomic[] = {
static const struct codec_connection onyx_connections_nomic[] = {
{
.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
.codec_bit = 0,
@@ -133,7 +133,7 @@ static struct codec_connection onyx_connections_nomic[] = {
};
/* onyx on machines without headphone */
static struct codec_connection onyx_connections_noheadphones[] = {
static const struct codec_connection onyx_connections_noheadphones[] = {
{
.connected = CC_SPEAKERS | CC_LINEOUT |
CC_LINEOUT_LABELLED_HEADPHONE,
@@ -157,7 +157,7 @@ static struct codec_connection onyx_connections_noheadphones[] = {
};
/* onyx on machines with real line-out */
static struct codec_connection onyx_connections_reallineout[] = {
static const struct codec_connection onyx_connections_reallineout[] = {
{
.connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
.codec_bit = 0,
@@ -174,7 +174,7 @@ static struct codec_connection onyx_connections_reallineout[] = {
};
/* tas on machines without line out */
static struct codec_connection tas_connections_nolineout[] = {
static const struct codec_connection tas_connections_nolineout[] = {
{
.connected = CC_SPEAKERS | CC_HEADPHONE,
.codec_bit = 0,
@@ -191,7 +191,7 @@ static struct codec_connection tas_connections_nolineout[] = {
};
/* tas on machines with neither line out nor line in */
static struct codec_connection tas_connections_noline[] = {
static const struct codec_connection tas_connections_noline[] = {
{
.connected = CC_SPEAKERS | CC_HEADPHONE,
.codec_bit = 0,
@@ -204,7 +204,7 @@ static struct codec_connection tas_connections_noline[] = {
};
/* tas on machines without microphone */
static struct codec_connection tas_connections_nomic[] = {
static const struct codec_connection tas_connections_nomic[] = {
{
.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
.codec_bit = 0,
@@ -217,7 +217,7 @@ static struct codec_connection tas_connections_nomic[] = {
};
/* tas on machines with everything connected */
static struct codec_connection tas_connections_all[] = {
static const struct codec_connection tas_connections_all[] = {
{
.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
.codec_bit = 0,
@@ -233,7 +233,7 @@ static struct codec_connection tas_connections_all[] = {
{} /* terminate array by .connected == 0 */
};
static struct codec_connection toonie_connections[] = {
static const struct codec_connection toonie_connections[] = {
{
.connected = CC_SPEAKERS | CC_HEADPHONE,
.codec_bit = 0,
@@ -241,7 +241,7 @@ static struct codec_connection toonie_connections[] = {
{} /* terminate array by .connected == 0 */
};
static struct codec_connection topaz_input[] = {
static const struct codec_connection topaz_input[] = {
{
.connected = CC_DIGITALIN,
.codec_bit = 0,
@@ -249,7 +249,7 @@ static struct codec_connection topaz_input[] = {
{} /* terminate array by .connected == 0 */
};
static struct codec_connection topaz_output[] = {
static const struct codec_connection topaz_output[] = {
{
.connected = CC_DIGITALOUT,
.codec_bit = 1,
@@ -257,7 +257,7 @@ static struct codec_connection topaz_output[] = {
{} /* terminate array by .connected == 0 */
};
static struct codec_connection topaz_inout[] = {
static const struct codec_connection topaz_inout[] = {
{
.connected = CC_DIGITALIN,
.codec_bit = 0,
@@ -772,7 +772,7 @@ static int check_codec(struct aoa_codec *codec,
{
const u32 *ref;
char propname[32];
struct codec_connection *cc;
const struct codec_connection *cc;
/* if the codec has a 'codec' node, we require a reference */
if (of_node_name_eq(codec->node, "codec")) {
@@ -895,7 +895,7 @@ static void layout_notify(void *data)
static void layout_attached_codec(struct aoa_codec *codec)
{
struct codec_connection *cc;
const struct codec_connection *cc;
struct snd_kcontrol *ctl;
int headphones, lineout;
struct layout_dev *ldev = layout_device;
+9 -3
View File
@@ -84,6 +84,7 @@ static void i2sbus_release_dev(struct device *dev)
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
free_irq(i2sdev->interrupts[i], i2sdev);
i2sbus_control_remove_dev(i2sdev->control, i2sdev);
of_node_put(i2sdev->sound.ofdev.dev.of_node);
mutex_destroy(&i2sdev->lock);
kfree(i2sdev);
}
@@ -147,7 +148,6 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
}
/* Returns 1 if added, 0 for otherwise; don't return a negative value! */
/* FIXME: look at device node refcounting */
static int i2sbus_add_dev(struct macio_dev *macio,
struct i2sbus_control *control,
struct device_node *np)
@@ -178,8 +178,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
i = 0;
for_each_child_of_node(np, child) {
if (of_node_name_eq(child, "sound")) {
of_node_put(sound);
i++;
sound = child;
sound = of_node_get(child);
}
}
if (i == 1) {
@@ -205,6 +206,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
}
}
}
of_node_put(sound);
/* for the time being, until we can handle non-layout-id
* things in some fabric, refuse to attach if there is no
* layout-id property or we haven't been forced to attach.
@@ -219,7 +221,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
mutex_init(&dev->lock);
spin_lock_init(&dev->low_lock);
dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask;
dev->sound.ofdev.dev.of_node = np;
dev->sound.ofdev.dev.of_node = of_node_get(np);
dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask;
dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
dev->sound.ofdev.dev.release = i2sbus_release_dev;
@@ -327,6 +329,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
for (i=0;i<3;i++)
release_and_free_resource(dev->allocated_resource[i]);
mutex_destroy(&dev->lock);
of_node_put(dev->sound.ofdev.dev.of_node);
kfree(dev);
return 0;
}
@@ -405,6 +408,9 @@ static int i2sbus_resume(struct macio_dev* dev)
int err, ret = 0;
list_for_each_entry(i2sdev, &control->list, item) {
if (list_empty(&i2sdev->sound.codec_list))
continue;
/* reset i2s bus format etc. */
i2sbus_pcm_prepare_both(i2sdev);
+49 -22
View File
@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
* currently in use (if any). */
hw->rate_min = 5512;
hw->rate_max = 192000;
/* if the other stream is active, then we can only
* support what it is currently using.
* FIXME: I lied. This comment is wrong. We can support
* anything that works with the same serial format, ie.
* when recording 24 bit sound we can well play 16 bit
* sound at the same time iff using the same transfer mode.
/* If the other stream is already prepared, keep this stream
* on the same duplex format and rate.
*
* i2sbus_pcm_prepare() still programs one shared transport
* configuration for both directions, so mixed duplex formats
* are not supported here.
*/
if (other->active) {
/* FIXME: is this guaranteed by the alsa api? */
hw->formats &= pcm_format_to_bits(i2sdev->format);
/* see above, restrict rates to the one we already have */
/* Restrict rates to the one already in use. */
hw->rate_min = i2sdev->rate;
hw->rate_max = i2sdev->rate;
}
@@ -283,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
}
#endif
static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
{
struct pcm_info *pi;
guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, NULL);
pi->active = 0;
}
static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, int in)
{
i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
return 0;
}
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
@@ -291,14 +307,27 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
get_pcm_info(i2sdev, in, &pi, NULL);
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
i2sbus_pcm_clear_active(i2sdev, in);
return 0;
}
static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return i2sbus_hw_params(substream, params, 0);
}
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 0);
}
static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return i2sbus_hw_params(substream, params, 1);
}
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 1);
@@ -335,7 +364,6 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
return -EINVAL;
runtime = pi->substream->runtime;
pi->active = 1;
if (other->active &&
((i2sdev->format != runtime->format)
|| (i2sdev->rate != runtime->rate)))
@@ -383,6 +411,9 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* set stop command */
command->command = cpu_to_le16(DBDMA_STOP);
cii = list_first_entry(&i2sdev->sound.codec_list,
struct codec_info_item, list);
/* ok, let's set the serial format and stuff */
switch (runtime->format) {
/* 16 bit formats */
@@ -390,13 +421,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
case SNDRV_PCM_FORMAT_U16_BE:
/* FIXME: if we add different bus factors we need to
* do more here!! */
bi.bus_factor = 0;
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
bi.bus_factor = cii->codec->bus_factor;
break;
}
if (!bi.bus_factor)
return -ENODEV;
bi.bus_factor = cii->codec->bus_factor;
input_16bit = 1;
break;
case SNDRV_PCM_FORMAT_S32_BE:
@@ -410,10 +435,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
return -EINVAL;
}
/* we assume all sysclocks are the same! */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
bi.sysclock_factor = cii->codec->sysclock_factor;
break;
}
bi.sysclock_factor = cii->codec->sysclock_factor;
if (clock_and_divisors(bi.sysclock_factor,
bi.bus_factor,
@@ -450,9 +472,11 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* early exit if already programmed correctly */
/* not locking these is fine since we touch them only in this function */
if (in_le32(&i2sdev->intfregs->serial_format) == sfr
&& in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
pi->active = 1;
return 0;
}
/* let's notify the codecs about clocks going away.
* For now we only do mastering on the i2s cell... */
@@ -490,6 +514,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (cii->codec->switch_clock)
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
pi->active = 1;
return 0;
}
@@ -734,6 +759,7 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_playback_ops = {
.open = i2sbus_playback_open,
.close = i2sbus_playback_close,
.hw_params = i2sbus_playback_hw_params,
.hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger,
@@ -802,6 +828,7 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_record_ops = {
.open = i2sbus_record_open,
.close = i2sbus_record_close,
.hw_params = i2sbus_record_hw_params,
.hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger,
+1
View File
@@ -23,6 +23,7 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
# for trace-points
CFLAGS_pcm_lib.o := -I$(src)
CFLAGS_pcm_native.o := -I$(src)
CFLAGS_control.o := -I$(src)
snd-pcm-dmaengine-y := pcm_dmaengine.o
+13 -8
View File
@@ -41,13 +41,6 @@
#define COMPR_CODEC_CAPS_OVERFLOW
#endif
/* TODO:
* - add substream support for multiple devices in case of
* SND_DYNAMIC_MINORS is not used
* - Multiple node representation
* driver should be able to register multiple nodes
*/
struct snd_compr_file {
unsigned long caps;
struct snd_compr_stream stream;
@@ -190,9 +183,21 @@ snd_compr_tstamp32_from_64(struct snd_compr_tstamp *tstamp32,
static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
struct snd_compr_tstamp64 *tstamp)
{
int ret;
if (!stream->ops->pointer)
return -ENOTSUPP;
stream->ops->pointer(stream, tstamp);
switch (stream->runtime->state) {
case SNDRV_PCM_STATE_OPEN:
return -EBADFD;
default:
break;
}
ret = stream->ops->pointer(stream, tstamp);
if (ret != 0)
return ret;
pr_debug("dsp consumed till %u total %llu bytes\n", tstamp->byte_offset,
tstamp->copied_total);
if (stream->direction == SND_COMPRESS_PLAYBACK)
+75 -1
View File
@@ -19,6 +19,13 @@
#include <sound/info.h>
#include <sound/control.h>
#ifdef CONFIG_SND_CTL_DEBUG
#define CREATE_TRACE_POINTS
#include "control_trace.h"
#else
#define trace_snd_ctl_put(card, kctl, iname, expected, actual)
#endif
// Max allocation size for user controls.
static int max_user_ctl_alloc_size = 8 * 1024 * 1024;
module_param_named(max_user_ctl_alloc_size, max_user_ctl_alloc_size, int, 0444);
@@ -1264,6 +1271,72 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
return result;
}
#if IS_ENABLED(CONFIG_SND_CTL_DEBUG)
static const char *const snd_ctl_elem_iface_names[] = {
[SNDRV_CTL_ELEM_IFACE_CARD] = "CARD",
[SNDRV_CTL_ELEM_IFACE_HWDEP] = "HWDEP",
[SNDRV_CTL_ELEM_IFACE_MIXER] = "MIXER",
[SNDRV_CTL_ELEM_IFACE_PCM] = "PCM",
[SNDRV_CTL_ELEM_IFACE_RAWMIDI] = "RAWMIDI",
[SNDRV_CTL_ELEM_IFACE_TIMER] = "TIMER",
[SNDRV_CTL_ELEM_IFACE_SEQUENCER] = "SEQUENCER",
};
static int snd_ctl_put_verify(struct snd_card *card, struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *control)
{
struct snd_ctl_elem_value *original = card->value_buf;
struct snd_ctl_elem_info info;
const char *iname;
int ret, retcmp;
memset(original, 0, sizeof(*original));
memset(&info, 0, sizeof(info));
ret = kctl->info(kctl, &info);
if (ret)
return ret;
ret = kctl->get(kctl, original);
if (ret)
return ret;
ret = kctl->put(kctl, control);
if (ret < 0)
return ret;
/* Sanitize the new value (control->value) before comparing. */
fill_remaining_elem_value(control, &info, 0);
/* With known state for both new and original, do the comparison. */
retcmp = memcmp(&original->value, &control->value, sizeof(original->value));
if (retcmp)
retcmp = 1;
iname = snd_ctl_elem_iface_names[kctl->id.iface];
trace_snd_ctl_put(&kctl->id, iname, card->number, ret, retcmp);
return ret;
}
static int snd_ctl_put(struct snd_card *card, struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *control, unsigned int access)
{
if ((access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK) ||
(access & SNDRV_CTL_ELEM_ACCESS_VOLATILE))
return kctl->put(kctl, control);
return snd_ctl_put_verify(card, kctl, control);
}
#else
static inline int snd_ctl_put(struct snd_card *card, struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *control, unsigned int access)
{
return kctl->put(kctl, control);
}
#endif
static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
struct snd_ctl_elem_value *control)
{
@@ -1300,7 +1373,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
false);
}
if (!result)
result = kctl->put(kctl, control);
result = snd_ctl_put(card, kctl, control, vd->access);
if (result < 0) {
up_write(&card->controls_rwsem);
return result;
+55
View File
@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM snd_ctl
#if !defined(_TRACE_SND_CTL_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SND_CTL_H
#include <linux/tracepoint.h>
#include <uapi/sound/asound.h>
TRACE_EVENT(snd_ctl_put,
TP_PROTO(struct snd_ctl_elem_id *id, const char *iname, unsigned int card,
int expected, int actual),
TP_ARGS(id, iname, card, expected, actual),
TP_STRUCT__entry(
__field(unsigned int, numid)
__string(iname, iname)
__string(kname, id->name)
__field(unsigned int, index)
__field(unsigned int, device)
__field(unsigned int, subdevice)
__field(unsigned int, card)
__field(int, expected)
__field(int, actual)
),
TP_fast_assign(
__entry->numid = id->numid;
__assign_str(iname);
__assign_str(kname);
__entry->index = id->index;
__entry->device = id->device;
__entry->subdevice = id->subdevice;
__entry->card = card;
__entry->expected = expected;
__entry->actual = actual;
),
TP_printk("%s: expected=%d, actual=%d for ctl numid=%d, iface=%s, name='%s', index=%d, device=%d, subdevice=%d, card=%d\n",
__entry->expected == __entry->actual ? "success" : "fail",
__entry->expected, __entry->actual, __entry->numid,
__get_str(iname), __get_str(kname), __entry->index,
__entry->device, __entry->subdevice, __entry->card)
);
#endif /* _TRACE_SND_CTL_H */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE control_trace
#include <trace/define_trace.h>
+8
View File
@@ -362,6 +362,11 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
#ifdef CONFIG_SND_DEBUG
card->debugfs_root = debugfs_create_dir(dev_name(&card->card_dev),
sound_debugfs_root);
#endif
#ifdef CONFIG_SND_CTL_DEBUG
card->value_buf = kmalloc(sizeof(*card->value_buf), GFP_KERNEL);
if (!card->value_buf)
return -ENOMEM;
#endif
return 0;
@@ -587,6 +592,9 @@ static int snd_card_do_free(struct snd_card *card)
snd_device_free_all(card);
if (card->private_free)
card->private_free(card);
#ifdef CONFIG_SND_CTL_DEBUG
kfree(card->value_buf);
#endif
if (snd_info_card_free(card) < 0) {
dev_warn(card->dev, "unable to free card info\n");
/* Not fatal error */
+25 -19
View File
@@ -1227,14 +1227,16 @@ static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substrea
snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_state_t state;
int ret;
while (1) {
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
state = snd_pcm_get_state(substream);
if (state == SNDRV_PCM_STATE_XRUN ||
state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
pcm_dbg(substream->pcm,
"pcm_oss: write: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ?
state == SNDRV_PCM_STATE_XRUN ?
"XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
@@ -1249,7 +1251,7 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
break;
/* test, if we can't store new data, because the stream */
/* has not been started */
if (runtime->state == SNDRV_PCM_STATE_PREPARED)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_PREPARED)
return -EAGAIN;
}
return ret;
@@ -1259,20 +1261,22 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t delay;
snd_pcm_state_t state;
int ret;
while (1) {
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
state = snd_pcm_get_state(substream);
if (state == SNDRV_PCM_STATE_XRUN ||
state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
pcm_dbg(substream->pcm,
"pcm_oss: read: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ?
state == SNDRV_PCM_STATE_XRUN ?
"XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
break;
} else if (runtime->state == SNDRV_PCM_STATE_SETUP) {
} else if (state == SNDRV_PCM_STATE_SETUP) {
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
break;
@@ -1285,7 +1289,7 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
frames, in_kernel);
mutex_lock(&runtime->oss.params_lock);
if (ret == -EPIPE) {
if (runtime->state == SNDRV_PCM_STATE_DRAINING) {
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_DRAINING) {
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if (ret < 0)
break;
@@ -1301,15 +1305,16 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_state_t state;
int ret;
while (1) {
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
state = snd_pcm_get_state(substream);
if (state == SNDRV_PCM_STATE_XRUN ||
state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
pcm_dbg(substream->pcm,
"pcm_oss: writev: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ?
state == SNDRV_PCM_STATE_XRUN ?
"XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
@@ -1322,7 +1327,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
/* test, if we can't store new data, because the stream */
/* has not been started */
if (runtime->state == SNDRV_PCM_STATE_PREPARED)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_PREPARED)
return -EAGAIN;
}
return ret;
@@ -1330,21 +1335,22 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_state_t state;
int ret;
while (1) {
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
state = snd_pcm_get_state(substream);
if (state == SNDRV_PCM_STATE_XRUN ||
state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
pcm_dbg(substream->pcm,
"pcm_oss: readv: recovering from %s\n",
runtime->state == SNDRV_PCM_STATE_XRUN ?
state == SNDRV_PCM_STATE_XRUN ?
"XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
break;
} else if (runtime->state == SNDRV_PCM_STATE_SETUP) {
} else if (state == SNDRV_PCM_STATE_SETUP) {
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
break;

Some files were not shown because too many files have changed in this diff Show More