[alsa-devel] [PATCH 00/15 v3] ALSA: firewire-lib: separate to packet streaming layer and data block processing layer
This patchset updates a part of my previous post (patch 01 and 02):
[alsa-devel] [PATCH 00/25 v2] ALSA: support AMDTP variants http://mailman.alsa-project.org/pipermail/alsa-devel/2015-August/096739.html
The aim of this patchset is to allow current amdtp implementation to handle several data block processing backends. For this aim, this patchset separates the implementation to packet streaming layer and AM824 data block processing layer.
The communication between these two layers is done by callback function. This patchset adds an overhead to call the functions as the same frequently as 8,000 times per second.
Takashi Sakamoto (15): ALSA: firewire-lib: arrange structure for AMDTP stream ALSA: firewire-lib: return error code when amdtp_stream_set_parameters() detects error ALSA: firewire-lib: add an argument for Dice's dual wire mode ALSA: firewire-lib: add a member of frame_multiplier instead of double_pcm_frames ALSA: firewire-lib: add helper functions as interfaces between packet streaming layer and data block processing layer ALSA: firewire-lib: add support arbitrary value for fmt/fdf fields in CIP header ALSA: firewire-lib: rename 'amdtp' to 'amdtp-stream' to prepare for functional separation ALSA: firewire-lib: add data block processing layer for AM824 format ALSA: firewire-lib: rename parameter setting function for AM824 with FDF field ALSA: firewire-lib: move PCM substream constraint to AM824 layer ALSA: firewire-lib: add helper functions to set positions of data channels ALSA: firewire-lib: move MIDI trigger helper function to AM824 layer ALSA: firewire-lib: rename PCM format helper function ALSA: firewire-lib: rename macros with AM824 prefix ALSA: firewire-lib: complete AM824 data block processing layer
sound/firewire/Makefile | 2 +- sound/firewire/amdtp-am824.c | 465 ++++++++++++++++++++++++++++ sound/firewire/amdtp-am824.h | 52 ++++ sound/firewire/{amdtp.c => amdtp-stream.c} | 377 ++++------------------ sound/firewire/{amdtp.h => amdtp-stream.h} | 116 +++---- sound/firewire/bebob/bebob.h | 2 +- sound/firewire/bebob/bebob_midi.c | 16 +- sound/firewire/bebob/bebob_pcm.c | 14 +- sound/firewire/bebob/bebob_stream.c | 34 +- sound/firewire/dice/dice-midi.c | 12 +- sound/firewire/dice/dice-pcm.c | 12 +- sound/firewire/dice/dice-stream.c | 22 +- sound/firewire/dice/dice.h | 2 +- sound/firewire/fcp.c | 2 +- sound/firewire/fireworks/fireworks.c | 12 +- sound/firewire/fireworks/fireworks.h | 2 +- sound/firewire/fireworks/fireworks_midi.c | 12 +- sound/firewire/fireworks/fireworks_pcm.c | 12 +- sound/firewire/fireworks/fireworks_stream.c | 8 +- sound/firewire/oxfw/oxfw-midi.c | 16 +- sound/firewire/oxfw/oxfw-pcm.c | 10 +- sound/firewire/oxfw/oxfw-stream.c | 11 +- sound/firewire/oxfw/oxfw.h | 2 +- 23 files changed, 730 insertions(+), 483 deletions(-) create mode 100644 sound/firewire/amdtp-am824.c create mode 100644 sound/firewire/amdtp-am824.h rename sound/firewire/{amdtp.c => amdtp-stream.c} (70%) rename sound/firewire/{amdtp.h => amdtp-stream.h} (78%)
In later commit, some members related to AM824 data format will be moved from AMDTP stream structure to data block structure. This commit is a preparation for it. Additionally, current layout of AMDTP stream structure is a bit mess by several extensions. This commit also arranges the layout.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp.h | 58 +++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 27 deletions(-)
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index b2cf9e7..4640d2b 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -117,52 +117,56 @@ struct amdtp_stream { struct fw_unit *unit; enum cip_flags flags; enum amdtp_stream_direction direction; - struct fw_iso_context *context; struct mutex mutex;
- enum cip_sfc sfc; - unsigned int data_block_quadlets; - unsigned int pcm_channels; - unsigned int midi_ports; - void (*transfer_samples)(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); - u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM]; - u8 midi_position; - - unsigned int syt_interval; - unsigned int transfer_delay; - unsigned int source_node_id_field; + /* For packet processing. */ + struct fw_iso_context *context; struct iso_packets_buffer buffer; - - struct snd_pcm_substream *pcm; - struct tasklet_struct period_tasklet; - int packet_index; + + /* For CIP headers. */ + unsigned int source_node_id_field; + unsigned int data_block_quadlets; unsigned int data_block_counter; + /* quirk: fixed interval of dbc between previos/current packets. */ + unsigned int tx_dbc_interval; + /* quirk: indicate the value of dbc field in a first packet. */ + unsigned int tx_first_dbc;
+ /* Internal flags. */ + enum cip_sfc sfc; + unsigned int syt_interval; + unsigned int transfer_delay; unsigned int data_block_state; - unsigned int last_syt_offset; unsigned int syt_offset_state;
+ /* For a PCM substream processing. */ + struct snd_pcm_substream *pcm; + struct tasklet_struct period_tasklet; unsigned int pcm_buffer_pointer; unsigned int pcm_period_pointer; bool pointer_flush; - bool double_pcm_frames;
+ /* To wait for first packet. */ + bool callbacked; + wait_queue_head_t callback_wait; + struct amdtp_stream *sync_slave; + + /* For AM824 processing. */ struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; int midi_fifo_limit; int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; + unsigned int pcm_channels; + unsigned int midi_ports;
- /* quirk: fixed interval of dbc between previos/current packets. */ - unsigned int tx_dbc_interval; - /* quirk: indicate the value of dbc field in a first packet. */ - unsigned int tx_first_dbc; + u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM]; + u8 midi_position; + bool double_pcm_frames;
- bool callbacked; - wait_queue_head_t callback_wait; - struct amdtp_stream *sync_slave; + void (*transfer_samples)(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames); };
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
Currently, amdtp_stream_set_parameters() returns no error even if wrong arguments are given. This is not good for streaming layer because drivers can continue processing ignoring capability of streaming layer.
This commit changes this function to return error code.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp.c | 22 ++++++++++++---------- sound/firewire/amdtp.h | 8 ++++---- sound/firewire/bebob/bebob_stream.c | 13 +++++++++---- sound/firewire/dice/dice-stream.c | 5 ++++- sound/firewire/fireworks/fireworks_stream.c | 6 ++++-- sound/firewire/oxfw/oxfw-stream.c | 5 ++++- 6 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 2a153d2..2bacb51 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -197,10 +197,10 @@ EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints); * The parameters must be set before the stream is started, and must not be * changed while the stream is running. */ -void amdtp_stream_set_parameters(struct amdtp_stream *s, - unsigned int rate, - unsigned int pcm_channels, - unsigned int midi_ports) +int amdtp_stream_set_parameters(struct amdtp_stream *s, + unsigned int rate, + unsigned int pcm_channels, + unsigned int midi_ports) { unsigned int i, sfc, midi_channels;
@@ -209,15 +209,15 @@ void amdtp_stream_set_parameters(struct amdtp_stream *s, if (WARN_ON(amdtp_stream_running(s)) | WARN_ON(pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM) | WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI)) - return; + return -EINVAL;
- for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc) + for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc) { if (amdtp_rate_table[sfc] == rate) - goto sfc_found; - WARN_ON(1); - return; + break; + } + if (sfc == ARRAY_SIZE(amdtp_rate_table)) + return -EINVAL;
-sfc_found: s->pcm_channels = pcm_channels; s->sfc = sfc; s->data_block_quadlets = s->pcm_channels + midi_channels; @@ -243,6 +243,8 @@ sfc_found: * (The value here is adjusted for midi_ratelimit_per_packet().) */ s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; + + return 0; } EXPORT_SYMBOL(amdtp_stream_set_parameters);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index 4640d2b..3fb8db7 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -174,10 +174,10 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum cip_flags flags); void amdtp_stream_destroy(struct amdtp_stream *s);
-void amdtp_stream_set_parameters(struct amdtp_stream *s, - unsigned int rate, - unsigned int pcm_channels, - unsigned int midi_ports); +int amdtp_stream_set_parameters(struct amdtp_stream *s, + unsigned int rate, + unsigned int pcm_channels, + unsigned int midi_ports); unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 5be5242..c642b79 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -427,12 +427,17 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate) index = get_formation_index(rate); pcm_channels = bebob->tx_stream_formations[index].pcm; midi_channels = bebob->tx_stream_formations[index].midi; - amdtp_stream_set_parameters(&bebob->tx_stream, - rate, pcm_channels, midi_channels * 8); + err = amdtp_stream_set_parameters(&bebob->tx_stream, rate, + pcm_channels, midi_channels * 8); + if (err < 0) + goto end; + pcm_channels = bebob->rx_stream_formations[index].pcm; midi_channels = bebob->rx_stream_formations[index].midi; - amdtp_stream_set_parameters(&bebob->rx_stream, - rate, pcm_channels, midi_channels * 8); + err = amdtp_stream_set_parameters(&bebob->rx_stream, rate, + pcm_channels, midi_channels * 8); + if (err < 0) + goto end;
/* establish connections for both streams */ err = cmp_connection_establish(&bebob->out_conn, diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 07dbd01..c96306a 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -133,7 +133,10 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, stream->double_pcm_frames = false; }
- amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports); + err = amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports); + if (err < 0) + goto end; + if (mode > 1) { pcm_chs /= 2;
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 7e353f1..dfefccf 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -73,8 +73,10 @@ start_stream(struct snd_efw *efw, struct amdtp_stream *stream, midi_ports = efw->midi_in_ports; }
- amdtp_stream_set_parameters(stream, sampling_rate, - pcm_channels, midi_ports); + err = amdtp_stream_set_parameters(stream, sampling_rate, + pcm_channels, midi_ports); + if (err < 0) + goto end;
/* establish connection via CMP */ err = cmp_connection_establish(conn, diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 77ad5b9..d119468 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -155,7 +155,10 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream, err = -EINVAL; goto end; } - amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports); + err = amdtp_stream_set_parameters(stream, rate, + pcm_channels, midi_ports); + if (err < 0) + goto end;
err = cmp_connection_establish(conn, amdtp_stream_get_max_payload(stream));
In IEC 61883-6, one data block represents one event. In ALSA, the event is one PCM frame. Therefore, when processing one data block, current implementation counts one PCM frame.
On the other hand, Dice platform has a quirk called as 'dual wire' at higher sampling rate. In detail, see comment of commit 6eb6c81eee2a ("ALSA: dice: Split stream functionality into a file").
Currently, to handle this quirk, AMDTP stream structure has a 'double_pcm_frames' member. When this is enabled, two PCM frames are counted. Each driver set this flag by accessing the structure member directly.
In future commit, some members related to AM824 data block will be moved to specific structure, to separate packet streaming layer and data block processing layer. The access will be limited by opaque pointer.
For this reason, this commit adds an argument into amdtp_stream_set_parameter() to set the flag.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp.c | 4 +++- sound/firewire/amdtp.h | 3 ++- sound/firewire/bebob/bebob_stream.c | 6 ++++-- sound/firewire/dice/dice-stream.c | 12 ++++++------ sound/firewire/fireworks/fireworks_stream.c | 2 +- sound/firewire/oxfw/oxfw-stream.c | 2 +- 6 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 2bacb51..094982f 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -193,6 +193,7 @@ EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints); * @pcm_channels: the number of PCM samples in each data block, to be encoded * as AM824 multi-bit linear audio * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) + * @double_pcm_frames: one data block transfers two PCM frames * * The parameters must be set before the stream is started, and must not be * changed while the stream is running. @@ -200,7 +201,8 @@ EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints); int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int pcm_channels, - unsigned int midi_ports) + unsigned int midi_ports, + bool double_pcm_frames) { unsigned int i, sfc, midi_channels;
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index 3fb8db7..2c91306 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -177,7 +177,8 @@ void amdtp_stream_destroy(struct amdtp_stream *s); int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int pcm_channels, - unsigned int midi_ports); + unsigned int midi_ports, + bool double_pcm_frames); unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index c642b79..920a3b8 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -428,14 +428,16 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate) pcm_channels = bebob->tx_stream_formations[index].pcm; midi_channels = bebob->tx_stream_formations[index].midi; err = amdtp_stream_set_parameters(&bebob->tx_stream, rate, - pcm_channels, midi_channels * 8); + pcm_channels, midi_channels * 8, + false); if (err < 0) goto end;
pcm_channels = bebob->rx_stream_formations[index].pcm; midi_channels = bebob->rx_stream_formations[index].midi; err = amdtp_stream_set_parameters(&bebob->rx_stream, rate, - pcm_channels, midi_channels * 8); + pcm_channels, midi_channels * 8, + false); if (err < 0) goto end;
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index c96306a..e4c6c20 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -100,6 +100,7 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, { struct fw_iso_resources *resources; unsigned int i, mode, pcm_chs, midi_ports; + bool double_pcm_frames; int err;
err = snd_dice_stream_get_rate_mode(dice, rate, &mode); @@ -125,19 +126,18 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, * For this quirk, blocking mode is required and PCM buffer size should * be aligned to SYT_INTERVAL. */ - if (mode > 1) { + double_pcm_frames = mode > 1; + if (double_pcm_frames) { rate /= 2; pcm_chs *= 2; - stream->double_pcm_frames = true; - } else { - stream->double_pcm_frames = false; }
- err = amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports); + err = amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports, + false); if (err < 0) goto end;
- if (mode > 1) { + if (double_pcm_frames) { pcm_chs /= 2;
for (i = 0; i < pcm_chs; i++) { diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index dfefccf..85a72e6 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -74,7 +74,7 @@ start_stream(struct snd_efw *efw, struct amdtp_stream *stream, }
err = amdtp_stream_set_parameters(stream, sampling_rate, - pcm_channels, midi_ports); + pcm_channels, midi_ports, false); if (err < 0) goto end;
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index d119468..318f78e 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -156,7 +156,7 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream, goto end; } err = amdtp_stream_set_parameters(stream, rate, - pcm_channels, midi_ports); + pcm_channels, midi_ports, false); if (err < 0) goto end;
In future commit, interface between data block processing layer and packet stream processing layer is defined. These two layers communicate the number of data blocks and the number of PCM frames.
The data block processing layer has a responsibility for calculating the number of PCM frames. Therefore, 'dual wire' of Dice quirk should be handled in data block processing layer.
This commit adds a member of 'frame_multiplier'. This member represents the ratio of the number of PCM frames against the number of data blocks. Usually, the value of this member is 1, while it's 2 in Dice's 'dual wire'.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp.c | 22 ++++++++++++---------- sound/firewire/amdtp.h | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 094982f..0bb5e14 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -225,6 +225,16 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, s->data_block_quadlets = s->pcm_channels + midi_channels; s->midi_ports = midi_ports;
+ /* + * In IEC 61883-6, one data block represents one event. In ALSA, one + * event equals to one PCM frame. But Dice has a quirk at higher + * sampling rate to transfer two PCM frames in one data block. + */ + if (double_pcm_frames) + s->frame_multiplier = 2; + else + s->frame_multiplier = 1; + s->syt_interval = amdtp_syt_intervals[sfc];
/* default buffering in the device */ @@ -584,14 +594,6 @@ static void update_pcm_pointers(struct amdtp_stream *s, { unsigned int ptr;
- /* - * In IEC 61883-6, one data block represents one event. In ALSA, one - * event equals to one PCM frame. But Dice has a quirk to transfer - * two PCM frames in one data block. - */ - if (s->double_pcm_frames) - frames *= 2; - ptr = s->pcm_buffer_pointer + frames; if (ptr >= pcm->runtime->buffer_size) ptr -= pcm->runtime->buffer_size; @@ -685,7 +687,7 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, return -EIO;
if (pcm) - update_pcm_pointers(s, pcm, data_blocks); + update_pcm_pointers(s, pcm, data_blocks * s->frame_multiplier);
/* No need to return the number of handled data blocks. */ return 0; @@ -788,7 +790,7 @@ end: return -EIO;
if (pcm) - update_pcm_pointers(s, pcm, *data_blocks); + update_pcm_pointers(s, pcm, *data_blocks * s->frame_multiplier);
return 0; } diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index 2c91306..6522925 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -162,11 +162,12 @@ struct amdtp_stream {
u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM]; u8 midi_position; - bool double_pcm_frames;
void (*transfer_samples)(struct amdtp_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); + + unsigned int frame_multiplier; };
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
ALSA PCM framework uses PCM buffer with a concept of 'period' to synchronize userspace operations to hardware for nearly-realtime processing. Each driver implements snd_pcm_period_elapsed() to tell across of the period boundary to ALSA PCM middleware. To call the function, some drivers utilize hardware interrupt handlers, the others count handled PCM frames.
Drivers for sound units on IEEE 1394 bus are the latter. They use two buffers; PCM buffer and DMA buffer for IEEE 1394 isochronous packet. PCM frames are copied between these two buffers and 'amdtp_stream' structure counts the handled PCM frames. Then, snd_pcm_period_elapsed() is called if required.
Essentially, packet streaming layer should not be responsible for PCM frame processing. The PCM frame processing should be handled in each data block processing layer as a result of handling data blocks. Although, PCM frame counting is a common work for all of protocols which ALSA firewire stack is going to support.
This commit adds two new helper functions as interfaces between packet streaming layer to data block processing layer. In future, each data block processing layer implements these functions. The packet streaming layer calls data block processing layer per packet by calling the functions. The data block processing layer processes data blocks and PCM frames, and returns the number of processed PCM frames. Then the packet streaming layer calculates handled PCM frames and calls snd_pcm_period_elapsed().
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp.c | 82 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 27 deletions(-)
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 0bb5e14..5a3a452 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -657,28 +657,42 @@ static inline int queue_in_packet(struct amdtp_stream *s) amdtp_stream_get_max_payload(s), false); }
+unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, + unsigned int data_blocks, unsigned int *syt) +{ + struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + unsigned int pcm_frames; + + if (pcm) { + s->transfer_samples(s, pcm, buffer, data_blocks); + pcm_frames = data_blocks * s->frame_multiplier; + } else { + write_pcm_silence(s, buffer, data_blocks); + pcm_frames = 0; + } + + if (s->midi_ports) + write_midi_messages(s, buffer, data_blocks); + + return pcm_frames; +} + static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, unsigned int syt) { __be32 *buffer; unsigned int payload_length; + unsigned int pcm_frames; struct snd_pcm_substream *pcm;
buffer = s->buffer.packets[s->packet_index].buffer; + pcm_frames = process_rx_data_blocks(s, buffer + 2, data_blocks, &syt); + buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | s->data_block_counter); buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 | (s->sfc << CIP_FDF_SHIFT) | syt); - buffer += 2; - - pcm = ACCESS_ONCE(s->pcm); - if (pcm) - s->transfer_samples(s, pcm, buffer, data_blocks); - else - write_pcm_silence(s, buffer, data_blocks); - if (s->midi_ports) - write_midi_messages(s, buffer, data_blocks);
s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
@@ -686,20 +700,41 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, if (queue_out_packet(s, payload_length, false) < 0) return -EIO;
- if (pcm) - update_pcm_pointers(s, pcm, data_blocks * s->frame_multiplier); + pcm = ACCESS_ONCE(s->pcm); + if (pcm && pcm_frames > 0) + update_pcm_pointers(s, pcm, pcm_frames);
/* No need to return the number of handled data blocks. */ return 0; }
+unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, + unsigned int data_blocks, unsigned int *syt) +{ + struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + unsigned int pcm_frames; + + if (pcm) { + s->transfer_samples(s, pcm, buffer, data_blocks); + pcm_frames = data_blocks * s->frame_multiplier; + } else { + pcm_frames = 0; + } + + if (s->midi_ports) + read_midi_messages(s, buffer, data_blocks); + + return pcm_frames; +} + static int handle_in_packet(struct amdtp_stream *s, unsigned int payload_quadlets, __be32 *buffer, - unsigned int *data_blocks) + unsigned int *data_blocks, unsigned int syt) { u32 cip_header[2]; unsigned int data_block_quadlets, data_block_counter, dbc_interval; - struct snd_pcm_substream *pcm = NULL; + struct snd_pcm_substream *pcm; + unsigned int pcm_frames; bool lost;
cip_header[0] = be32_to_cpu(buffer[0]); @@ -716,6 +751,7 @@ static int handle_in_packet(struct amdtp_stream *s, "Invalid CIP header for AMDTP: %08X:%08X\n", cip_header[0], cip_header[1]); *data_blocks = 0; + pcm_frames = 0; goto end; }
@@ -769,16 +805,7 @@ static int handle_in_packet(struct amdtp_stream *s, return -EIO; }
- if (*data_blocks > 0) { - buffer += 2; - - pcm = ACCESS_ONCE(s->pcm); - if (pcm) - s->transfer_samples(s, pcm, buffer, *data_blocks); - - if (s->midi_ports) - read_midi_messages(s, buffer, *data_blocks); - } + pcm_frames = process_tx_data_blocks(s, buffer + 2, *data_blocks, &syt);
if (s->flags & CIP_DBC_IS_END_EVENT) s->data_block_counter = data_block_counter; @@ -789,8 +816,9 @@ end: if (queue_in_packet(s) < 0) return -EIO;
- if (pcm) - update_pcm_pointers(s, pcm, *data_blocks * s->frame_multiplier); + pcm = ACCESS_ONCE(s->pcm); + if (pcm && pcm_frames > 0) + update_pcm_pointers(s, pcm, pcm_frames);
return 0; } @@ -860,15 +888,15 @@ static void in_stream_callback(struct fw_iso_context *context, u32 cycle, break; }
+ syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK; if (handle_in_packet(s, payload_quadlets, buffer, - &data_blocks) < 0) { + &data_blocks, syt) < 0) { s->packet_index = -1; break; }
/* Process sync slave stream */ if (s->sync_slave && s->sync_slave->callbacked) { - syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK; if (handle_out_packet(s->sync_slave, data_blocks, syt) < 0) { s->packet_index = -1;
Some vendor specific protocol uses its own value for fmt/fdf fields in CIP header.
This commit support to set arbitrary values for the fields.
In IEC 61883-6, NO-DATA code is defined for FDF field. A packet with this code includes no data even if it includes some data blocks. This commit still leaves a condition to handle this special packet.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp.c | 31 +++++++++++++++++++++++-------- sound/firewire/amdtp.h | 2 ++ 2 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 5a3a452..b251f4b 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -59,8 +59,8 @@ * Audio and Music transfer protocol specific parameters * only "Clock-based rate control mode" is supported */ -#define CIP_FMT_AM (0x10 << CIP_FMT_SHIFT) -#define AMDTP_FDF_AM824 (0 << (CIP_FDF_SHIFT + 3)) +#define CIP_FMT_AM 0x10 +#define AMDTP_FDF_AM824 0x00 #define AMDTP_FDF_NO_DATA 0xff
/* TODO: make these configurable */ @@ -94,6 +94,8 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->callbacked = false; s->sync_slave = NULL;
+ s->fmt = CIP_FMT_AM; + return 0; } EXPORT_SYMBOL(amdtp_stream_init); @@ -225,6 +227,8 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, s->data_block_quadlets = s->pcm_channels + midi_channels; s->midi_ports = midi_ports;
+ s->fdf = AMDTP_FDF_AM824 | s->sfc; + /* * In IEC 61883-6, one data block represents one event. In ALSA, one * event equals to one PCM frame. But Dice has a quirk at higher @@ -691,8 +695,10 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | s->data_block_counter); - buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 | - (s->sfc << CIP_FDF_SHIFT) | syt); + buffer[1] = cpu_to_be32(CIP_EOH | + ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) | + ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) | + (syt & CIP_SYT_MASK));
s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
@@ -732,6 +738,7 @@ static int handle_in_packet(struct amdtp_stream *s, unsigned int *data_blocks, unsigned int syt) { u32 cip_header[2]; + unsigned int fmt, fdf; unsigned int data_block_quadlets, data_block_counter, dbc_interval; struct snd_pcm_substream *pcm; unsigned int pcm_frames; @@ -745,8 +752,7 @@ static int handle_in_packet(struct amdtp_stream *s, * For convenience, also check FMT field is AM824 or not. */ if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) || - ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH) || - ((cip_header[1] & CIP_FMT_MASK) != CIP_FMT_AM)) { + ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) { dev_info_ratelimited(&s->unit->device, "Invalid CIP header for AMDTP: %08X:%08X\n", cip_header[0], cip_header[1]); @@ -755,10 +761,19 @@ static int handle_in_packet(struct amdtp_stream *s, goto end; }
+ /* Check valid protocol or not. */ + fmt = (cip_header[1] & CIP_FMT_MASK) >> CIP_FMT_SHIFT; + if (fmt != s->fmt) { + dev_err(&s->unit->device, + "Detect unexpected protocol: %08x %08x\n", + cip_header[0], cip_header[1]); + return -EIO; + } + /* Calculate data blocks */ + fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT; if (payload_quadlets < 3 || - ((cip_header[1] & CIP_FDF_MASK) == - (AMDTP_FDF_NO_DATA << CIP_FDF_SHIFT))) { + (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) { *data_blocks = 0; } else { data_block_quadlets = diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index 6522925..883bb1a 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -128,6 +128,8 @@ struct amdtp_stream { unsigned int source_node_id_field; unsigned int data_block_quadlets; unsigned int data_block_counter; + unsigned int fmt; + unsigned int fdf; /* quirk: fixed interval of dbc between previos/current packets. */ unsigned int tx_dbc_interval; /* quirk: indicate the value of dbc field in a first packet. */
In later commit, data block processing layer will be newly added. This layer will be named as 'amdtp-am824'.
This commit renames current amdtp file to amdtp-stream, to distinguish it from the new layer.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/Makefile | 2 +- sound/firewire/{amdtp.c => amdtp-stream.c} | 2 +- sound/firewire/{amdtp.h => amdtp-stream.h} | 0 sound/firewire/bebob/bebob.h | 2 +- sound/firewire/dice/dice.h | 2 +- sound/firewire/fcp.c | 2 +- sound/firewire/fireworks/fireworks.h | 2 +- sound/firewire/oxfw/oxfw.h | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename sound/firewire/{amdtp.c => amdtp-stream.c} (99%) rename sound/firewire/{amdtp.h => amdtp-stream.h} (100%)
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index 8b37f08..102e342 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,5 +1,5 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ - fcp.o cmp.o amdtp.o + fcp.o cmp.o amdtp-stream.o snd-oxfw-objs := oxfw.o snd-isight-objs := isight.o snd-scs1x-objs := scs1x.o diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp-stream.c similarity index 99% rename from sound/firewire/amdtp.c rename to sound/firewire/amdtp-stream.c index b251f4b..f1418b7 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp-stream.c @@ -15,7 +15,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/rawmidi.h> -#include "amdtp.h" +#include "amdtp-stream.h"
#define TICKS_PER_CYCLE 3072 #define CYCLES_PER_SECOND 8000 diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp-stream.h similarity index 100% rename from sound/firewire/amdtp.h rename to sound/firewire/amdtp-stream.h diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index d23caca..72a1c5e 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -31,7 +31,7 @@ #include "../fcp.h" #include "../packets-buffer.h" #include "../iso-resources.h" -#include "../amdtp.h" +#include "../amdtp-stream.h" #include "../cmp.h"
/* basic register addresses on DM1000/DM1100/DM1500 */ diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index ecf5dc8..29578c1 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -34,7 +34,7 @@ #include <sound/pcm_params.h> #include <sound/rawmidi.h>
-#include "../amdtp.h" +#include "../amdtp-stream.h" #include "../iso-resources.h" #include "../lib.h" #include "dice-interface.h" diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c index 0619597..cce1976 100644 --- a/sound/firewire/fcp.c +++ b/sound/firewire/fcp.c @@ -17,7 +17,7 @@ #include <linux/delay.h> #include "fcp.h" #include "lib.h" -#include "amdtp.h" +#include "amdtp-stream.h"
#define CTS_AVC 0x00
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 084d414..d54f171 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -29,7 +29,7 @@
#include "../packets-buffer.h" #include "../iso-resources.h" -#include "../amdtp.h" +#include "../amdtp-stream.h" #include "../cmp.h" #include "../lib.h"
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index cace5ad..2c3d20b 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -28,7 +28,7 @@ #include "../fcp.h" #include "../packets-buffer.h" #include "../iso-resources.h" -#include "../amdtp.h" +#include "../amdtp-stream.h" #include "../cmp.h"
struct device_info {
This commit adds data block processing layer for AM824 format. The new layer initializes streaming layer with its value for fmt field.
Currently, most implementation of data block processing still remains streaming layer. In later commits, these codes will be moved to the layer.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/Makefile | 2 +- sound/firewire/amdtp-am824.c | 26 ++++++++++++++++++++++++++ sound/firewire/amdtp-am824.h | 8 ++++++++ sound/firewire/amdtp-stream.c | 7 ++++--- sound/firewire/amdtp-stream.h | 3 ++- sound/firewire/bebob/bebob.h | 2 +- sound/firewire/bebob/bebob_stream.c | 8 ++++---- sound/firewire/dice/dice-stream.c | 2 +- sound/firewire/dice/dice.h | 2 +- sound/firewire/fireworks/fireworks.h | 2 +- sound/firewire/fireworks/fireworks_stream.c | 2 +- sound/firewire/oxfw/oxfw-stream.c | 2 +- sound/firewire/oxfw/oxfw.h | 2 +- 13 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 sound/firewire/amdtp-am824.c create mode 100644 sound/firewire/amdtp-am824.h
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index 102e342..6a8a713 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,5 +1,5 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ - fcp.o cmp.o amdtp-stream.o + fcp.o cmp.o amdtp-stream.o amdtp-am824.o snd-oxfw-objs := oxfw.o snd-isight-objs := isight.o snd-scs1x-objs := scs1x.o diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c new file mode 100644 index 0000000..da4b643 --- /dev/null +++ b/sound/firewire/amdtp-am824.c @@ -0,0 +1,26 @@ +/* + * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6) + * + * Copyright (c) 2015 Takashi Sakamoto o-takashi@sakamocchi.jp + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "amdtp-am824.h" + +#define CIP_FMT_AM 0x10 + +/** + * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824 + * data block + * @s: the AMDTP stream to initialize + * @unit: the target of the stream + * @dir: the direction of stream + * @flags: the packet transmission method to use + */ +int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, + enum amdtp_stream_direction dir, enum cip_flags flags) +{ + return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM); +} +EXPORT_SYMBOL_GPL(amdtp_am824_init); diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h new file mode 100644 index 0000000..ed96ac5 --- /dev/null +++ b/sound/firewire/amdtp-am824.h @@ -0,0 +1,8 @@ +#ifndef SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED +#define SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED + +#include "amdtp-stream.h" + +int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, + enum amdtp_stream_direction dir, enum cip_flags flags); +#endif diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index f1418b7..62f98e1 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -11,7 +11,6 @@ #include <linux/firewire.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/sched.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/rawmidi.h> @@ -78,9 +77,11 @@ static void pcm_period_tasklet(unsigned long data); * @unit: the target of the stream * @dir: the direction of stream * @flags: the packet transmission method to use + * @fmt: the value of fmt field in CIP header */ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, enum cip_flags flags) + enum amdtp_stream_direction dir, enum cip_flags flags, + unsigned int fmt) { s->unit = unit; s->direction = dir; @@ -94,7 +95,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->callbacked = false; s->sync_slave = NULL;
- s->fmt = CIP_FMT_AM; + s->fmt = fmt;
return 0; } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 883bb1a..5f96aff 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -4,6 +4,7 @@ #include <linux/err.h> #include <linux/interrupt.h> #include <linux/mutex.h> +#include <linux/sched.h> #include <sound/asound.h> #include "packets-buffer.h"
@@ -174,7 +175,7 @@ struct amdtp_stream {
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, - enum cip_flags flags); + enum cip_flags flags, unsigned int fmt); void amdtp_stream_destroy(struct amdtp_stream *s);
int amdtp_stream_set_parameters(struct amdtp_stream *s, diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 72a1c5e..d3c9d8d 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -31,7 +31,7 @@ #include "../fcp.h" #include "../packets-buffer.h" #include "../iso-resources.h" -#include "../amdtp-stream.h" +#include "../amdtp-am824.h" #include "../cmp.h"
/* basic register addresses on DM1000/DM1100/DM1500 */ diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 920a3b8..34bc3a4 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -537,8 +537,8 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) if (err < 0) goto end;
- err = amdtp_stream_init(&bebob->tx_stream, bebob->unit, - AMDTP_IN_STREAM, CIP_BLOCKING); + err = amdtp_am824_init(&bebob->tx_stream, bebob->unit, + AMDTP_IN_STREAM, CIP_BLOCKING); if (err < 0) { amdtp_stream_destroy(&bebob->tx_stream); destroy_both_connections(bebob); @@ -566,8 +566,8 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) if (bebob->maudio_special_quirk) bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
- err = amdtp_stream_init(&bebob->rx_stream, bebob->unit, - AMDTP_OUT_STREAM, CIP_BLOCKING); + err = amdtp_am824_init(&bebob->rx_stream, bebob->unit, + AMDTP_OUT_STREAM, CIP_BLOCKING); if (err < 0) { amdtp_stream_destroy(&bebob->tx_stream); amdtp_stream_destroy(&bebob->rx_stream); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index e4c6c20..917860e 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -305,7 +305,7 @@ static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream) goto end; resources->channels_mask = 0x00000000ffffffffuLL;
- err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING); + err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING); if (err < 0) { amdtp_stream_destroy(stream); fw_iso_resources_destroy(resources); diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 29578c1..101550ac 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -34,7 +34,7 @@ #include <sound/pcm_params.h> #include <sound/rawmidi.h>
-#include "../amdtp-stream.h" +#include "../amdtp-am824.h" #include "../iso-resources.h" #include "../lib.h" #include "dice-interface.h" diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index d54f171..c7cb7de 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -29,7 +29,7 @@
#include "../packets-buffer.h" #include "../iso-resources.h" -#include "../amdtp-stream.h" +#include "../amdtp-am824.h" #include "../cmp.h" #include "../lib.h"
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 85a72e6..8cac5b9 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -31,7 +31,7 @@ init_stream(struct snd_efw *efw, struct amdtp_stream *stream) if (err < 0) goto end;
- err = amdtp_stream_init(stream, efw->unit, s_dir, CIP_BLOCKING); + err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING); if (err < 0) { amdtp_stream_destroy(stream); cmp_connection_destroy(conn); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 318f78e..8368341 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -228,7 +228,7 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw, if (err < 0) goto end;
- err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING); + err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING); if (err < 0) { amdtp_stream_destroy(stream); cmp_connection_destroy(conn); diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 2c3d20b..2441459 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -28,7 +28,7 @@ #include "../fcp.h" #include "../packets-buffer.h" #include "../iso-resources.h" -#include "../amdtp-stream.h" +#include "../amdtp-am824.h" #include "../cmp.h"
struct device_info {
The value of FDF field in CIP header is protocol-dependent. Thus, it's better to allow data block processing layer to decide the value in any timing.
In AM824 data format, the value of FDF field in CIP header indicates N-flag and Nominal Sampling Frequency Code (sfc). The N-flag is for switching 'Clock-based rate control mode' and 'Command-based rate control mode'. In our implementation, 'Clock-based rate control mode' is just supported. Therefore, When sampling transfer frequency is decided, then the FDF can be set.
This commit replaces 'amdtp_stream_set_parameters' with 'amdtp_am824_set_parameters' to set the FDF. This is the same timing to decide the ration between the number of data blocks and the number of PCM frames.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-am824.c | 42 +++++++++++++++++++++++++++++ sound/firewire/amdtp-am824.h | 5 ++++ sound/firewire/amdtp-stream.c | 21 ++------------- sound/firewire/amdtp-stream.h | 3 +-- sound/firewire/bebob/bebob_stream.c | 12 ++++----- sound/firewire/dice/dice-stream.c | 4 +-- sound/firewire/fireworks/fireworks_stream.c | 4 +-- sound/firewire/oxfw/oxfw-stream.c | 4 +-- 8 files changed, 62 insertions(+), 33 deletions(-)
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index da4b643..f5edcbf 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -10,6 +10,48 @@
#define CIP_FMT_AM 0x10
+/* "Clock-based rate control mode" is just supported. */ +#define AMDTP_FDF_AM824 0x00 + +/** + * amdtp_am824_set_parameters - set stream parameters + * @s: the AMDTP stream to configure + * @rate: the sample rate + * @pcm_channels: the number of PCM samples in each data block, to be encoded + * as AM824 multi-bit linear audio + * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) + * @double_pcm_frames: one data block transfers two PCM frames + * + * The parameters must be set before the stream is started, and must not be + * changed while the stream is running. + */ +int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, + unsigned int pcm_channels, + unsigned int midi_ports, + bool double_pcm_frames) +{ + int err; + + err = amdtp_stream_set_parameters(s, rate, pcm_channels, midi_ports); + if (err < 0) + return err; + + s->fdf = AMDTP_FDF_AM824 | s->sfc; + + /* + * In IEC 61883-6, one data block represents one event. In ALSA, one + * event equals to one PCM frame. But Dice has a quirk at higher + * sampling rate to transfer two PCM frames in one data block. + */ + if (double_pcm_frames) + s->frame_multiplier = 2; + else + s->frame_multiplier = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters); + /** * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824 * data block diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index ed96ac5..cfc0d61 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -3,6 +3,11 @@
#include "amdtp-stream.h"
+int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, + unsigned int pcm_channels, + unsigned int midi_ports, + bool double_pcm_frames); + int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags); #endif diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 62f98e1..39ad8e8 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -54,12 +54,8 @@ #define CIP_SYT_MASK 0x0000ffff #define CIP_SYT_NO_INFO 0xffff
-/* - * Audio and Music transfer protocol specific parameters - * only "Clock-based rate control mode" is supported - */ +/* Audio and Music transfer protocol specific parameters */ #define CIP_FMT_AM 0x10 -#define AMDTP_FDF_AM824 0x00 #define AMDTP_FDF_NO_DATA 0xff
/* TODO: make these configurable */ @@ -204,8 +200,7 @@ EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints); int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int pcm_channels, - unsigned int midi_ports, - bool double_pcm_frames) + unsigned int midi_ports) { unsigned int i, sfc, midi_channels;
@@ -228,18 +223,6 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, s->data_block_quadlets = s->pcm_channels + midi_channels; s->midi_ports = midi_ports;
- s->fdf = AMDTP_FDF_AM824 | s->sfc; - - /* - * In IEC 61883-6, one data block represents one event. In ALSA, one - * event equals to one PCM frame. But Dice has a quirk at higher - * sampling rate to transfer two PCM frames in one data block. - */ - if (double_pcm_frames) - s->frame_multiplier = 2; - else - s->frame_multiplier = 1; - s->syt_interval = amdtp_syt_intervals[sfc];
/* default buffering in the device */ diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 5f96aff..d915940 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -181,8 +181,7 @@ void amdtp_stream_destroy(struct amdtp_stream *s); int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int pcm_channels, - unsigned int midi_ports, - bool double_pcm_frames); + unsigned int midi_ports); unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 34bc3a4..fa510f3 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -427,17 +427,17 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate) index = get_formation_index(rate); pcm_channels = bebob->tx_stream_formations[index].pcm; midi_channels = bebob->tx_stream_formations[index].midi; - err = amdtp_stream_set_parameters(&bebob->tx_stream, rate, - pcm_channels, midi_channels * 8, - false); + err = amdtp_am824_set_parameters(&bebob->tx_stream, rate, + pcm_channels, midi_channels * 8, + false); if (err < 0) goto end;
pcm_channels = bebob->rx_stream_formations[index].pcm; midi_channels = bebob->rx_stream_formations[index].midi; - err = amdtp_stream_set_parameters(&bebob->rx_stream, rate, - pcm_channels, midi_channels * 8, - false); + err = amdtp_am824_set_parameters(&bebob->rx_stream, rate, + pcm_channels, midi_channels * 8, + false); if (err < 0) goto end;
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 917860e..8948381 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -132,8 +132,8 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, pcm_chs *= 2; }
- err = amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports, - false); + err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports, + double_pcm_frames); if (err < 0) goto end;
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 8cac5b9..759f6e3 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -73,8 +73,8 @@ start_stream(struct snd_efw *efw, struct amdtp_stream *stream, midi_ports = efw->midi_in_ports; }
- err = amdtp_stream_set_parameters(stream, sampling_rate, - pcm_channels, midi_ports, false); + err = amdtp_am824_set_parameters(stream, sampling_rate, + pcm_channels, midi_ports, false); if (err < 0) goto end;
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 8368341..4982bef 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -155,8 +155,8 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream, err = -EINVAL; goto end; } - err = amdtp_stream_set_parameters(stream, rate, - pcm_channels, midi_ports, false); + err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports, + false); if (err < 0) goto end;
In IEC 61883-6, PCM frames are transferred in Multi Bit Linear Audio data channel. The data channel transfers 16/20/24 bit PCM samples. Thus, PCM substream has a constrain about it.
This commit moves codes related to the constraint from packet streaming layer to AM824 data block processing layer.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-am824.c | 20 ++++++++++++++++++++ sound/firewire/amdtp-am824.h | 5 +++++ sound/firewire/amdtp-stream.c | 5 ----- sound/firewire/bebob/bebob_pcm.c | 2 +- sound/firewire/dice/dice-pcm.c | 2 +- sound/firewire/fireworks/fireworks_pcm.c | 2 +- sound/firewire/oxfw/oxfw-pcm.c | 2 +- 7 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index f5edcbf..7adaba3 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -53,6 +53,26 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters);
/** + * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream + * @s: the AMDTP stream for AM824 data block, must be initialized. + * @runtime: the PCM substream runtime + * + */ +int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, + struct snd_pcm_runtime *runtime) +{ + int err; + + err = amdtp_stream_add_pcm_hw_constraints(s, runtime); + if (err < 0) + return err; + + /* AM824 in IEC 61883-6 can deliver 24bit data. */ + return snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); +} +EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints); + +/** * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824 * data block * @s: the AMDTP stream to initialize diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index cfc0d61..4aaed90 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -1,6 +1,8 @@ #ifndef SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED #define SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
+#include <sound/pcm.h> + #include "amdtp-stream.h"
int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, @@ -8,6 +10,9 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int midi_ports, bool double_pcm_frames);
+int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, + struct snd_pcm_runtime *runtime); + int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags); #endif diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 39ad8e8..06fbf23 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -140,11 +140,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, { int err;
- /* AM824 in IEC 61883-6 can deliver 24bit data */ - err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - if (err < 0) - goto end; - /* * Currently firewire-lib processes 16 packets in one software * interrupt callback. This equals to 2msec but actually the diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index c0f018a..50610ca 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -146,7 +146,7 @@ pcm_init_hw_params(struct snd_bebob *bebob, if (err < 0) goto end;
- err = amdtp_stream_add_pcm_hw_constraints(s, runtime); + err = amdtp_am824_add_pcm_hw_constraints(s, runtime); end: return err; } diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 4e67b1d..f5f3007 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -156,7 +156,7 @@ static int init_hw_info(struct snd_dice *dice, if (err < 0) goto end;
- err = amdtp_stream_add_pcm_hw_constraints(stream, runtime); + err = amdtp_am824_add_pcm_hw_constraints(stream, runtime); end: return err; } diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index c30b2ff..f186ab7 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -187,7 +187,7 @@ pcm_init_hw_params(struct snd_efw *efw, if (err < 0) goto end;
- err = amdtp_stream_add_pcm_hw_constraints(s, runtime); + err = amdtp_am824_add_pcm_hw_constraints(s, runtime); end: return err; } diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 9c73930..bddd287 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -158,7 +158,7 @@ static int init_hw_params(struct snd_oxfw *oxfw, if (err < 0) goto end;
- err = amdtp_stream_add_pcm_hw_constraints(stream, runtime); + err = amdtp_am824_add_pcm_hw_constraints(stream, runtime); end: return err; }
In IEC 61883-6, several types of data are available in AM824 format. The data is transferred in each data channel. The position of data channel in data block differs depending on model.
Current implementation has an array to map the index of data channel in an data block to the position of actual data channel. The implementation allows each driver to access the mapping directly.
In later commit, the mapping is in specific structure pushed into an opaque pointer. Helper functions are required.
This commit adds the helper functions for this purpose. In IEC 61883-6, AM824 format supports many data types, while this specification easily causes over-engineering. Current AM824 implementation is allowed to handle two types of data, Multi Bit Linear Audio data (=PCM samples) and MIDI conformant data (=MIDI messages).
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-am824.c | 28 ++++++++++++++++++++++++++++ sound/firewire/amdtp-am824.h | 6 ++++++ sound/firewire/bebob/bebob_stream.c | 5 +++-- sound/firewire/dice/dice-stream.c | 5 +++-- 4 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 7adaba3..5d99a992 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -53,6 +53,34 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters);
/** + * amdtp_am824_set_pcm_position - set an index of data channel for a channel + * of PCM frame + * @s: the AMDTP stream + * @index: the index of data channel in an data block + * @position: the channel of PCM frame + */ +void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index, + unsigned int position) +{ + if (index < s->pcm_channels) + s->pcm_positions[index] = position; +} +EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position); + +/** + * amdtp_am824_set_midi_position - set a index of data channel for MIDI + * conformant data channel + * @s: the AMDTP stream + * @position: the index of data channel in an data block + */ +void amdtp_am824_set_midi_position(struct amdtp_stream *s, + unsigned int position) +{ + s->midi_position = position; +} +EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position); + +/** * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream * @s: the AMDTP stream for AM824 data block, must be initialized. * @runtime: the PCM substream runtime diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index 4aaed90..7c21e99 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -10,6 +10,12 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int midi_ports, bool double_pcm_frames);
+void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index, + unsigned int position); + +void amdtp_am824_set_midi_position(struct amdtp_stream *s, + unsigned int position); + int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime);
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index fa510f3..cf6402d 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -338,7 +338,7 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) err = -ENOSYS; goto end; } - s->midi_position = stm_pos; + amdtp_am824_set_midi_position(s, stm_pos); midi = stm_pos; break; /* for PCM data channel */ @@ -358,7 +358,8 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) err = -ENOSYS; goto end; } - s->pcm_positions[location] = stm_pos; + amdtp_am824_set_pcm_position(s, location, + stm_pos); break; } } diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 8948381..2108f7f 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -141,8 +141,9 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream, pcm_chs /= 2;
for (i = 0; i < pcm_chs; i++) { - stream->pcm_positions[i] = i * 2; - stream->pcm_positions[i + pcm_chs] = i * 2 + 1; + amdtp_am824_set_pcm_position(stream, i, i * 2); + amdtp_am824_set_pcm_position(stream, i + pcm_chs, + i * 2 + 1); } }
In IEC 61883-6, MIDI messages are transferred in MIDI conformant data channel. Essentially, packet streaming layer is not responsible for MIDI functionality.
This commit moves MIDI trigger helper function from the layer to AM824 layer. The rest of codes related to MIDI functionality will be moved in later commits.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-am824.c | 18 ++++++++++++++++++ sound/firewire/amdtp-am824.h | 4 ++++ sound/firewire/amdtp-stream.h | 18 ------------------ sound/firewire/bebob/bebob_midi.c | 16 ++++++++-------- sound/firewire/dice/dice-midi.c | 12 ++++++------ sound/firewire/fireworks/fireworks_midi.c | 12 ++++++------ sound/firewire/oxfw/oxfw-midi.c | 16 ++++++++-------- 7 files changed, 50 insertions(+), 46 deletions(-)
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 5d99a992..540a101 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -101,6 +101,24 @@ int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints);
/** + * amdtp_am824_midi_trigger - start/stop playback/capture with a MIDI device + * @s: the AMDTP stream + * @port: index of MIDI port + * @midi: the MIDI device to be started, or %NULL to stop the current device + * + * Call this function on a running isochronous stream to enable the actual + * transmission of MIDI data. This function should be called from the MIDI + * device's .trigger callback. + */ +void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, + struct snd_rawmidi_substream *midi) +{ + if (port < s->midi_ports) + ACCESS_ONCE(s->midi[port]) = midi; +} +EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger); + +/** * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824 * data block * @s: the AMDTP stream to initialize diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index 7c21e99..65e6093 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -2,6 +2,7 @@ #define SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
#include <sound/pcm.h> +#include <sound/rawmidi.h>
#include "amdtp-stream.h"
@@ -19,6 +20,9 @@ void amdtp_am824_set_midi_position(struct amdtp_stream *s, int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime);
+void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, + struct snd_rawmidi_substream *midi); + int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags); #endif diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index d915940..984f02a 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -248,24 +248,6 @@ static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s, ACCESS_ONCE(s->pcm) = pcm; }
-/** - * amdtp_stream_midi_trigger - start/stop playback/capture with a MIDI device - * @s: the AMDTP stream - * @port: index of MIDI port - * @midi: the MIDI device to be started, or %NULL to stop the current device - * - * Call this function on a running isochronous stream to enable the actual - * transmission of MIDI data. This function should be called from the MIDI - * device's .trigger callback. - */ -static inline void amdtp_stream_midi_trigger(struct amdtp_stream *s, - unsigned int port, - struct snd_rawmidi_substream *midi) -{ - if (port < s->midi_ports) - ACCESS_ONCE(s->midi[port]) = midi; -} - static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) { return sfc & 1; diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 5681143..90d95be 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -72,11 +72,11 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&bebob->lock, flags);
if (up) - amdtp_stream_midi_trigger(&bebob->tx_stream, - substrm->number, substrm); + amdtp_am824_midi_trigger(&bebob->tx_stream, + substrm->number, substrm); else - amdtp_stream_midi_trigger(&bebob->tx_stream, - substrm->number, NULL); + amdtp_am824_midi_trigger(&bebob->tx_stream, + substrm->number, NULL);
spin_unlock_irqrestore(&bebob->lock, flags); } @@ -89,11 +89,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&bebob->lock, flags);
if (up) - amdtp_stream_midi_trigger(&bebob->rx_stream, - substrm->number, substrm); + amdtp_am824_midi_trigger(&bebob->rx_stream, + substrm->number, substrm); else - amdtp_stream_midi_trigger(&bebob->rx_stream, - substrm->number, NULL); + amdtp_am824_midi_trigger(&bebob->rx_stream, + substrm->number, NULL);
spin_unlock_irqrestore(&bebob->lock, flags); } diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index fe43ce7..151b09f 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&dice->lock, flags);
if (up) - amdtp_stream_midi_trigger(&dice->tx_stream, + amdtp_am824_midi_trigger(&dice->tx_stream, substrm->number, substrm); else - amdtp_stream_midi_trigger(&dice->tx_stream, + amdtp_am824_midi_trigger(&dice->tx_stream, substrm->number, NULL);
spin_unlock_irqrestore(&dice->lock, flags); @@ -69,11 +69,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&dice->lock, flags);
if (up) - amdtp_stream_midi_trigger(&dice->rx_stream, - substrm->number, substrm); + amdtp_am824_midi_trigger(&dice->rx_stream, + substrm->number, substrm); else - amdtp_stream_midi_trigger(&dice->rx_stream, - substrm->number, NULL); + amdtp_am824_midi_trigger(&dice->rx_stream, + substrm->number, NULL);
spin_unlock_irqrestore(&dice->lock, flags); } diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index cf9c652..fba01bb 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -73,10 +73,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&efw->lock, flags);
if (up) - amdtp_stream_midi_trigger(&efw->tx_stream, + amdtp_am824_midi_trigger(&efw->tx_stream, substrm->number, substrm); else - amdtp_stream_midi_trigger(&efw->tx_stream, + amdtp_am824_midi_trigger(&efw->tx_stream, substrm->number, NULL);
spin_unlock_irqrestore(&efw->lock, flags); @@ -90,11 +90,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&efw->lock, flags);
if (up) - amdtp_stream_midi_trigger(&efw->rx_stream, - substrm->number, substrm); + amdtp_am824_midi_trigger(&efw->rx_stream, + substrm->number, substrm); else - amdtp_stream_midi_trigger(&efw->rx_stream, - substrm->number, NULL); + amdtp_am824_midi_trigger(&efw->rx_stream, + substrm->number, NULL);
spin_unlock_irqrestore(&efw->lock, flags); } diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 540a303..37a86cf 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -90,11 +90,11 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&oxfw->lock, flags);
if (up) - amdtp_stream_midi_trigger(&oxfw->tx_stream, - substrm->number, substrm); + amdtp_am824_midi_trigger(&oxfw->tx_stream, + substrm->number, substrm); else - amdtp_stream_midi_trigger(&oxfw->tx_stream, - substrm->number, NULL); + amdtp_am824_midi_trigger(&oxfw->tx_stream, + substrm->number, NULL);
spin_unlock_irqrestore(&oxfw->lock, flags); } @@ -107,11 +107,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_lock_irqsave(&oxfw->lock, flags);
if (up) - amdtp_stream_midi_trigger(&oxfw->rx_stream, - substrm->number, substrm); + amdtp_am824_midi_trigger(&oxfw->rx_stream, + substrm->number, substrm); else - amdtp_stream_midi_trigger(&oxfw->rx_stream, - substrm->number, NULL); + amdtp_am824_midi_trigger(&oxfw->rx_stream, + substrm->number, NULL);
spin_unlock_irqrestore(&oxfw->lock, flags); }
Setting the format of PCM substream to AMDTP stream structure is important to set a handler to copy actual PCM samples between buffers. The processing should be in data block processing layer because essentially it has no relationship to packet streaming.
This commit renames PCM format setting function to prepare for integrating AM824 layer.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 7 +++---- sound/firewire/amdtp-stream.h | 4 ++-- sound/firewire/bebob/bebob_pcm.c | 8 ++++---- sound/firewire/dice/dice-pcm.c | 6 ++---- sound/firewire/fireworks/fireworks_pcm.c | 6 ++++-- sound/firewire/oxfw/oxfw-pcm.c | 4 ++-- 6 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 06fbf23..cc640cd 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -272,7 +272,7 @@ static void read_pcm_s32(struct amdtp_stream *s, __be32 *buffer, unsigned int frames);
/** - * amdtp_stream_set_pcm_format - set the PCM format + * amdtp_am824_set_pcm_format - set the PCM format * @s: the AMDTP stream to configure * @format: the format of the ALSA PCM device * @@ -280,8 +280,7 @@ static void read_pcm_s32(struct amdtp_stream *s, * MIDI) and before the stream is started, and must not be changed while the * stream is running. */ -void amdtp_stream_set_pcm_format(struct amdtp_stream *s, - snd_pcm_format_t format) +void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format) { if (WARN_ON(amdtp_stream_pcm_running(s))) return; @@ -305,7 +304,7 @@ void amdtp_stream_set_pcm_format(struct amdtp_stream *s, break; } } -EXPORT_SYMBOL(amdtp_stream_set_pcm_format); +EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format);
/** * amdtp_stream_pcm_prepare - prepare PCM device for running diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 984f02a..3fb82c7 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -190,8 +190,8 @@ void amdtp_stream_stop(struct amdtp_stream *s);
int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); -void amdtp_stream_set_pcm_format(struct amdtp_stream *s, - snd_pcm_format_t format); +void amdtp_am824_set_pcm_format(struct amdtp_stream *s, + snd_pcm_format_t format); void amdtp_stream_pcm_prepare(struct amdtp_stream *s); unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s); void amdtp_stream_pcm_abort(struct amdtp_stream *s); diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 50610ca..8d8de4c 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -220,8 +220,8 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&bebob->substreams_counter); - amdtp_stream_set_pcm_format(&bebob->tx_stream, - params_format(hw_params)); + + amdtp_am824_set_pcm_format(&bebob->tx_stream, params_format(hw_params));
return 0; } @@ -239,8 +239,8 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&bebob->substreams_counter); - amdtp_stream_set_pcm_format(&bebob->rx_stream, - params_format(hw_params)); + + amdtp_am824_set_pcm_format(&bebob->rx_stream, params_format(hw_params));
return 0; } diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index f5f3007..8cbcd5d 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -243,8 +243,7 @@ static int capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&dice->mutex); }
- amdtp_stream_set_pcm_format(&dice->tx_stream, - params_format(hw_params)); + amdtp_am824_set_pcm_format(&dice->tx_stream, params_format(hw_params));
return 0; } @@ -265,8 +264,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&dice->mutex); }
- amdtp_stream_set_pcm_format(&dice->rx_stream, - params_format(hw_params)); + amdtp_am824_set_pcm_format(&dice->rx_stream, params_format(hw_params));
return 0; } diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index f186ab7..109fb1b 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -253,7 +253,8 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&efw->capture_substreams); - amdtp_stream_set_pcm_format(&efw->tx_stream, params_format(hw_params)); + + amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params));
return 0; } @@ -270,7 +271,8 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&efw->playback_substreams); - amdtp_stream_set_pcm_format(&efw->rx_stream, params_format(hw_params)); + + amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params));
return 0; } diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index bddd287..217fe37 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -244,7 +244,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&oxfw->mutex); }
- amdtp_stream_set_pcm_format(&oxfw->tx_stream, params_format(hw_params)); + amdtp_am824_set_pcm_format(&oxfw->tx_stream, params_format(hw_params));
return 0; } @@ -265,7 +265,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&oxfw->mutex); }
- amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params)); + amdtp_am824_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
return 0; }
This commit renames some macros just related to AM824 format. In later commit, they're moved to AM824 layer.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 4 ++-- sound/firewire/amdtp-stream.h | 14 +++++++------- sound/firewire/bebob/bebob_pcm.c | 4 ++-- sound/firewire/bebob/bebob_stream.c | 6 +++--- sound/firewire/dice/dice-pcm.c | 4 ++-- sound/firewire/fireworks/fireworks.c | 12 ++++++------ sound/firewire/fireworks/fireworks_pcm.c | 4 ++-- sound/firewire/oxfw/oxfw-pcm.c | 4 ++-- sound/firewire/oxfw/oxfw-stream.c | 4 ++-- 9 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index cc640cd..e677b05 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -202,8 +202,8 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, midi_channels = DIV_ROUND_UP(midi_ports, 8);
if (WARN_ON(amdtp_stream_running(s)) | - WARN_ON(pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM) | - WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI)) + WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) | + WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)) return -EINVAL;
for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc) { diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 3fb82c7..71f4f75 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -81,9 +81,9 @@ enum cip_sfc { CIP_SFC_COUNT };
-#define AMDTP_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32 +#define AM824_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32
-#define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ +#define AM824_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ SNDRV_PCM_FMTBIT_S32)
@@ -91,7 +91,7 @@ enum cip_sfc { * This module supports maximum 64 PCM channels for one PCM stream * This is for our convenience. */ -#define AMDTP_MAX_CHANNELS_FOR_PCM 64 +#define AM824_MAX_CHANNELS_FOR_PCM 64
/* * AMDTP packet can include channels for MIDI conformant data. @@ -101,7 +101,7 @@ enum cip_sfc { * This module supports maximum 1 MIDI conformant data channels. * Then this AMDTP packets can transfer maximum 8 MIDI data streams. */ -#define AMDTP_MAX_CHANNELS_FOR_MIDI 1 +#define AM824_MAX_CHANNELS_FOR_MIDI 1
struct fw_unit; struct fw_iso_context; @@ -157,13 +157,13 @@ struct amdtp_stream { struct amdtp_stream *sync_slave;
/* For AM824 processing. */ - struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; + struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8]; int midi_fifo_limit; - int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; + int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8]; unsigned int pcm_channels; unsigned int midi_ports;
- u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM]; + u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM]; u8 midi_position;
void (*transfer_samples)(struct amdtp_stream *s, diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 8d8de4c..2fdc1f1 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -122,11 +122,11 @@ pcm_init_hw_params(struct snd_bebob *bebob, SNDRV_PCM_INFO_MMAP_VALID;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS; + runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; s = &bebob->tx_stream; formations = bebob->tx_stream_formations; } else { - runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS; + runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS; s = &bebob->rx_stream; formations = bebob->rx_stream_formations; } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index cf6402d..a2baa47 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -354,7 +354,7 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) case 0x09: /* Digital */ default: location = pcm + sec_loc; - if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) { + if (location >= AM824_MAX_CHANNELS_FOR_PCM) { err = -ENOSYS; goto end; } @@ -872,8 +872,8 @@ parse_stream_formation(u8 *buf, unsigned int len, } }
- if (formation[i].pcm > AMDTP_MAX_CHANNELS_FOR_PCM || - formation[i].midi > AMDTP_MAX_CHANNELS_FOR_MIDI) + if (formation[i].pcm > AM824_MAX_CHANNELS_FOR_PCM || + formation[i].midi > AM824_MAX_CHANNELS_FOR_MIDI) return -ENOSYS;
return 0; diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 8cbcd5d..9b34319 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -133,11 +133,11 @@ static int init_hw_info(struct snd_dice *dice, SNDRV_PCM_INFO_BLOCK_TRANSFER;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - hw->formats = AMDTP_IN_PCM_FORMAT_BITS; + hw->formats = AM824_IN_PCM_FORMAT_BITS; stream = &dice->tx_stream; pcm_channels = dice->tx_channels; } else { - hw->formats = AMDTP_OUT_PCM_FORMAT_BITS; + hw->formats = AM824_OUT_PCM_FORMAT_BITS; stream = &dice->rx_stream; pcm_channels = dice->rx_channels; } diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index c94a432..d5b19bc 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -138,12 +138,12 @@ get_hardware_info(struct snd_efw *efw) efw->midi_out_ports = hwinfo->midi_out_ports; efw->midi_in_ports = hwinfo->midi_in_ports;
- if (hwinfo->amdtp_tx_pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM || - hwinfo->amdtp_tx_pcm_channels_2x > AMDTP_MAX_CHANNELS_FOR_PCM || - hwinfo->amdtp_tx_pcm_channels_4x > AMDTP_MAX_CHANNELS_FOR_PCM || - hwinfo->amdtp_rx_pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM || - hwinfo->amdtp_rx_pcm_channels_2x > AMDTP_MAX_CHANNELS_FOR_PCM || - hwinfo->amdtp_rx_pcm_channels_4x > AMDTP_MAX_CHANNELS_FOR_PCM) { + if (hwinfo->amdtp_tx_pcm_channels > AM824_MAX_CHANNELS_FOR_PCM || + hwinfo->amdtp_tx_pcm_channels_2x > AM824_MAX_CHANNELS_FOR_PCM || + hwinfo->amdtp_tx_pcm_channels_4x > AM824_MAX_CHANNELS_FOR_PCM || + hwinfo->amdtp_rx_pcm_channels > AM824_MAX_CHANNELS_FOR_PCM || + hwinfo->amdtp_rx_pcm_channels_2x > AM824_MAX_CHANNELS_FOR_PCM || + hwinfo->amdtp_rx_pcm_channels_4x > AM824_MAX_CHANNELS_FOR_PCM) { err = -ENOSYS; goto end; } diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 109fb1b..d27135b 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -159,11 +159,11 @@ pcm_init_hw_params(struct snd_efw *efw, SNDRV_PCM_INFO_MMAP_VALID;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS; + runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; s = &efw->tx_stream; pcm_channels = efw->pcm_capture_channels; } else { - runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS; + runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS; s = &efw->rx_stream; pcm_channels = efw->pcm_playback_channels; } diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 217fe37..8d23341 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -134,11 +134,11 @@ static int init_hw_params(struct snd_oxfw *oxfw, SNDRV_PCM_INFO_MMAP_VALID;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS; + runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; stream = &oxfw->tx_stream; formats = oxfw->tx_stream_formats; } else { - runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS; + runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS; stream = &oxfw->rx_stream; formats = oxfw->rx_stream_formats; } diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 4982bef..0c40c00 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -483,8 +483,8 @@ int snd_oxfw_stream_parse_format(u8 *format, } }
- if (formation->pcm > AMDTP_MAX_CHANNELS_FOR_PCM || - formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI) + if (formation->pcm > AM824_MAX_CHANNELS_FOR_PCM || + formation->midi > AM824_MAX_CHANNELS_FOR_MIDI) return -ENOSYS;
return 0;
This commit moves the codes related to data block processing from packet streaming layer to AM824 layer.
Each driver initializes amdtp stream structure for AM824 data block by calling amdtp_am824_init(). Then, a memory block is allocated for AM824 specific structure. This memory block is released by calling amdtp_stream_destroy().
When setting streaming parameters, it calls amdtp_am824_set_parameters(). When starting packet streaming, it calls amdtp_stream_start(). When stopping packet streaming, it calls amdtp_stream_stop().
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-am824.c | 349 ++++++++++++++++++++++++++++++++++++++++-- sound/firewire/amdtp-am824.h | 24 +++ sound/firewire/amdtp-stream.c | 316 +++----------------------------------- sound/firewire/amdtp-stream.h | 62 ++------ 4 files changed, 401 insertions(+), 350 deletions(-)
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 540a101..945b471 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -1,11 +1,14 @@ /* * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6) * + * Copyright (c) Clemens Ladisch clemens@ladisch.de * Copyright (c) 2015 Takashi Sakamoto o-takashi@sakamocchi.jp * * Licensed under the terms of the GNU General Public License, version 2. */
+#include <linux/slab.h> + #include "amdtp-am824.h"
#define CIP_FMT_AM 0x10 @@ -13,6 +16,35 @@ /* "Clock-based rate control mode" is just supported. */ #define AMDTP_FDF_AM824 0x00
+/* + * Nominally 3125 bytes/second, but the MIDI port's clock might be + * 1% too slow, and the bus clock 100 ppm too fast. + */ +#define MIDI_BYTES_PER_SECOND 3093 + +/* + * Several devices look only at the first eight data blocks. + * In any case, this is more than enough for the MIDI data rate. + */ +#define MAX_MIDI_RX_BLOCKS 8 + +struct amdtp_am824 { + struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8]; + int midi_fifo_limit; + int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8]; + unsigned int pcm_channels; + unsigned int midi_ports; + + u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM]; + u8 midi_position; + + void (*transfer_samples)(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames); + + unsigned int frame_multiplier; +}; + /** * amdtp_am824_set_parameters - set stream parameters * @s: the AMDTP stream to configure @@ -30,23 +62,58 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int midi_ports, bool double_pcm_frames) { + struct amdtp_am824 *p = s->protocol; + unsigned int midi_channels; + unsigned int i; int err;
- err = amdtp_stream_set_parameters(s, rate, pcm_channels, midi_ports); + if (amdtp_stream_running(s)) + return -EINVAL; + + if (pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) + return -EINVAL; + + midi_channels = DIV_ROUND_UP(midi_ports, 8); + if (midi_channels > AM824_MAX_CHANNELS_FOR_MIDI) + return -EINVAL; + + if (WARN_ON(amdtp_stream_running(s)) | + WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) | + WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)) + return -EINVAL; + + err = amdtp_stream_set_parameters(s, rate, + pcm_channels + midi_channels); if (err < 0) return err;
s->fdf = AMDTP_FDF_AM824 | s->sfc;
+ p->pcm_channels = pcm_channels; + p->midi_ports = midi_ports; + /* * In IEC 61883-6, one data block represents one event. In ALSA, one * event equals to one PCM frame. But Dice has a quirk at higher * sampling rate to transfer two PCM frames in one data block. */ if (double_pcm_frames) - s->frame_multiplier = 2; + p->frame_multiplier = 2; else - s->frame_multiplier = 1; + p->frame_multiplier = 1; + + /* init the position map for PCM and MIDI channels */ + for (i = 0; i < pcm_channels; i++) + p->pcm_positions[i] = i; + p->midi_position = p->pcm_channels; + + /* + * We do not know the actual MIDI FIFO size of most devices. Just + * assume two bytes, i.e., one byte can be received over the bus while + * the previous one is transmitted over MIDI. + * (The value here is adjusted for midi_ratelimit_per_packet().) + */ + p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
return 0; } @@ -62,8 +129,10 @@ EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters); void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index, unsigned int position) { - if (index < s->pcm_channels) - s->pcm_positions[index] = position; + struct amdtp_am824 *p = s->protocol; + + if (index < p->pcm_channels) + p->pcm_positions[index] = position; } EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position);
@@ -76,10 +145,139 @@ EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position); void amdtp_am824_set_midi_position(struct amdtp_stream *s, unsigned int position) { - s->midi_position = position; + struct amdtp_am824 *p = s->protocol; + + p->midi_position = position; } EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position);
+static void write_pcm_s32(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames) +{ + struct amdtp_am824 *p = s->protocol; + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int channels, remaining_frames, i, c; + const u32 *src; + + channels = p->pcm_channels; + src = (void *)runtime->dma_area + + frames_to_bytes(runtime, s->pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + + for (i = 0; i < frames; ++i) { + for (c = 0; c < channels; ++c) { + buffer[p->pcm_positions[c]] = + cpu_to_be32((*src >> 8) | 0x40000000); + src++; + } + buffer += s->data_block_quadlets; + if (--remaining_frames == 0) + src = (void *)runtime->dma_area; + } +} + +static void write_pcm_s16(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames) +{ + struct amdtp_am824 *p = s->protocol; + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int channels, remaining_frames, i, c; + const u16 *src; + + channels = p->pcm_channels; + src = (void *)runtime->dma_area + + frames_to_bytes(runtime, s->pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + + for (i = 0; i < frames; ++i) { + for (c = 0; c < channels; ++c) { + buffer[p->pcm_positions[c]] = + cpu_to_be32((*src << 8) | 0x42000000); + src++; + } + buffer += s->data_block_quadlets; + if (--remaining_frames == 0) + src = (void *)runtime->dma_area; + } +} + +static void read_pcm_s32(struct amdtp_stream *s, + struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames) +{ + struct amdtp_am824 *p = s->protocol; + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int channels, remaining_frames, i, c; + u32 *dst; + + channels = p->pcm_channels; + dst = (void *)runtime->dma_area + + frames_to_bytes(runtime, s->pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + + for (i = 0; i < frames; ++i) { + for (c = 0; c < channels; ++c) { + *dst = be32_to_cpu(buffer[p->pcm_positions[c]]) << 8; + dst++; + } + buffer += s->data_block_quadlets; + if (--remaining_frames == 0) + dst = (void *)runtime->dma_area; + } +} + +static void write_pcm_silence(struct amdtp_stream *s, + __be32 *buffer, unsigned int frames) +{ + struct amdtp_am824 *p = s->protocol; + unsigned int i, c, channels = p->pcm_channels; + + for (i = 0; i < frames; ++i) { + for (c = 0; c < channels; ++c) + buffer[p->pcm_positions[c]] = cpu_to_be32(0x40000000); + buffer += s->data_block_quadlets; + } +} + +/** + * amdtp_am824_set_pcm_format - set the PCM format + * @s: the AMDTP stream to configure + * @format: the format of the ALSA PCM device + * + * The sample format must be set after the other parameters (rate/PCM channels/ + * MIDI) and before the stream is started, and must not be changed while the + * stream is running. + */ +void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format) +{ + struct amdtp_am824 *p = s->protocol; + + if (WARN_ON(amdtp_stream_pcm_running(s))) + return; + + switch (format) { + default: + WARN_ON(1); + /* fall through */ + case SNDRV_PCM_FORMAT_S16: + if (s->direction == AMDTP_OUT_STREAM) { + p->transfer_samples = write_pcm_s16; + break; + } + WARN_ON(1); + /* fall through */ + case SNDRV_PCM_FORMAT_S32: + if (s->direction == AMDTP_OUT_STREAM) + p->transfer_samples = write_pcm_s32; + else + p->transfer_samples = read_pcm_s32; + break; + } +} +EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format); + /** * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream * @s: the AMDTP stream for AM824 data block, must be initialized. @@ -113,11 +311,135 @@ EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints); void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, struct snd_rawmidi_substream *midi) { - if (port < s->midi_ports) - ACCESS_ONCE(s->midi[port]) = midi; + struct amdtp_am824 *p = s->protocol; + + if (port < p->midi_ports) + ACCESS_ONCE(p->midi[port]) = midi; } EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger);
+/* + * To avoid sending MIDI bytes at too high a rate, assume that the receiving + * device has a FIFO, and track how much it is filled. This values increases + * by one whenever we send one byte in a packet, but the FIFO empties at + * a constant rate independent of our packet rate. One packet has syt_interval + * samples, so the number of bytes that empty out of the FIFO, per packet(!), + * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate. To avoid storing + * fractional values, the values in midi_fifo_used[] are measured in bytes + * multiplied by the sample rate. + */ +static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) +{ + struct amdtp_am824 *p = s->protocol; + int used; + + used = p->midi_fifo_used[port]; + if (used == 0) /* common shortcut */ + return true; + + used -= MIDI_BYTES_PER_SECOND * s->syt_interval; + used = max(used, 0); + p->midi_fifo_used[port] = used; + + return used < p->midi_fifo_limit; +} + +static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) +{ + struct amdtp_am824 *p = s->protocol; + + p->midi_fifo_used[port] += amdtp_rate_table[s->sfc]; +} + +static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, + unsigned int frames) +{ + struct amdtp_am824 *p = s->protocol; + unsigned int f, port; + u8 *b; + + for (f = 0; f < frames; f++) { + b = (u8 *)&buffer[p->midi_position]; + + port = (s->data_block_counter + f) % 8; + if (f < MAX_MIDI_RX_BLOCKS && + midi_ratelimit_per_packet(s, port) && + p->midi[port] != NULL && + snd_rawmidi_transmit(p->midi[port], &b[1], 1) == 1) { + midi_rate_use_one_byte(s, port); + b[0] = 0x81; + } else { + b[0] = 0x80; + b[1] = 0; + } + b[2] = 0; + b[3] = 0; + + buffer += s->data_block_quadlets; + } +} + +static void read_midi_messages(struct amdtp_stream *s, + __be32 *buffer, unsigned int frames) +{ + struct amdtp_am824 *p = s->protocol; + unsigned int f, port; + int len; + u8 *b; + + for (f = 0; f < frames; f++) { + port = (s->data_block_counter + f) % 8; + b = (u8 *)&buffer[p->midi_position]; + + len = b[0] - 0x80; + if ((1 <= len) && (len <= 3) && (p->midi[port])) + snd_rawmidi_receive(p->midi[port], b + 1, len); + + buffer += s->data_block_quadlets; + } +} + +unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, + unsigned int data_blocks, unsigned int *syt) +{ + struct amdtp_am824 *p = s->protocol; + struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + unsigned int pcm_frames; + + if (pcm) { + p->transfer_samples(s, pcm, buffer, data_blocks); + pcm_frames = data_blocks * p->frame_multiplier; + } else { + write_pcm_silence(s, buffer, data_blocks); + pcm_frames = 0; + } + + if (p->midi_ports) + write_midi_messages(s, buffer, data_blocks); + + return pcm_frames; +} + +unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, + unsigned int data_blocks, unsigned int *syt) +{ + struct amdtp_am824 *p = s->protocol; + struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + unsigned int pcm_frames; + + if (pcm) { + p->transfer_samples(s, pcm, buffer, data_blocks); + pcm_frames = data_blocks * p->frame_multiplier; + } else { + pcm_frames = 0; + } + + if (p->midi_ports) + read_midi_messages(s, buffer, data_blocks); + + return pcm_frames; +} + /** * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824 * data block @@ -129,6 +451,15 @@ EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger); int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags) { - return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM); + amdtp_stream_process_data_blocks_t process_data_blocks; + + if (dir == AMDTP_IN_STREAM) + process_data_blocks = process_tx_data_blocks; + else + process_data_blocks = process_rx_data_blocks; + + return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, + process_data_blocks, + sizeof(struct amdtp_am824)); } EXPORT_SYMBOL_GPL(amdtp_am824_init); diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index 65e6093..73b07b3 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -6,6 +6,27 @@
#include "amdtp-stream.h"
+#define AM824_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32 + +#define AM824_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ + SNDRV_PCM_FMTBIT_S32) + +/* + * This module supports maximum 64 PCM channels for one PCM stream + * This is for our convenience. + */ +#define AM824_MAX_CHANNELS_FOR_PCM 64 + +/* + * AMDTP packet can include channels for MIDI conformant data. + * Each MIDI conformant data channel includes 8 MPX-MIDI data stream. + * Each MPX-MIDI data stream includes one data stream from/to MIDI ports. + * + * This module supports maximum 1 MIDI conformant data channels. + * Then this AMDTP packets can transfer maximum 8 MIDI data streams. + */ +#define AM824_MAX_CHANNELS_FOR_MIDI 1 + int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int pcm_channels, unsigned int midi_ports, @@ -20,6 +41,9 @@ void amdtp_am824_set_midi_position(struct amdtp_stream *s, int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime);
+void amdtp_am824_set_pcm_format(struct amdtp_stream *s, + snd_pcm_format_t format); + void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, struct snd_rawmidi_substream *midi);
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index e677b05..fa10b58 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -13,25 +13,12 @@ #include <linux/slab.h> #include <sound/pcm.h> #include <sound/pcm_params.h> -#include <sound/rawmidi.h> #include "amdtp-stream.h"
#define TICKS_PER_CYCLE 3072 #define CYCLES_PER_SECOND 8000 #define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
-/* - * Nominally 3125 bytes/second, but the MIDI port's clock might be - * 1% too slow, and the bus clock 100 ppm too fast. - */ -#define MIDI_BYTES_PER_SECOND 3093 - -/* - * Several devices look only at the first eight data blocks. - * In any case, this is more than enough for the MIDI data rate. - */ -#define MAX_MIDI_RX_BLOCKS 8 - #define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 microseconds */
/* isochronous header parameters */ @@ -74,11 +61,22 @@ static void pcm_period_tasklet(unsigned long data); * @dir: the direction of stream * @flags: the packet transmission method to use * @fmt: the value of fmt field in CIP header + * @process_data_blocks: callback handler to process data blocks + * @protocol_size: the size to allocate newly for protocol */ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags, - unsigned int fmt) + unsigned int fmt, + amdtp_stream_process_data_blocks_t process_data_blocks, + unsigned int protocol_size) { + if (process_data_blocks == NULL) + return -EINVAL; + + s->protocol = kzalloc(protocol_size, GFP_KERNEL); + if (!s->protocol) + return -ENOMEM; + s->unit = unit; s->direction = dir; s->flags = flags; @@ -92,6 +90,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->sync_slave = NULL;
s->fmt = fmt; + s->process_data_blocks = process_data_blocks;
return 0; } @@ -104,6 +103,7 @@ EXPORT_SYMBOL(amdtp_stream_init); void amdtp_stream_destroy(struct amdtp_stream *s) { WARN_ON(amdtp_stream_running(s)); + kfree(s->protocol); mutex_destroy(&s->mutex); } EXPORT_SYMBOL(amdtp_stream_destroy); @@ -184,27 +184,15 @@ EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints); * amdtp_stream_set_parameters - set stream parameters * @s: the AMDTP stream to configure * @rate: the sample rate - * @pcm_channels: the number of PCM samples in each data block, to be encoded - * as AM824 multi-bit linear audio - * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) - * @double_pcm_frames: one data block transfers two PCM frames + * @data_block_quadlets: the size of a data block in quadlet unit * * The parameters must be set before the stream is started, and must not be * changed while the stream is running. */ -int amdtp_stream_set_parameters(struct amdtp_stream *s, - unsigned int rate, - unsigned int pcm_channels, - unsigned int midi_ports) +int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, + unsigned int data_block_quadlets) { - unsigned int i, sfc, midi_channels; - - midi_channels = DIV_ROUND_UP(midi_ports, 8); - - if (WARN_ON(amdtp_stream_running(s)) | - WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) | - WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)) - return -EINVAL; + unsigned int sfc;
for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc) { if (amdtp_rate_table[sfc] == rate) @@ -213,11 +201,8 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, if (sfc == ARRAY_SIZE(amdtp_rate_table)) return -EINVAL;
- s->pcm_channels = pcm_channels; s->sfc = sfc; - s->data_block_quadlets = s->pcm_channels + midi_channels; - s->midi_ports = midi_ports; - + s->data_block_quadlets = data_block_quadlets; s->syt_interval = amdtp_syt_intervals[sfc];
/* default buffering in the device */ @@ -226,19 +211,6 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, /* additional buffering needed to adjust for no-data packets */ s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
- /* init the position map for PCM and MIDI channels */ - for (i = 0; i < pcm_channels; i++) - s->pcm_positions[i] = i; - s->midi_position = s->pcm_channels; - - /* - * We do not know the actual MIDI FIFO size of most devices. Just - * assume two bytes, i.e., one byte can be received over the bus while - * the previous one is transmitted over MIDI. - * (The value here is adjusted for midi_ratelimit_per_packet().) - */ - s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; - return 0; } EXPORT_SYMBOL(amdtp_stream_set_parameters); @@ -261,51 +233,6 @@ unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s) } EXPORT_SYMBOL(amdtp_stream_get_max_payload);
-static void write_pcm_s16(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); -static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); - -/** - * amdtp_am824_set_pcm_format - set the PCM format - * @s: the AMDTP stream to configure - * @format: the format of the ALSA PCM device - * - * The sample format must be set after the other parameters (rate/PCM channels/ - * MIDI) and before the stream is started, and must not be changed while the - * stream is running. - */ -void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format) -{ - if (WARN_ON(amdtp_stream_pcm_running(s))) - return; - - switch (format) { - default: - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S16: - if (s->direction == AMDTP_OUT_STREAM) { - s->transfer_samples = write_pcm_s16; - break; - } - WARN_ON(1); - /* fall through */ - case SNDRV_PCM_FORMAT_S32: - if (s->direction == AMDTP_OUT_STREAM) - s->transfer_samples = write_pcm_s32; - else - s->transfer_samples = read_pcm_s32; - break; - } -} -EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format); - /** * amdtp_stream_pcm_prepare - prepare PCM device for running * @s: the AMDTP stream @@ -408,168 +335,6 @@ static unsigned int calculate_syt(struct amdtp_stream *s, } }
-static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; - const u32 *src; - - channels = s->pcm_channels; - src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - buffer[s->pcm_positions[c]] = - cpu_to_be32((*src >> 8) | 0x40000000); - src++; - } - buffer += s->data_block_quadlets; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - -static void write_pcm_s16(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; - const u16 *src; - - channels = s->pcm_channels; - src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - buffer[s->pcm_positions[c]] = - cpu_to_be32((*src << 8) | 0x42000000); - src++; - } - buffer += s->data_block_quadlets; - if (--remaining_frames == 0) - src = (void *)runtime->dma_area; - } -} - -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) -{ - struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; - u32 *dst; - - channels = s->pcm_channels; - dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < channels; ++c) { - *dst = be32_to_cpu(buffer[s->pcm_positions[c]]) << 8; - dst++; - } - buffer += s->data_block_quadlets; - if (--remaining_frames == 0) - dst = (void *)runtime->dma_area; - } -} - -static void write_pcm_silence(struct amdtp_stream *s, - __be32 *buffer, unsigned int frames) -{ - unsigned int i, c; - - for (i = 0; i < frames; ++i) { - for (c = 0; c < s->pcm_channels; ++c) - buffer[s->pcm_positions[c]] = cpu_to_be32(0x40000000); - buffer += s->data_block_quadlets; - } -} - -/* - * To avoid sending MIDI bytes at too high a rate, assume that the receiving - * device has a FIFO, and track how much it is filled. This values increases - * by one whenever we send one byte in a packet, but the FIFO empties at - * a constant rate independent of our packet rate. One packet has syt_interval - * samples, so the number of bytes that empty out of the FIFO, per packet(!), - * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate. To avoid storing - * fractional values, the values in midi_fifo_used[] are measured in bytes - * multiplied by the sample rate. - */ -static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) -{ - int used; - - used = s->midi_fifo_used[port]; - if (used == 0) /* common shortcut */ - return true; - - used -= MIDI_BYTES_PER_SECOND * s->syt_interval; - used = max(used, 0); - s->midi_fifo_used[port] = used; - - return used < s->midi_fifo_limit; -} - -static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) -{ - s->midi_fifo_used[port] += amdtp_rate_table[s->sfc]; -} - -static void write_midi_messages(struct amdtp_stream *s, - __be32 *buffer, unsigned int frames) -{ - unsigned int f, port; - u8 *b; - - for (f = 0; f < frames; f++) { - b = (u8 *)&buffer[s->midi_position]; - - port = (s->data_block_counter + f) % 8; - if (f < MAX_MIDI_RX_BLOCKS && - midi_ratelimit_per_packet(s, port) && - s->midi[port] != NULL && - snd_rawmidi_transmit(s->midi[port], &b[1], 1) == 1) { - midi_rate_use_one_byte(s, port); - b[0] = 0x81; - } else { - b[0] = 0x80; - b[1] = 0; - } - b[2] = 0; - b[3] = 0; - - buffer += s->data_block_quadlets; - } -} - -static void read_midi_messages(struct amdtp_stream *s, - __be32 *buffer, unsigned int frames) -{ - unsigned int f, port; - int len; - u8 *b; - - for (f = 0; f < frames; f++) { - port = (s->data_block_counter + f) % 8; - b = (u8 *)&buffer[s->midi_position]; - - len = b[0] - 0x80; - if ((1 <= len) && (len <= 3) && (s->midi[port])) - snd_rawmidi_receive(s->midi[port], b + 1, len); - - buffer += s->data_block_quadlets; - } -} - static void update_pcm_pointers(struct amdtp_stream *s, struct snd_pcm_substream *pcm, unsigned int frames) @@ -639,26 +404,6 @@ static inline int queue_in_packet(struct amdtp_stream *s) amdtp_stream_get_max_payload(s), false); }
-unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) -{ - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); - unsigned int pcm_frames; - - if (pcm) { - s->transfer_samples(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * s->frame_multiplier; - } else { - write_pcm_silence(s, buffer, data_blocks); - pcm_frames = 0; - } - - if (s->midi_ports) - write_midi_messages(s, buffer, data_blocks); - - return pcm_frames; -} - static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, unsigned int syt) { @@ -668,7 +413,7 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, struct snd_pcm_substream *pcm;
buffer = s->buffer.packets[s->packet_index].buffer; - pcm_frames = process_rx_data_blocks(s, buffer + 2, data_blocks, &syt); + pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | @@ -692,25 +437,6 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, return 0; }
-unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) -{ - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); - unsigned int pcm_frames; - - if (pcm) { - s->transfer_samples(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * s->frame_multiplier; - } else { - pcm_frames = 0; - } - - if (s->midi_ports) - read_midi_messages(s, buffer, data_blocks); - - return pcm_frames; -} - static int handle_in_packet(struct amdtp_stream *s, unsigned int payload_quadlets, __be32 *buffer, unsigned int *data_blocks, unsigned int syt) @@ -798,7 +524,7 @@ static int handle_in_packet(struct amdtp_stream *s, return -EIO; }
- pcm_frames = process_tx_data_blocks(s, buffer + 2, *data_blocks, &syt); + pcm_frames = s->process_data_blocks(s, buffer + 2, *data_blocks, &syt);
if (s->flags & CIP_DBC_IS_END_EVENT) s->data_block_counter = data_block_counter; diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 71f4f75..8775704 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -81,39 +81,22 @@ enum cip_sfc { CIP_SFC_COUNT };
-#define AM824_IN_PCM_FORMAT_BITS SNDRV_PCM_FMTBIT_S32 - -#define AM824_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ - SNDRV_PCM_FMTBIT_S32) - - -/* - * This module supports maximum 64 PCM channels for one PCM stream - * This is for our convenience. - */ -#define AM824_MAX_CHANNELS_FOR_PCM 64 - -/* - * AMDTP packet can include channels for MIDI conformant data. - * Each MIDI conformant data channel includes 8 MPX-MIDI data stream. - * Each MPX-MIDI data stream includes one data stream from/to MIDI ports. - * - * This module supports maximum 1 MIDI conformant data channels. - * Then this AMDTP packets can transfer maximum 8 MIDI data streams. - */ -#define AM824_MAX_CHANNELS_FOR_MIDI 1 - struct fw_unit; struct fw_iso_context; struct snd_pcm_substream; struct snd_pcm_runtime; -struct snd_rawmidi_substream;
enum amdtp_stream_direction { AMDTP_OUT_STREAM = 0, AMDTP_IN_STREAM };
+struct amdtp_stream; +typedef unsigned int (*amdtp_stream_process_data_blocks_t)( + struct amdtp_stream *s, + __be32 *buffer, + unsigned int data_blocks, + unsigned int *syt); struct amdtp_stream { struct fw_unit *unit; enum cip_flags flags; @@ -156,32 +139,20 @@ struct amdtp_stream { wait_queue_head_t callback_wait; struct amdtp_stream *sync_slave;
- /* For AM824 processing. */ - struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8]; - int midi_fifo_limit; - int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8]; - unsigned int pcm_channels; - unsigned int midi_ports; - - u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM]; - u8 midi_position; - - void (*transfer_samples)(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames); - - unsigned int frame_multiplier; + /* For backends to process data blocks. */ + void *protocol; + amdtp_stream_process_data_blocks_t process_data_blocks; };
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, - enum cip_flags flags, unsigned int fmt); + enum amdtp_stream_direction dir, enum cip_flags flags, + unsigned int fmt, + amdtp_stream_process_data_blocks_t process_data_blocks, + unsigned int protocol_size); void amdtp_stream_destroy(struct amdtp_stream *s);
-int amdtp_stream_set_parameters(struct amdtp_stream *s, - unsigned int rate, - unsigned int pcm_channels, - unsigned int midi_ports); +int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, + unsigned int data_block_quadlets); unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed); @@ -190,8 +161,7 @@ void amdtp_stream_stop(struct amdtp_stream *s);
int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); -void amdtp_am824_set_pcm_format(struct amdtp_stream *s, - snd_pcm_format_t format); + void amdtp_stream_pcm_prepare(struct amdtp_stream *s); unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s); void amdtp_stream_pcm_abort(struct amdtp_stream *s);
On Sat, 19 Sep 2015 04:21:47 +0200, Takashi Sakamoto wrote:
This patchset updates a part of my previous post (patch 01 and 02):
[alsa-devel] [PATCH 00/25 v2] ALSA: support AMDTP variants http://mailman.alsa-project.org/pipermail/alsa-devel/2015-August/096739.html
The aim of this patchset is to allow current amdtp implementation to handle several data block processing backends. For this aim, this patchset separates the implementation to packet streaming layer and AM824 data block processing layer.
The communication between these two layers is done by callback function. This patchset adds an overhead to call the functions as the same frequently as 8,000 times per second.
Since I'm traveling now, I can't review in details and will take a closer look in the next week. Hopefully other people will give review comments before that.
thanks,
Takashi
Takashi Sakamoto (15): ALSA: firewire-lib: arrange structure for AMDTP stream ALSA: firewire-lib: return error code when amdtp_stream_set_parameters() detects error ALSA: firewire-lib: add an argument for Dice's dual wire mode ALSA: firewire-lib: add a member of frame_multiplier instead of double_pcm_frames ALSA: firewire-lib: add helper functions as interfaces between packet streaming layer and data block processing layer ALSA: firewire-lib: add support arbitrary value for fmt/fdf fields in CIP header ALSA: firewire-lib: rename 'amdtp' to 'amdtp-stream' to prepare for functional separation ALSA: firewire-lib: add data block processing layer for AM824 format ALSA: firewire-lib: rename parameter setting function for AM824 with FDF field ALSA: firewire-lib: move PCM substream constraint to AM824 layer ALSA: firewire-lib: add helper functions to set positions of data channels ALSA: firewire-lib: move MIDI trigger helper function to AM824 layer ALSA: firewire-lib: rename PCM format helper function ALSA: firewire-lib: rename macros with AM824 prefix ALSA: firewire-lib: complete AM824 data block processing layer
sound/firewire/Makefile | 2 +- sound/firewire/amdtp-am824.c | 465 ++++++++++++++++++++++++++++ sound/firewire/amdtp-am824.h | 52 ++++ sound/firewire/{amdtp.c => amdtp-stream.c} | 377 ++++------------------ sound/firewire/{amdtp.h => amdtp-stream.h} | 116 +++---- sound/firewire/bebob/bebob.h | 2 +- sound/firewire/bebob/bebob_midi.c | 16 +- sound/firewire/bebob/bebob_pcm.c | 14 +- sound/firewire/bebob/bebob_stream.c | 34 +- sound/firewire/dice/dice-midi.c | 12 +- sound/firewire/dice/dice-pcm.c | 12 +- sound/firewire/dice/dice-stream.c | 22 +- sound/firewire/dice/dice.h | 2 +- sound/firewire/fcp.c | 2 +- sound/firewire/fireworks/fireworks.c | 12 +- sound/firewire/fireworks/fireworks.h | 2 +- sound/firewire/fireworks/fireworks_midi.c | 12 +- sound/firewire/fireworks/fireworks_pcm.c | 12 +- sound/firewire/fireworks/fireworks_stream.c | 8 +- sound/firewire/oxfw/oxfw-midi.c | 16 +- sound/firewire/oxfw/oxfw-pcm.c | 10 +- sound/firewire/oxfw/oxfw-stream.c | 11 +- sound/firewire/oxfw/oxfw.h | 2 +- 23 files changed, 730 insertions(+), 483 deletions(-) create mode 100644 sound/firewire/amdtp-am824.c create mode 100644 sound/firewire/amdtp-am824.h rename sound/firewire/{amdtp.c => amdtp-stream.c} (70%) rename sound/firewire/{amdtp.h => amdtp-stream.h} (78%)
-- 2.1.4
On Sat, 19 Sep 2015 18:46:53 +0200, Takashi Iwai wrote:
On Sat, 19 Sep 2015 04:21:47 +0200, Takashi Sakamoto wrote:
This patchset updates a part of my previous post (patch 01 and 02):
[alsa-devel] [PATCH 00/25 v2] ALSA: support AMDTP variants http://mailman.alsa-project.org/pipermail/alsa-devel/2015-August/096739.html
The aim of this patchset is to allow current amdtp implementation to handle several data block processing backends. For this aim, this patchset separates the implementation to packet streaming layer and AM824 data block processing layer.
The communication between these two layers is done by callback function. This patchset adds an overhead to call the functions as the same frequently as 8,000 times per second.
Since I'm traveling now, I can't review in details and will take a closer look in the next week. Hopefully other people will give review comments before that.
There were a few obvious typos (using bit OR instead of logical OR), but otherwise they look good through a quick review, so I merged them with some manual fixes now. The patches are found in topic/firewire-update branch and merged into for-next branch, too.
thanks,
Takashi
On Sep 29 2015 19:55, Takashi Iwai wrote:
On Sat, 19 Sep 2015 18:46:53 +0200, Takashi Iwai wrote:
On Sat, 19 Sep 2015 04:21:47 +0200, Takashi Sakamoto wrote:
This patchset updates a part of my previous post (patch 01 and 02):
[alsa-devel] [PATCH 00/25 v2] ALSA: support AMDTP variants http://mailman.alsa-project.org/pipermail/alsa-devel/2015-August/096739.html
The aim of this patchset is to allow current amdtp implementation to handle several data block processing backends. For this aim, this patchset separates the implementation to packet streaming layer and AM824 data block processing layer.
The communication between these two layers is done by callback function. This patchset adds an overhead to call the functions as the same frequently as 8,000 times per second.
Since I'm traveling now, I can't review in details and will take a closer look in the next week. Hopefully other people will give review comments before that.
There were a few obvious typos (using bit OR instead of logical OR), but otherwise they look good through a quick review, so I merged them with some manual fixes now. The patches are found in topic/firewire-update branch and merged into for-next branch, too.
Oops. Patch 15 includes such typos... Thanks for your reviewing and fixing ;-)
I have more patches and I'll post them as a small parts in this developing period. I'd be glad if the patches are also reviewd.
Thanks
Takashi Sakamoto
On Tue, 29 Sep 2015 14:45:00 +0200, Takashi Sakamoto wrote:
On Sep 29 2015 19:55, Takashi Iwai wrote:
On Sat, 19 Sep 2015 18:46:53 +0200, Takashi Iwai wrote:
On Sat, 19 Sep 2015 04:21:47 +0200, Takashi Sakamoto wrote:
This patchset updates a part of my previous post (patch 01 and 02):
[alsa-devel] [PATCH 00/25 v2] ALSA: support AMDTP variants http://mailman.alsa-project.org/pipermail/alsa-devel/2015-August/096739.html
The aim of this patchset is to allow current amdtp implementation to handle several data block processing backends. For this aim, this patchset separates the implementation to packet streaming layer and AM824 data block processing layer.
The communication between these two layers is done by callback function. This patchset adds an overhead to call the functions as the same frequently as 8,000 times per second.
Since I'm traveling now, I can't review in details and will take a closer look in the next week. Hopefully other people will give review comments before that.
There were a few obvious typos (using bit OR instead of logical OR), but otherwise they look good through a quick review, so I merged them with some manual fixes now. The patches are found in topic/firewire-update branch and merged into for-next branch, too.
Oops. Patch 15 includes such typos... Thanks for your reviewing and fixing ;-)
I have more patches and I'll post them as a small parts in this developing period. I'd be glad if the patches are also reviewd.
Sure, feel free to submit patches at any time. But I'll be traveling again in the next week for LCE and audio mini summit, so the review might be taken after that.
thanks,
Takashi
participants (2)
-
Takashi Iwai
-
Takashi Sakamoto