summaryrefslogtreecommitdiff
path: root/sound/pci/echoaudio/echoaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/echoaudio/echoaudio.c')
-rw-r--r--sound/pci/echoaudio/echoaudio.c812
1 files changed, 367 insertions, 445 deletions
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 907cf1a46712..f2c8602a1ad7 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1,27 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ALSA driver for Echoaudio soundcards.
* Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Copyright (C) 2020 Mark Hills <mark@xwax.org>
*/
#include <linux/module.h>
+#include <linux/string.h>
MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver");
-MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}");
MODULE_DEVICE_TABLE(pci, snd_echo_ids);
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -35,7 +24,7 @@ MODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
-static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
+static const unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
@@ -46,7 +35,6 @@ static int get_firmware(const struct firmware **fw_entry,
int err;
char name[30];
-#ifdef CONFIG_PM_SLEEP
if (chip->fw_cache[fw_index]) {
dev_dbg(chip->card->dev,
"firmware requested: %s is cached\n",
@@ -54,7 +42,6 @@ static int get_firmware(const struct firmware **fw_entry,
*fw_entry = chip->fw_cache[fw_index];
return 0;
}
-#endif
dev_dbg(chip->card->dev,
"firmware requested: %s\n", card_fw[fw_index].data);
@@ -63,10 +50,8 @@ static int get_firmware(const struct firmware **fw_entry,
if (err < 0)
dev_err(chip->card->dev,
"get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM_SLEEP
else
chip->fw_cache[fw_index] = *fw_entry;
-#endif
return err;
}
@@ -75,18 +60,13 @@ static int get_firmware(const struct firmware **fw_entry,
static void free_firmware(const struct firmware *fw_entry,
struct echoaudio *chip)
{
-#ifdef CONFIG_PM_SLEEP
dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n");
-#else
- release_firmware(fw_entry);
-#endif
}
static void free_firmware_cache(struct echoaudio *chip)
{
-#ifdef CONFIG_PM_SLEEP
int i;
for (i = 0; i < 8 ; i++)
@@ -94,8 +74,6 @@ static void free_firmware_cache(struct echoaudio *chip)
release_firmware(chip->fw_cache[i]);
dev_dbg(chip->card->dev, "release_firmware(%d)\n", i);
}
-
-#endif
}
@@ -257,13 +235,19 @@ static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
SNDRV_PCM_HW_PARAM_RATE);
struct echoaudio *chip = rule->private;
struct snd_interval fixed;
+ int err;
- if (!chip->can_set_rate) {
+ guard(mutex)(&chip->mode_mutex);
+
+ if (chip->can_set_rate) {
+ err = 0;
+ } else {
snd_interval_any(&fixed);
fixed.min = fixed.max = chip->sample_rate;
- return snd_interval_refine(rate, &fixed);
+ err = snd_interval_refine(rate, &fixed);
}
- return 0;
+
+ return err;
}
@@ -306,42 +290,57 @@ static int pcm_open(struct snd_pcm_substream *substream,
snd_pcm_set_sync(substream);
/* Only mono and any even number of channels are allowed */
- if ((err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &pipe->constr)) < 0)
+ err = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &pipe->constr);
+ if (err < 0)
return err;
/* All periods should have the same size */
- if ((err = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+ err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
return err;
/* The hw accesses memory in chunks 32 frames long and they should be
32-bytes-aligned. It's not a requirement, but it seems that IRQs are
generated with a resolution of 32 frames. Thus we need the following */
- if ((err = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- 32)) < 0)
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
+ if (err < 0)
return err;
- if ((err = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- 32)) < 0)
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+ if (err < 0)
return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- hw_rule_sample_rate, chip,
- SNDRV_PCM_HW_PARAM_RATE, -1)) < 0)
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ hw_rule_sample_rate, chip,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
return err;
- /* Finally allocate a page for the scatter-gather list */
- if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
- PAGE_SIZE, &pipe->sgpage)) < 0) {
+ /* Allocate a page for the scatter-gather list */
+ err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+ &chip->pci->dev,
+ PAGE_SIZE, &pipe->sgpage);
+ if (err < 0) {
dev_err(chip->card->dev, "s-g list allocation failed\n");
return err;
}
+ /*
+ * Sole ownership required to set the rate
+ */
+
+ dev_dbg(chip->card->dev, "pcm_open opencount=%d can_set_rate=%d, rate_set=%d",
+ chip->opencount, chip->can_set_rate, chip->rate_set);
+
+ chip->opencount++;
+ if (chip->opencount > 1 && chip->rate_set)
+ chip->can_set_rate = 0;
+
return 0;
}
@@ -352,25 +351,23 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err;
- if ((err = pcm_open(substream, num_analog_busses_in(chip) -
- substream->number)) < 0)
+ err = pcm_open(substream,
+ num_analog_busses_in(chip) - substream->number);
+ if (err < 0)
return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_capture_channels_by_format, NULL,
- SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_capture_channels_by_format, NULL,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (err < 0)
return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_capture_format_by_channels, NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ hw_rule_capture_format_by_channels, NULL,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
return err;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
- dev_dbg(chip->card->dev, "pcm_analog_in_open cs=%d oc=%d r=%d\n",
- chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate);
+
return 0;
}
@@ -386,26 +383,24 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream)
#else
max_channels = num_analog_busses_out(chip);
#endif
- if ((err = pcm_open(substream, max_channels - substream->number)) < 0)
+ err = pcm_open(substream, max_channels - substream->number);
+ if (err < 0)
return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_playback_channels_by_format,
- NULL,
- SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_playback_channels_by_format,
+ NULL,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (err < 0)
return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_playback_format_by_channels,
- NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ hw_rule_playback_format_by_channels,
+ NULL,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
return err;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
- dev_dbg(chip->card->dev, "pcm_analog_out_open cs=%d oc=%d r=%d\n",
- chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate);
+
return 0;
}
@@ -419,7 +414,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
int err, max_channels;
max_channels = num_digital_busses_in(chip) - substream->number;
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
err = pcm_open(substream, max_channels);
else /* If the card has ADAT, subtract the 6 channels
@@ -428,26 +423,22 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
if (err < 0)
- goto din_exit;
-
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_capture_channels_by_format, NULL,
- SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
- goto din_exit;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_capture_format_by_channels, NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
- goto din_exit;
-
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
-
-din_exit:
- mutex_unlock(&chip->mode_mutex);
- return err;
+ return err;
+
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_capture_channels_by_format, NULL,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ hw_rule_capture_format_by_channels, NULL,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ return err;
+
+ return 0;
}
@@ -460,7 +451,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
int err, max_channels;
max_channels = num_digital_busses_out(chip) - substream->number;
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
err = pcm_open(substream, max_channels);
else /* If the card has ADAT, subtract the 6 channels
@@ -469,26 +460,24 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
if (err < 0)
- goto dout_exit;
-
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_playback_channels_by_format,
- NULL, SNDRV_PCM_HW_PARAM_FORMAT,
- -1)) < 0)
- goto dout_exit;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_playback_format_by_channels,
- NULL, SNDRV_PCM_HW_PARAM_CHANNELS,
- -1)) < 0)
- goto dout_exit;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
-dout_exit:
- mutex_unlock(&chip->mode_mutex);
- return err;
+ return err;
+
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_playback_channels_by_format,
+ NULL, SNDRV_PCM_HW_PARAM_FORMAT,
+ -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ hw_rule_playback_format_by_channels,
+ NULL, SNDRV_PCM_HW_PARAM_CHANNELS,
+ -1);
+ if (err < 0)
+ return err;
+
+ return 0;
}
#endif /* !ECHOCARD_HAS_VMIXER */
@@ -500,22 +489,27 @@ dout_exit:
static int pcm_close(struct snd_pcm_substream *substream)
{
struct echoaudio *chip = snd_pcm_substream_chip(substream);
- int oc;
/* Nothing to do here. Audio is already off and pipe will be
* freed by its callback
*/
- atomic_dec(&chip->opencount);
- oc = atomic_read(&chip->opencount);
- dev_dbg(chip->card->dev, "pcm_close oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate, chip->rate_set);
- if (oc < 2)
+ guard(mutex)(&chip->mode_mutex);
+
+ dev_dbg(chip->card->dev, "pcm_open opencount=%d can_set_rate=%d, rate_set=%d",
+ chip->opencount, chip->can_set_rate, chip->rate_set);
+
+ chip->opencount--;
+
+ switch (chip->opencount) {
+ case 1:
chip->can_set_rate = 1;
- if (oc == 0)
+ break;
+
+ case 0:
chip->rate_set = 0;
- dev_dbg(chip->card->dev, "pcm_close2 oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate, chip->rate_set);
+ break;
+ }
return 0;
}
@@ -537,38 +531,27 @@ static int init_engine(struct snd_pcm_substream *substream,
/* Sets up che hardware. If it's already initialized, reset and
* redo with the new parameters
*/
- spin_lock_irq(&chip->lock);
- if (pipe->index >= 0) {
- dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index);
- err = free_pipes(chip, pipe);
- snd_BUG_ON(err);
- chip->substream[pipe->index] = NULL;
- }
+ scoped_guard(spinlock_irq, &chip->lock) {
+ if (pipe->index >= 0) {
+ dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index);
+ err = free_pipes(chip, pipe);
+ snd_BUG_ON(err);
+ chip->substream[pipe->index] = NULL;
+ }
- err = allocate_pipes(chip, pipe, pipe_index, interleave);
- if (err < 0) {
- spin_unlock_irq(&chip->lock);
- dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n",
- pipe_index, err);
- return err;
+ err = allocate_pipes(chip, pipe, pipe_index, interleave);
+ if (err < 0) {
+ dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n",
+ pipe_index, err);
+ return err;
+ }
}
- spin_unlock_irq(&chip->lock);
dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index);
dev_dbg(chip->card->dev,
"pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
params_buffer_bytes(hw_params), params_periods(hw_params),
params_period_bytes(hw_params));
- err = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (err < 0) {
- dev_err(chip->card->dev, "malloc_pages err=%d\n", err);
- spin_lock_irq(&chip->lock);
- free_pipes(chip, pipe);
- spin_unlock_irq(&chip->lock);
- pipe->index = -1;
- return err;
- }
sglist_init(chip, pipe);
edge = PAGE_SIZE;
@@ -604,15 +587,14 @@ static int init_engine(struct snd_pcm_substream *substream,
/* This stuff is used by the irq handler, so it must be
* initialized before chip->substream
*/
- chip->last_period[pipe_index] = 0;
+ pipe->last_period = 0;
pipe->last_counter = 0;
pipe->position = 0;
smp_wmb();
chip->substream[pipe_index] = substream;
chip->rate_set = 1;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -674,16 +656,14 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
chip = snd_pcm_substream_chip(substream);
pipe = (struct audiopipe *) substream->runtime->private_data;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
if (pipe->index >= 0) {
dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index);
free_pipes(chip, pipe);
chip->substream[pipe->index] = NULL;
pipe->index = -1;
}
- spin_unlock_irq(&chip->lock);
- snd_pcm_lib_free_pages(substream);
return 0;
}
@@ -713,7 +693,7 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
break;
case SNDRV_PCM_FORMAT_S32_BE:
format.data_are_bigendian = 1;
- /* fall through */
+ fallthrough;
case SNDRV_PCM_FORMAT_S32_LE:
format.bits_per_sample = 32;
break;
@@ -726,9 +706,19 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
if (snd_BUG_ON(pipe_index >= px_num(chip)))
return -EINVAL;
+
+ /*
+ * We passed checks we can do independently; now take
+ * exclusive control
+ */
+
+ guard(spinlock_irq)(&chip->lock);
+
if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index)))
return -EINVAL;
+
set_audio_format(chip, pipe_index, &format);
+
return 0;
}
@@ -751,7 +741,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
}
- spin_lock(&chip->lock);
+ guard(spinlock)(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
@@ -761,11 +751,11 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
pipe = chip->substream[i]->runtime->private_data;
switch (pipe->state) {
case PIPE_STATE_STOPPED:
- chip->last_period[i] = 0;
+ pipe->last_period = 0;
pipe->last_counter = 0;
pipe->position = 0;
*pipe->dma_counter = 0;
- /* fall through */
+ fallthrough;
case PIPE_STATE_PAUSED:
pipe->state = PIPE_STATE_STARTED;
break;
@@ -799,7 +789,6 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
default:
err = -EINVAL;
}
- spin_unlock(&chip->lock);
return err;
}
@@ -809,19 +798,26 @@ static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct audiopipe *pipe = runtime->private_data;
- size_t cnt, bufsize, pos;
+ u32 counter, step;
+
+ /*
+ * IRQ handling runs concurrently. Do not share tracking of
+ * counter with it, which would race or require locking
+ */
- cnt = le32_to_cpu(*pipe->dma_counter);
- pipe->position += cnt - pipe->last_counter;
- pipe->last_counter = cnt;
- bufsize = substream->runtime->buffer_size;
- pos = bytes_to_frames(substream->runtime, pipe->position);
+ counter = le32_to_cpu(*pipe->dma_counter); /* presumed atomic */
- while (pos >= bufsize) {
- pipe->position -= frames_to_bytes(substream->runtime, bufsize);
- pos -= bufsize;
- }
- return pos;
+ step = counter - pipe->last_counter; /* handles wrapping */
+ pipe->last_counter = counter;
+
+ /* counter doesn't neccessarily wrap on a multiple of
+ * buffer_size, so can't derive the position; must
+ * accumulate */
+
+ pipe->position += step;
+ pipe->position %= frames_to_bytes(runtime, runtime->buffer_size); /* wrap */
+
+ return bytes_to_frames(runtime, pipe->position);
}
@@ -830,49 +826,41 @@ static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops analog_playback_ops = {
.open = pcm_analog_out_open,
.close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_analog_out_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
};
static const struct snd_pcm_ops analog_capture_ops = {
.open = pcm_analog_in_open,
.close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_analog_in_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
};
#ifdef ECHOCARD_HAS_DIGITAL_IO
#ifndef ECHOCARD_HAS_VMIXER
static const struct snd_pcm_ops digital_playback_ops = {
.open = pcm_digital_out_open,
.close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_digital_out_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
};
#endif /* !ECHOCARD_HAS_VMIXER */
static const struct snd_pcm_ops digital_capture_ops = {
.open = pcm_digital_in_open,
.close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_digital_in_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_prepare,
.trigger = pcm_trigger,
.pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
};
#endif /* ECHOCARD_HAS_DIGITAL_IO */
@@ -881,21 +869,17 @@ static const struct snd_pcm_ops digital_capture_ops = {
/* Preallocate memory only for the first substream because it's the most
* used one
*/
-static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
+static void snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
{
struct snd_pcm_substream *ss;
- int stream, err;
+ int stream;
for (stream = 0; stream < 2; stream++)
- for (ss = pcm->streams[stream].substream; ss; ss = ss->next) {
- err = snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG,
- dev,
- ss->number ? 0 : 128<<10,
- 256<<10);
- if (err < 0)
- return err;
- }
- return 0;
+ for (ss = pcm->streams[stream].substream; ss; ss = ss->next)
+ snd_pcm_set_managed_buffer(ss, SNDRV_DMA_TYPE_DEV_SG,
+ dev,
+ ss->number ? 0 : 128<<10,
+ 256<<10);
}
@@ -914,28 +898,28 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
separated */
/* PCM#0 Virtual outputs and analog inputs */
- if ((err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip),
- num_analog_busses_in(chip), &pcm)) < 0)
+ err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip),
+ num_analog_busses_in(chip), &pcm);
+ if (err < 0)
return err;
pcm->private_data = chip;
chip->analog_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
+ snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital inputs, no outputs */
- if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, 0,
- num_digital_busses_in(chip), &pcm)) < 0)
+ err = snd_pcm_new(chip->card, "Digital PCM", 1, 0,
+ num_digital_busses_in(chip), &pcm);
+ if (err < 0)
return err;
pcm->private_data = chip;
chip->digital_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
+ snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#else /* ECHOCARD_HAS_VMIXER */
@@ -946,31 +930,31 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
register two PCM devices: */
/* PCM#0 Analog i/o */
- if ((err = snd_pcm_new(chip->card, "Analog PCM", 0,
- num_analog_busses_out(chip),
- num_analog_busses_in(chip), &pcm)) < 0)
+ err = snd_pcm_new(chip->card, "Analog PCM", 0,
+ num_analog_busses_out(chip),
+ num_analog_busses_in(chip), &pcm);
+ if (err < 0)
return err;
pcm->private_data = chip;
chip->analog_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
+ snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital i/o */
- if ((err = snd_pcm_new(chip->card, "Digital PCM", 1,
- num_digital_busses_out(chip),
- num_digital_busses_in(chip), &pcm)) < 0)
+ err = snd_pcm_new(chip->card, "Digital PCM", 1,
+ num_digital_busses_out(chip),
+ num_digital_busses_in(chip), &pcm);
+ if (err < 0)
return err;
pcm->private_data = chip;
chip->digital_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
+ snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#endif /* ECHOCARD_HAS_VMIXER */
@@ -1021,7 +1005,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_busses_out(chip); c++) {
gain = ucontrol->value.integer.value[c];
/* Ignore out of range values */
@@ -1034,7 +1018,6 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
}
if (changed)
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1102,7 +1085,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_analog_busses_in(chip); c++) {
gain = ucontrol->value.integer.value[c];
/* Ignore out of range values */
@@ -1115,7 +1098,6 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
}
if (changed)
update_input_line_level(chip);
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1171,7 +1153,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_analog_busses_out(chip); c++) {
if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) {
set_nominal_level(chip, c,
@@ -1181,7 +1163,6 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
}
if (changed)
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1234,7 +1215,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_analog_busses_in(chip); c++) {
if (chip->nominal_level[bx_analog_in(chip) + c] !=
ucontrol->value.integer.value[c]) {
@@ -1247,7 +1228,6 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
update_output_line_level(chip); /* "Output" is not a mistake
* here.
*/
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1269,15 +1249,10 @@ static const struct snd_kcontrol_new snd_echo_intput_nominal_level = {
static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct echoaudio *chip;
-
- chip = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = ECHOGAIN_MINOUT;
uinfo->value.integer.max = ECHOGAIN_MAXOUT;
- uinfo->dimen.d[0] = num_busses_out(chip);
- uinfo->dimen.d[1] = num_busses_in(chip);
return 0;
}
@@ -1312,10 +1287,9 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
return -EINVAL;
if (chip->monitor_gain[out][in] != gain) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_monitor_gain(chip, out, in, gain);
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
changed = 1;
}
return changed;
@@ -1341,15 +1315,10 @@ static struct snd_kcontrol_new snd_echo_monitor_mixer = {
static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct echoaudio *chip;
-
- chip = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = ECHOGAIN_MINOUT;
uinfo->value.integer.max = ECHOGAIN_MAXOUT;
- uinfo->dimen.d[0] = num_busses_out(chip);
- uinfo->dimen.d[1] = num_pipes_out(chip);
return 0;
}
@@ -1380,10 +1349,9 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
return -EINVAL;
if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]);
update_vmixer_level(chip);
- spin_unlock_irq(&chip->lock);
changed = 1;
}
return changed;
@@ -1453,12 +1421,12 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
if (dmode != chip->digital_mode) {
/* mode_mutex is required to make this operation atomic wrt
pcm_digital_*_open() and set_input_clock() functions. */
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
/* Do not allow the user to change the digital mode when a pcm
device is open because it also changes the number of channels
and the allowed sample rates */
- if (atomic_read(&chip->opencount)) {
+ if (chip->opencount) {
changed = -EAGAIN;
} else {
changed = set_digital_mode(chip, dmode);
@@ -1473,7 +1441,6 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
if (changed >= 0)
changed = 1; /* No errors */
}
- mutex_unlock(&chip->mode_mutex);
}
return changed;
}
@@ -1520,9 +1487,8 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol,
chip = snd_kcontrol_chip(kcontrol);
mode = !!ucontrol->value.enumerated.item[0];
if (mode != chip->professional_spdif) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_professional_spdif(chip, mode);
- spin_unlock_irq(&chip->lock);
return 1;
}
return 0;
@@ -1586,12 +1552,11 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
dclock = chip->clock_source_list[eclock];
if (chip->input_clock != dclock) {
- mutex_lock(&chip->mode_mutex);
- spin_lock_irq(&chip->lock);
- if ((changed = set_input_clock(chip, dclock)) == 0)
+ guard(mutex)(&chip->mode_mutex);
+ guard(spinlock_irq)(&chip->lock);
+ changed = set_input_clock(chip, dclock);
+ if (!changed)
changed = 1; /* no errors */
- spin_unlock_irq(&chip->lock);
- mutex_unlock(&chip->mode_mutex);
}
if (changed < 0)
@@ -1635,9 +1600,8 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol,
power = !!ucontrol->value.integer.value[0];
if (chip->phantom_power != power) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
changed = set_phantom_power(chip, power);
- spin_unlock_irq(&chip->lock);
if (changed == 0)
changed = 1; /* no errors */
}
@@ -1678,9 +1642,8 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,
automute = !!ucontrol->value.integer.value[0];
if (chip->digital_in_automute != automute) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
changed = set_input_auto_mute(chip, automute);
- spin_unlock_irq(&chip->lock);
if (changed == 0)
changed = 1; /* no errors */
}
@@ -1708,9 +1671,8 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,
struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_meters_on(chip, ucontrol->value.integer.value[0]);
- spin_unlock_irq(&chip->lock);
return 1;
}
@@ -1732,13 +1694,6 @@ static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,
uinfo->count = 96;
uinfo->value.integer.min = ECHOGAIN_MINOUT;
uinfo->value.integer.max = 0;
-#ifdef ECHOCARD_HAS_VMIXER
- uinfo->dimen.d[0] = 3; /* Out, In, Virt */
-#else
- uinfo->dimen.d[0] = 2; /* Out, In */
-#endif
- uinfo->dimen.d[1] = 16; /* 16 channels */
- uinfo->dimen.d[2] = 2; /* 0=level, 1=peak */
return 0;
}
@@ -1817,14 +1772,43 @@ static const struct snd_kcontrol_new snd_echo_channels_info = {
/******************************************************************************
- IRQ Handler
+ IRQ Handling
******************************************************************************/
+/* Check if a period has elapsed since last interrupt
+ *
+ * Don't make any updates to state; PCM core handles this with the
+ * correct locks.
+ *
+ * \return true if a period has elapsed, otherwise false
+ */
+static bool period_has_elapsed(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audiopipe *pipe = runtime->private_data;
+ u32 counter, step;
+ size_t period_bytes;
+
+ if (pipe->state != PIPE_STATE_STARTED)
+ return false;
+
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
+
+ counter = le32_to_cpu(*pipe->dma_counter); /* presumed atomic */
+
+ step = counter - pipe->last_period; /* handles wrapping */
+ step -= step % period_bytes; /* acknowledge whole periods only */
+
+ if (step == 0)
+ return false; /* haven't advanced a whole period yet */
+
+ pipe->last_period += step; /* used exclusively by us */
+ return true;
+}
static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
{
struct echoaudio *chip = dev_id;
- struct snd_pcm_substream *substream;
- int period, ss, st;
+ int ss, st;
spin_lock(&chip->lock);
st = service_irq(chip);
@@ -1835,17 +1819,13 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
/* The hardware doesn't tell us which substream caused the irq,
thus we have to check all running substreams. */
for (ss = 0; ss < DSP_MAXPIPES; ss++) {
+ struct snd_pcm_substream *substream;
+
substream = chip->substream[ss];
- if (substream && ((struct audiopipe *)substream->runtime->
- private_data)->state == PIPE_STATE_STARTED) {
- period = pcm_pointer(substream) /
- substream->runtime->period_size;
- if (period != chip->last_period[ss]) {
- chip->last_period[ss] = period;
- spin_unlock(&chip->lock);
- snd_pcm_period_elapsed(substream);
- spin_lock(&chip->lock);
- }
+ if (substream && period_has_elapsed(substream)) {
+ spin_unlock(&chip->lock);
+ snd_pcm_period_elapsed(substream);
+ spin_lock(&chip->lock);
}
}
spin_unlock(&chip->lock);
@@ -1866,146 +1846,102 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
Module construction / destruction
******************************************************************************/
-static int snd_echo_free(struct echoaudio *chip)
+static void snd_echo_free(struct snd_card *card)
{
+ struct echoaudio *chip = card->private_data;
+
if (chip->comm_page)
rest_in_peace(chip);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->comm_page)
- snd_dma_free_pages(&chip->commpage_dma_buf);
-
- iounmap(chip->dsp_registers);
- release_and_free_resource(chip->iores);
- pci_disable_device(chip->pci);
-
/* release chip data */
free_firmware_cache(chip);
- kfree(chip);
- return 0;
-}
-
-
-
-static int snd_echo_dev_free(struct snd_device *device)
-{
- struct echoaudio *chip = device->device_data;
-
- return snd_echo_free(chip);
}
-
-
/* <--snd_echo_probe() */
static int snd_echo_create(struct snd_card *card,
- struct pci_dev *pci,
- struct echoaudio **rchip)
+ struct pci_dev *pci)
{
- struct echoaudio *chip;
+ struct echoaudio *chip = card->private_data;
int err;
size_t sz;
- static struct snd_device_ops ops = {
- .dev_free = snd_echo_dev_free,
- };
-
- *rchip = NULL;
pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0);
- if ((err = pci_enable_device(pci)) < 0)
+ err = pcim_enable_device(pci);
+ if (err < 0)
return err;
pci_set_master(pci);
/* Allocate chip if needed */
- if (!*rchip) {
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (!chip) {
- pci_disable_device(pci);
- return -ENOMEM;
- }
- dev_dbg(card->dev, "chip=%p\n", chip);
- spin_lock_init(&chip->lock);
- chip->card = card;
- chip->pci = pci;
- chip->irq = -1;
- atomic_set(&chip->opencount, 0);
- mutex_init(&chip->mode_mutex);
- chip->can_set_rate = 1;
- } else {
- /* If this was called from the resume function, chip is
- * already allocated and it contains current card settings.
- */
- chip = *rchip;
- }
+ spin_lock_init(&chip->lock);
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
+ chip->opencount = 0;
+ mutex_init(&chip->mode_mutex);
+ chip->can_set_rate = 1;
/* PCI resource allocation */
+ err = pcim_request_all_regions(pci, ECHOCARD_NAME);
+ if (err < 0)
+ return err;
+
chip->dsp_registers_phys = pci_resource_start(pci, 0);
sz = pci_resource_len(pci, 0);
if (sz > PAGE_SIZE)
sz = PAGE_SIZE; /* We map only the required part */
- if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,
- ECHOCARD_NAME)) == NULL) {
- dev_err(chip->card->dev, "cannot get memory region\n");
- snd_echo_free(chip);
- return -EBUSY;
+ chip->dsp_registers = devm_ioremap(&pci->dev, chip->dsp_registers_phys, sz);
+ if (!chip->dsp_registers) {
+ dev_err(chip->card->dev, "ioremap failed\n");
+ return -ENOMEM;
}
- chip->dsp_registers = (volatile u32 __iomem *)
- ioremap_nocache(chip->dsp_registers_phys, sz);
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
dev_err(chip->card->dev, "cannot grab irq\n");
- snd_echo_free(chip);
return -EBUSY;
}
chip->irq = pci->irq;
+ card->sync_irq = chip->irq;
dev_dbg(card->dev, "pci=%p irq=%d subdev=%04x Init hardware...\n",
chip->pci, chip->irq, chip->pci->subsystem_device);
+ card->private_free = snd_echo_free;
+
/* Create the DSP comm page - this is the area of memory used for most
of the communication with the DSP, which accesses it via bus mastering */
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
- sizeof(struct comm_page),
- &chip->commpage_dma_buf) < 0) {
- dev_err(chip->card->dev, "cannot allocate the comm page\n");
- snd_echo_free(chip);
+ chip->commpage_dma_buf =
+ snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV,
+ sizeof(struct comm_page));
+ if (!chip->commpage_dma_buf)
return -ENOMEM;
- }
- chip->comm_page_phys = chip->commpage_dma_buf.addr;
- chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;
+ chip->comm_page_phys = chip->commpage_dma_buf->addr;
+ chip->comm_page = (struct comm_page *)chip->commpage_dma_buf->area;
err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err >= 0)
err = set_mixer_defaults(chip);
if (err < 0) {
dev_err(card->dev, "init_hw err=%d\n", err);
- snd_echo_free(chip);
return err;
}
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- snd_echo_free(chip);
- return err;
- }
- *rchip = chip;
- /* Init done ! */
return 0;
}
-
-
/* constructor */
-static int snd_echo_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
+static int __snd_echo_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
{
static int dev;
struct snd_card *card;
struct echoaudio *chip;
char *dsp;
- int i, err;
+ int err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
@@ -2014,20 +1950,18 @@ static int snd_echo_probe(struct pci_dev *pci,
return -ENOENT;
}
- i = 0;
- err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
- 0, &card);
+ err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(*chip), &card);
if (err < 0)
return err;
+ chip = card->private_data;
- chip = NULL; /* Tells snd_echo_create to allocate chip */
- if ((err = snd_echo_create(card, pci, &chip)) < 0) {
- snd_card_free(card);
+ err = snd_echo_create(card, pci);
+ if (err < 0)
return err;
- }
- strcpy(card->driver, "Echo_" ECHOCARD_NAME);
- strcpy(card->shortname, chip->card_name);
+ strscpy(card->driver, "Echo_" ECHOCARD_NAME);
+ strscpy(card->shortname, chip->card_name);
dsp = "56301";
if (pci_id->device == 0x3410)
@@ -2037,17 +1971,17 @@ static int snd_echo_probe(struct pci_dev *pci,
card->shortname, pci_id->subdevice & 0x000f, dsp,
chip->dsp_registers_phys, chip->irq);
- if ((err = snd_echo_new_pcm(chip)) < 0) {
+ err = snd_echo_new_pcm(chip);
+ if (err < 0) {
dev_err(chip->card->dev, "new pcm error %d\n", err);
- snd_card_free(card);
return err;
}
#ifdef ECHOCARD_HAS_MIDI
if (chip->has_midi) { /* Some Mia's do not have midi */
- if ((err = snd_echo_midi_create(card, chip)) < 0) {
+ err = snd_echo_midi_create(card, chip);
+ if (err < 0) {
dev_err(chip->card->dev, "new midi error %d\n", err);
- snd_card_free(card);
return err;
}
}
@@ -2055,139 +1989,146 @@ static int snd_echo_probe(struct pci_dev *pci,
#ifdef ECHOCARD_HAS_VMIXER
snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip));
+ if (err < 0)
+ return err;
#ifdef ECHOCARD_HAS_LINE_OUT_GAIN
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_echo_line_output_gain, chip));
if (err < 0)
- goto ctl_error;
+ return err;
#endif
#else /* ECHOCARD_HAS_VMIXER */
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_echo_pcm_output_gain, chip));
if (err < 0)
- goto ctl_error;
+ return err;
#endif /* ECHOCARD_HAS_VMIXER */
#ifdef ECHOCARD_HAS_INPUT_GAIN
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip));
+ if (err < 0)
+ return err;
#endif
#ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
- if (!chip->hasnt_input_nominal_level)
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0)
- goto ctl_error;
+ if (!chip->hasnt_input_nominal_level) {
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip));
+ if (err < 0)
+ return err;
+ }
#endif
#ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip));
+ if (err < 0)
+ return err;
#endif
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip));
+ if (err < 0)
+ return err;
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip));
+ if (err < 0)
+ return err;
#ifdef ECHOCARD_HAS_MONITOR
snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip);
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip));
+ if (err < 0)
+ return err;
#endif
#ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip));
+ if (err < 0)
+ return err;
#endif
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip));
+ if (err < 0)
+ return err;
#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
/* Creates a list of available digital modes */
chip->num_digital_modes = 0;
- for (i = 0; i < 6; i++)
+ for (int i = 0; i < 6; i++)
if (chip->digital_modes & (1 << i))
chip->digital_mode_list[chip->num_digital_modes++] = i;
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip));
+ if (err < 0)
+ return err;
#endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
/* Creates a list of available clock sources */
chip->num_clock_sources = 0;
- for (i = 0; i < 10; i++)
+ for (int i = 0; i < 10; i++)
if (chip->input_clock_types & (1 << i))
chip->clock_source_list[chip->num_clock_sources++] = i;
if (chip->num_clock_sources > 1) {
chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip);
- if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, chip->clock_src_ctl);
+ if (err < 0)
+ return err;
}
#endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
#ifdef ECHOCARD_HAS_DIGITAL_IO
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0)
- goto ctl_error;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip));
+ if (err < 0)
+ return err;
#endif
#ifdef ECHOCARD_HAS_PHANTOM_POWER
- if (chip->has_phantom_power)
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0)
- goto ctl_error;
+ if (chip->has_phantom_power) {
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip));
+ if (err < 0)
+ return err;
+ }
#endif
err = snd_card_register(card);
if (err < 0)
- goto ctl_error;
+ return err;
dev_info(card->dev, "Card registered: %s\n", card->longname);
pci_set_drvdata(pci, chip);
dev++;
return 0;
-
-ctl_error:
- dev_err(card->dev, "new control error %d\n", err);
- snd_card_free(card);
- return err;
}
+static int snd_echo_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ return snd_card_free_on_error(&pci->dev, __snd_echo_probe(pci, pci_id));
+}
-#if defined(CONFIG_PM_SLEEP)
-
static int snd_echo_suspend(struct device *dev)
{
struct echoaudio *chip = dev_get_drvdata(dev);
- snd_pcm_suspend_all(chip->analog_pcm);
- snd_pcm_suspend_all(chip->digital_pcm);
-
#ifdef ECHOCARD_HAS_MIDI
/* This call can sleep */
if (chip->midi_out)
snd_echo_midi_output_trigger(chip->midi_out, 0);
#endif
- spin_lock_irq(&chip->lock);
- if (wait_handshake(chip)) {
- spin_unlock_irq(&chip->lock);
- return -EIO;
- }
- clear_handshake(chip);
- if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) {
- spin_unlock_irq(&chip->lock);
- return -EIO;
+ scoped_guard(spinlock_irq, &chip->lock) {
+ if (wait_handshake(chip))
+ return -EIO;
+ clear_handshake(chip);
+ if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0)
+ return -EIO;
}
- spin_unlock_irq(&chip->lock);
chip->dsp_code = NULL;
free_irq(chip->irq, chip);
chip->irq = -1;
+ chip->card->sync_irq = -1;
return 0;
}
@@ -2201,17 +2142,15 @@ static int snd_echo_resume(struct device *dev)
u32 pipe_alloc_mask;
int err;
- commpage_bak = kmalloc(sizeof(*commpage), GFP_KERNEL);
+ commpage = chip->comm_page;
+ commpage_bak = kmemdup(commpage, sizeof(*commpage), GFP_KERNEL);
if (commpage_bak == NULL)
return -ENOMEM;
- commpage = chip->comm_page;
- memcpy(commpage_bak, commpage, sizeof(*commpage));
err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err < 0) {
kfree(commpage_bak);
dev_err(dev, "resume init_hw err=%d\n", err);
- snd_echo_free(chip);
return err;
}
@@ -2238,10 +2177,10 @@ static int snd_echo_resume(struct device *dev)
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
dev_err(chip->card->dev, "cannot grab irq\n");
- snd_echo_free(chip);
return -EBUSY;
}
chip->irq = pci->irq;
+ chip->card->sync_irq = chip->irq;
dev_dbg(dev, "resume irq=%d\n", chip->irq);
#ifdef ECHOCARD_HAS_MIDI
@@ -2254,23 +2193,7 @@ static int snd_echo_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
-#define SND_ECHO_PM_OPS &snd_echo_pm
-#else
-#define SND_ECHO_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
-
-
-static void snd_echo_remove(struct pci_dev *pci)
-{
- struct echoaudio *chip;
-
- chip = pci_get_drvdata(pci);
- if (chip)
- snd_card_free(chip->card);
-}
-
-
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
/******************************************************************************
Everything starts and ends here
@@ -2281,9 +2204,8 @@ static struct pci_driver echo_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_echo_ids,
.probe = snd_echo_probe,
- .remove = snd_echo_remove,
.driver = {
- .pm = SND_ECHO_PM_OPS,
+ .pm = &snd_echo_pm,
},
};