Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/sound/firewire/digi00x/Makefile b/sound/firewire/digi00x/Makefile
index 1123e68..8add0cd 100644
--- a/sound/firewire/digi00x/Makefile
+++ b/sound/firewire/digi00x/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
digi00x-pcm.o digi00x-hwdep.o \
digi00x-transaction.o digi00x-midi.o digi00x.o
diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c
index 4a884a3..d613642 100644
--- a/sound/firewire/digi00x/amdtp-dot.c
+++ b/sound/firewire/digi00x/amdtp-dot.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
* Copyright (C) 2012 Robin Gareus <robin@gareus.org>
* Copyright (C) 2012 Damien Zammit <damien@zamaudio.com>
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include <sound/pcm.h>
@@ -128,7 +127,7 @@
if (err < 0)
return err;
- s->fdf = AMDTP_FDF_AM824 | s->sfc;
+ s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
p->pcm_channels = pcm_channels;
@@ -144,17 +143,23 @@
}
static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
- __be32 *buffer, unsigned int frames)
+ __be32 *buffer, unsigned int frames,
+ unsigned int pcm_frames)
{
struct amdtp_dot *p = s->protocol;
+ unsigned int channels = p->pcm_channels;
struct snd_pcm_runtime *runtime = pcm->runtime;
- unsigned int channels, remaining_frames, i, c;
+ unsigned int pcm_buffer_pointer;
+ int remaining_frames;
const u32 *src;
+ int i, c;
- channels = p->pcm_channels;
+ pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
+ pcm_buffer_pointer %= runtime->buffer_size;
+
src = (void *)runtime->dma_area +
- frames_to_bytes(runtime, s->pcm_buffer_pointer);
- remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+ frames_to_bytes(runtime, pcm_buffer_pointer);
+ remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
buffer++;
for (i = 0; i < frames; ++i) {
@@ -170,17 +175,23 @@
}
static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
- __be32 *buffer, unsigned int frames)
+ __be32 *buffer, unsigned int frames,
+ unsigned int pcm_frames)
{
struct amdtp_dot *p = s->protocol;
+ unsigned int channels = p->pcm_channels;
struct snd_pcm_runtime *runtime = pcm->runtime;
- unsigned int channels, remaining_frames, i, c;
+ unsigned int pcm_buffer_pointer;
+ int remaining_frames;
u32 *dst;
+ int i, c;
- channels = p->pcm_channels;
+ pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
+ pcm_buffer_pointer %= runtime->buffer_size;
+
dst = (void *)runtime->dma_area +
- frames_to_bytes(runtime, s->pcm_buffer_pointer);
- remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+ frames_to_bytes(runtime, pcm_buffer_pointer);
+ remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
buffer++;
for (i = 0; i < frames; ++i) {
@@ -235,7 +246,7 @@
}
static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
- unsigned int data_blocks)
+ unsigned int data_blocks, unsigned int data_block_counter)
{
struct amdtp_dot *p = s->protocol;
unsigned int f, port;
@@ -243,7 +254,7 @@
u8 *b;
for (f = 0; f < data_blocks; f++) {
- port = (s->data_block_counter + f) % 8;
+ port = (data_block_counter + f) % 8;
b = (u8 *)&buffer[0];
len = 0;
@@ -330,66 +341,74 @@
WRITE_ONCE(p->midi[port], midi);
}
-static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
- __be32 *buffer,
- unsigned int data_blocks,
- unsigned int *syt)
+static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
+ const struct pkt_desc *descs,
+ unsigned int packets,
+ struct snd_pcm_substream *pcm)
{
- struct snd_pcm_substream *pcm;
- unsigned int pcm_frames;
+ unsigned int pcm_frames = 0;
+ int i;
- pcm = READ_ONCE(s->pcm);
- if (pcm) {
- read_pcm_s32(s, pcm, buffer, data_blocks);
- pcm_frames = data_blocks;
- } else {
- pcm_frames = 0;
+ for (i = 0; i < packets; ++i) {
+ const struct pkt_desc *desc = descs + i;
+ __be32 *buf = desc->ctx_payload;
+ unsigned int data_blocks = desc->data_blocks;
+
+ if (pcm) {
+ read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
+ pcm_frames += data_blocks;
+ }
+
+ read_midi_messages(s, buf, data_blocks);
}
- read_midi_messages(s, buffer, data_blocks);
-
return pcm_frames;
}
-static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
- __be32 *buffer,
- unsigned int data_blocks,
- unsigned int *syt)
+static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
+ const struct pkt_desc *descs,
+ unsigned int packets,
+ struct snd_pcm_substream *pcm)
{
- struct snd_pcm_substream *pcm;
- unsigned int pcm_frames;
+ unsigned int pcm_frames = 0;
+ int i;
- pcm = READ_ONCE(s->pcm);
- if (pcm) {
- write_pcm_s32(s, pcm, buffer, data_blocks);
- pcm_frames = data_blocks;
- } else {
- write_pcm_silence(s, buffer, data_blocks);
- pcm_frames = 0;
+ for (i = 0; i < packets; ++i) {
+ const struct pkt_desc *desc = descs + i;
+ __be32 *buf = desc->ctx_payload;
+ unsigned int data_blocks = desc->data_blocks;
+
+ if (pcm) {
+ write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
+ pcm_frames += data_blocks;
+ } else {
+ write_pcm_silence(s, buf, data_blocks);
+ }
+
+ write_midi_messages(s, buf, data_blocks,
+ desc->data_block_counter);
}
- write_midi_messages(s, buffer, data_blocks);
-
return pcm_frames;
}
int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir)
{
- amdtp_stream_process_data_blocks_t process_data_blocks;
+ amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
enum cip_flags flags;
- /* Use different mode between incoming/outgoing. */
+ // Use different mode between incoming/outgoing.
if (dir == AMDTP_IN_STREAM) {
flags = CIP_NONBLOCKING;
- process_data_blocks = process_tx_data_blocks;
+ process_ctx_payloads = process_ir_ctx_payloads;
} else {
flags = CIP_BLOCKING;
- process_data_blocks = process_rx_data_blocks;
+ process_ctx_payloads = process_it_ctx_payloads;
}
return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
- process_data_blocks, sizeof(struct amdtp_dot));
+ process_ctx_payloads, sizeof(struct amdtp_dot));
}
void amdtp_dot_reset(struct amdtp_stream *s)
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
index 426cd39..41c5857 100644
--- a/sound/firewire/digi00x/digi00x-hwdep.c
+++ b/sound/firewire/digi00x/digi00x-hwdep.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
/*
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index 7ab3d08..2b57ece 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include "digi00x.h"
@@ -18,8 +17,13 @@
return err;
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
- err = snd_dg00x_stream_start_duplex(dg00x, 0);
+ err = snd_dg00x_stream_reserve_duplex(dg00x, 0);
+ if (err >= 0) {
+ ++dg00x->substreams_counter;
+ err = snd_dg00x_stream_start_duplex(dg00x);
+ if (err < 0)
+ --dg00x->substreams_counter;
+ }
mutex_unlock(&dg00x->mutex);
if (err < 0)
snd_dg00x_stream_lock_release(dg00x);
@@ -32,7 +36,7 @@
struct snd_dg00x *dg00x = substream->rmidi->private_data;
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index fdcff04..18e561b 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include "digi00x.h"
@@ -155,8 +154,8 @@
return 0;
}
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_dg00x *dg00x = substream->private_data;
int err;
@@ -167,58 +166,26 @@
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
+ err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
+ if (err >= 0)
+ ++dg00x->substreams_counter;
mutex_unlock(&dg00x->mutex);
}
- return 0;
+ return err;
}
-static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_dg00x *dg00x = substream->private_data;
- int err;
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
-
- if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
- mutex_unlock(&dg00x->mutex);
- }
-
- return 0;
-}
-
-static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
mutex_lock(&dg00x->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dg00x->substreams_counter--;
-
- snd_dg00x_stream_stop_duplex(dg00x);
-
- mutex_unlock(&dg00x->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_dg00x *dg00x = substream->private_data;
-
- mutex_lock(&dg00x->mutex);
-
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
@@ -230,12 +197,11 @@
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+ err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0)
amdtp_stream_pcm_prepare(&dg00x->tx_stream);
@@ -247,12 +213,11 @@
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+ err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0) {
amdtp_stream_pcm_prepare(&dg00x->rx_stream);
amdtp_dot_reset(&dg00x->rx_stream);
@@ -333,8 +298,8 @@
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
@@ -345,8 +310,8 @@
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
+ .hw_params = pcm_hw_params,
+ .hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
diff --git a/sound/firewire/digi00x/digi00x-proc.c b/sound/firewire/digi00x/digi00x-proc.c
index 6996d5a..00b047f 100644
--- a/sound/firewire/digi00x/digi00x-proc.c
+++ b/sound/firewire/digi00x/digi00x-proc.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x-proc.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include "digi00x.h"
@@ -80,20 +79,8 @@
return;
root->mode = S_IFDIR | 0555;
- if (snd_info_register(root) < 0) {
- snd_info_free_entry(root);
- return;
- }
entry = snd_info_create_card_entry(dg00x->card, "clock", root);
- if (entry == NULL) {
- snd_info_free_entry(root);
- return;
- }
-
- snd_info_set_text_ops(entry, dg00x, proc_read_clock);
- if (snd_info_register(entry) < 0) {
- snd_info_free_entry(entry);
- snd_info_free_entry(root);
- }
+ if (entry)
+ snd_info_set_text_ops(entry, dg00x, proc_read_clock);
}
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
index 4d3b4eb..d6a9246 100644
--- a/sound/firewire/digi00x/digi00x-stream.c
+++ b/sound/firewire/digi00x/digi00x-stream.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include "digi00x.h"
@@ -125,11 +124,22 @@
static void finish_session(struct snd_dg00x *dg00x)
{
- __be32 data = cpu_to_be32(0x00000003);
+ __be32 data;
+ data = cpu_to_be32(0x00000003);
snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
&data, sizeof(data), 0);
+
+ // Unregister isochronous channels for both direction.
+ data = 0;
+ snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+ DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+ &data, sizeof(data), 0);
+
+ // Just after finishing the session, the device may lost transmitting
+ // functionality for a short time.
+ msleep(50);
}
static int begin_session(struct snd_dg00x *dg00x)
@@ -138,11 +148,20 @@
u32 curr;
int err;
+ // Register isochronous channels for both direction.
+ data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
+ dg00x->rx_resources.channel);
+ err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+ DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+ &data, sizeof(data), 0);
+ if (err < 0)
+ return err;
+
err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
&data, sizeof(data), 0);
if (err < 0)
- goto error;
+ return err;
curr = be32_to_cpu(data);
if (curr == 0)
@@ -157,39 +176,23 @@
DG00X_OFFSET_STREAMING_SET,
&data, sizeof(data), 0);
if (err < 0)
- goto error;
+ break;
msleep(20);
curr--;
}
- return 0;
-error:
- finish_session(dg00x);
return err;
}
-static void release_resources(struct snd_dg00x *dg00x)
+static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
+ unsigned int rate)
{
- __be32 data = 0;
-
- /* Unregister isochronous channels for both direction. */
- snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
- DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
- &data, sizeof(data), 0);
-
- /* Release isochronous resources. */
- fw_iso_resources_free(&dg00x->tx_resources);
- fw_iso_resources_free(&dg00x->rx_resources);
-}
-
-static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
-{
- unsigned int i;
- __be32 data;
+ struct fw_iso_resources *resources;
+ int i;
int err;
- /* Check sampling rate. */
+ // Check sampling rate.
for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
if (snd_dg00x_stream_rates[i] == rate)
break;
@@ -197,66 +200,74 @@
if (i == SND_DG00X_RATE_COUNT)
return -EINVAL;
- /* Keep resources for out-stream. */
- err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate,
+ if (stream == &dg00x->tx_stream)
+ resources = &dg00x->tx_resources;
+ else
+ resources = &dg00x->rx_resources;
+
+ err = amdtp_dot_set_parameters(stream, rate,
snd_dg00x_stream_pcm_channels[i]);
if (err < 0)
return err;
- err = fw_iso_resources_allocate(&dg00x->rx_resources,
- amdtp_stream_get_max_payload(&dg00x->rx_stream),
+
+ return fw_iso_resources_allocate(resources,
+ amdtp_stream_get_max_payload(stream),
fw_parent_device(dg00x->unit)->max_speed);
+}
+
+static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
+{
+ struct fw_iso_resources *resources;
+ enum amdtp_stream_direction dir;
+ int err;
+
+ if (s == &dg00x->tx_stream) {
+ resources = &dg00x->tx_resources;
+ dir = AMDTP_IN_STREAM;
+ } else {
+ resources = &dg00x->rx_resources;
+ dir = AMDTP_OUT_STREAM;
+ }
+
+ err = fw_iso_resources_init(resources, dg00x->unit);
if (err < 0)
return err;
- /* Keep resources for in-stream. */
- err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate,
- snd_dg00x_stream_pcm_channels[i]);
+ err = amdtp_dot_init(s, dg00x->unit, dir);
if (err < 0)
- return err;
- err = fw_iso_resources_allocate(&dg00x->tx_resources,
- amdtp_stream_get_max_payload(&dg00x->tx_stream),
- fw_parent_device(dg00x->unit)->max_speed);
- if (err < 0)
- goto error;
+ fw_iso_resources_destroy(resources);
- /* Register isochronous channels for both direction. */
- data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
- dg00x->rx_resources.channel);
- err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
- DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
- &data, sizeof(data), 0);
- if (err < 0)
- goto error;
-
- return 0;
-error:
- release_resources(dg00x);
return err;
}
+static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s)
+{
+ amdtp_stream_destroy(s);
+
+ if (s == &dg00x->tx_stream)
+ fw_iso_resources_destroy(&dg00x->tx_resources);
+ else
+ fw_iso_resources_destroy(&dg00x->rx_resources);
+}
+
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
{
int err;
- /* For out-stream. */
- err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit);
+ err = init_stream(dg00x, &dg00x->rx_stream);
if (err < 0)
- goto error;
- err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM);
- if (err < 0)
- goto error;
+ return err;
- /* For in-stream. */
- err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit);
+ err = init_stream(dg00x, &dg00x->tx_stream);
if (err < 0)
- goto error;
- err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM);
- if (err < 0)
- goto error;
+ destroy_stream(dg00x, &dg00x->rx_stream);
- return 0;
-error:
- snd_dg00x_stream_destroy_duplex(dg00x);
+ err = amdtp_domain_init(&dg00x->domain);
+ if (err < 0) {
+ destroy_stream(dg00x, &dg00x->rx_stream);
+ destroy_stream(dg00x, &dg00x->tx_stream);
+ }
+
return err;
}
@@ -266,35 +277,71 @@
*/
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
{
- amdtp_stream_destroy(&dg00x->rx_stream);
- fw_iso_resources_destroy(&dg00x->rx_resources);
+ amdtp_domain_destroy(&dg00x->domain);
- amdtp_stream_destroy(&dg00x->tx_stream);
- fw_iso_resources_destroy(&dg00x->tx_resources);
+ destroy_stream(dg00x, &dg00x->rx_stream);
+ destroy_stream(dg00x, &dg00x->tx_stream);
}
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
{
unsigned int curr_rate;
+ int err;
+
+ err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
+ if (err < 0)
+ return err;
+ if (rate == 0)
+ rate = curr_rate;
+
+ if (dg00x->substreams_counter == 0 || curr_rate != rate) {
+ amdtp_domain_stop(&dg00x->domain);
+
+ finish_session(dg00x);
+
+ fw_iso_resources_free(&dg00x->tx_resources);
+ fw_iso_resources_free(&dg00x->rx_resources);
+
+ err = snd_dg00x_stream_set_local_rate(dg00x, rate);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(dg00x, &dg00x->rx_stream, rate);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(dg00x, &dg00x->tx_stream, rate);
+ if (err < 0) {
+ fw_iso_resources_free(&dg00x->rx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
+{
+ unsigned int generation = dg00x->rx_resources.generation;
int err = 0;
if (dg00x->substreams_counter == 0)
- goto end;
+ return 0;
- /* Check current sampling rate. */
- err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
- if (err < 0)
- goto error;
- if (rate == 0)
- rate = curr_rate;
- if (curr_rate != rate ||
- amdtp_streaming_error(&dg00x->tx_stream) ||
+ if (amdtp_streaming_error(&dg00x->tx_stream) ||
amdtp_streaming_error(&dg00x->rx_stream)) {
+ amdtp_domain_stop(&dg00x->domain);
finish_session(dg00x);
+ }
- amdtp_stream_stop(&dg00x->tx_stream);
- amdtp_stream_stop(&dg00x->rx_stream);
- release_resources(dg00x);
+ if (generation != fw_parent_device(dg00x->unit)->card->generation) {
+ err = fw_iso_resources_update(&dg00x->tx_resources);
+ if (err < 0)
+ goto error;
+
+ err = fw_iso_resources_update(&dg00x->rx_resources);
+ if (err < 0)
+ goto error;
}
/*
@@ -302,75 +349,52 @@
* which source of clock is used.
*/
if (!amdtp_stream_running(&dg00x->rx_stream)) {
- err = snd_dg00x_stream_set_local_rate(dg00x, rate);
- if (err < 0)
- goto error;
-
- err = keep_resources(dg00x, rate);
- if (err < 0)
- goto error;
+ int spd = fw_parent_device(dg00x->unit)->max_speed;
err = begin_session(dg00x);
if (err < 0)
goto error;
- err = amdtp_stream_start(&dg00x->rx_stream,
- dg00x->rx_resources.channel,
- fw_parent_device(dg00x->unit)->max_speed);
+ err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream,
+ dg00x->rx_resources.channel, spd);
+ if (err < 0)
+ goto error;
+
+ err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream,
+ dg00x->tx_resources.channel, spd);
+ if (err < 0)
+ goto error;
+
+ err = amdtp_domain_start(&dg00x->domain);
if (err < 0)
goto error;
if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
- CALLBACK_TIMEOUT)) {
+ CALLBACK_TIMEOUT) ||
+ !amdtp_stream_wait_callback(&dg00x->tx_stream,
+ CALLBACK_TIMEOUT)) {
err = -ETIMEDOUT;
goto error;
}
}
- /*
- * The value of SYT field in transmitted packets is always 0x0000. Thus,
- * duplex streams with timestamp synchronization cannot be built.
- */
- if (!amdtp_stream_running(&dg00x->tx_stream)) {
- err = amdtp_stream_start(&dg00x->tx_stream,
- dg00x->tx_resources.channel,
- fw_parent_device(dg00x->unit)->max_speed);
- if (err < 0)
- goto error;
-
- if (!amdtp_stream_wait_callback(&dg00x->tx_stream,
- CALLBACK_TIMEOUT)) {
- err = -ETIMEDOUT;
- goto error;
- }
- }
-end:
- return err;
+ return 0;
error:
+ amdtp_domain_stop(&dg00x->domain);
finish_session(dg00x);
- amdtp_stream_stop(&dg00x->tx_stream);
- amdtp_stream_stop(&dg00x->rx_stream);
- release_resources(dg00x);
-
return err;
}
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
{
- if (dg00x->substreams_counter > 0)
- return;
+ if (dg00x->substreams_counter == 0) {
+ amdtp_domain_stop(&dg00x->domain);
+ finish_session(dg00x);
- amdtp_stream_stop(&dg00x->tx_stream);
- amdtp_stream_stop(&dg00x->rx_stream);
- finish_session(dg00x);
- release_resources(dg00x);
-
- /*
- * Just after finishing the session, the device may lost transmitting
- * functionality for a short time.
- */
- msleep(50);
+ fw_iso_resources_free(&dg00x->tx_resources);
+ fw_iso_resources_free(&dg00x->rx_resources);
+ }
}
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c
index af9bc85..cf0bcf1 100644
--- a/sound/firewire/digi00x/digi00x-transaction.c
+++ b/sound/firewire/digi00x/digi00x-transaction.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x-transaction.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include <sound/asound.h>
diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c
index ef68999..1f5fc0e 100644
--- a/sound/firewire/digi00x/digi00x.c
+++ b/sound/firewire/digi00x/digi00x.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* digi00x.c - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include "digi00x.h"
@@ -41,20 +40,12 @@
return 0;
}
-static void dg00x_free(struct snd_dg00x *dg00x)
-{
- snd_dg00x_stream_destroy_duplex(dg00x);
- snd_dg00x_transaction_unregister(dg00x);
-
- fw_unit_put(dg00x->unit);
-
- mutex_destroy(&dg00x->mutex);
- kfree(dg00x);
-}
-
static void dg00x_card_free(struct snd_card *card)
{
- dg00x_free(card->private_data);
+ struct snd_dg00x *dg00x = card->private_data;
+
+ snd_dg00x_stream_destroy_duplex(dg00x);
+ snd_dg00x_transaction_unregister(dg00x);
}
static void do_registration(struct work_struct *work)
@@ -70,6 +61,8 @@
&dg00x->card);
if (err < 0)
return;
+ dg00x->card->private_free = dg00x_card_free;
+ dg00x->card->private_data = dg00x;
err = name_card(dg00x);
if (err < 0)
@@ -101,14 +94,10 @@
if (err < 0)
goto error;
- dg00x->card->private_free = dg00x_card_free;
- dg00x->card->private_data = dg00x;
dg00x->registered = true;
return;
error:
- snd_dg00x_transaction_unregister(dg00x);
- snd_dg00x_stream_destroy_duplex(dg00x);
snd_card_free(dg00x->card);
dev_info(&dg00x->unit->device,
"Sound card registration failed: %d\n", err);
@@ -120,8 +109,9 @@
struct snd_dg00x *dg00x;
/* Allocate this independent of sound card instance. */
- dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL);
- if (dg00x == NULL)
+ dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x),
+ GFP_KERNEL);
+ if (!dg00x)
return -ENOMEM;
dg00x->unit = fw_unit_get(unit);
@@ -173,12 +163,12 @@
cancel_delayed_work_sync(&dg00x->dwork);
if (dg00x->registered) {
- /* No need to wait for releasing card object in this context. */
- snd_card_free_when_closed(dg00x->card);
- } else {
- /* Don't forget this case. */
- dg00x_free(dg00x);
+ // Block till all of ALSA character devices are released.
+ snd_card_free(dg00x->card);
}
+
+ mutex_destroy(&dg00x->mutex);
+ fw_unit_put(dg00x->unit);
}
static const struct ieee1394_device_id snd_dg00x_id_table[] = {
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 4dd1bbf..8041c65 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* digi00x.h - a part of driver for Digidesign Digi 002/003 family
*
* Copyright (c) 2014-2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#ifndef SOUND_DIGI00X_H_INCLUDED
@@ -60,6 +59,8 @@
/* Console models have additional MIDI ports for control surface. */
bool is_console;
+
+ struct amdtp_domain domain;
};
#define DG00X_ADDR_BASE 0xffffe0000000ull
@@ -140,7 +141,8 @@
int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
bool *detect);
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);