diff options
author | Takashi Iwai <tiwai@suse.de> | 2019-09-14 17:24:57 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2019-09-14 17:26:10 +0200 |
commit | d3f9990f1b48514b33342612b51fad238592d774 (patch) | |
tree | 9ad5ae81ba3e820e91a09e2675b7c98675bd809e /sound/firewire | |
parent | e1a00b5b253a4f97216b9a33199a863987075162 (diff) | |
parent | 7711fb7dac1ab77fd1b4d948f4647a569e4a1ae2 (diff) |
Merge branch 'for-next' into for-linus
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
26 files changed, 1169 insertions, 721 deletions
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index fd5d6b8ac557..67d735e9a6a4 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -146,19 +146,24 @@ void amdtp_am824_set_midi_position(struct amdtp_stream *s, } 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) +static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_am824 *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - 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; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -172,19 +177,24 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void read_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, + unsigned int pcm_frames) { struct amdtp_am824 *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - 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; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -284,7 +294,7 @@ static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) } static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, - unsigned int frames) + unsigned int frames, unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; unsigned int f, port; @@ -293,7 +303,7 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, for (f = 0; f < frames; f++) { b = (u8 *)&buffer[p->midi_position]; - port = (s->data_block_counter + f) % 8; + port = (data_block_counter + f) % 8; if (f < MAX_MIDI_RX_BLOCKS && midi_ratelimit_per_packet(s, port) && p->midi[port] != NULL && @@ -311,16 +321,20 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, } } -static void read_midi_messages(struct amdtp_stream *s, - __be32 *buffer, unsigned int frames) +static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, + unsigned int frames, unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; - unsigned int f, port; int len; u8 *b; + int f; for (f = 0; f < frames; f++) { - port = (8 - s->ctx_data.tx.first_dbc + s->data_block_counter + f) % 8; + unsigned int port = f; + + if (!(s->flags & CIP_UNALIGHED_DBC)) + port += data_block_counter; + port %= 8; b = (u8 *)&buffer[p->midi_position]; len = b[0] - 0x80; @@ -331,43 +345,60 @@ static void read_midi_messages(struct amdtp_stream *s, } } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) +static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); - unsigned int pcm_frames; - - if (pcm) { - write_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * p->frame_multiplier; - } else { - write_pcm_silence(s, buffer, data_blocks); - pcm_frames = 0; - } + unsigned int pcm_frames = 0; + int i; - if (p->midi_ports) - write_midi_messages(s, buffer, data_blocks); + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; + + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks * p->frame_multiplier; + } else { + write_pcm_silence(s, buf, data_blocks); + } + + if (p->midi_ports) { + write_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } + } return pcm_frames; } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) +static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); - unsigned int pcm_frames; - - if (pcm) { - read_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * p->frame_multiplier; - } else { - pcm_frames = 0; - } + unsigned int pcm_frames = 0; + int i; + + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - if (p->midi_ports) - read_midi_messages(s, buffer, data_blocks); + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks * p->frame_multiplier; + } + + if (p->midi_ports) { + read_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } + } return pcm_frames; } @@ -383,15 +414,14 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffe int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; if (dir == AMDTP_IN_STREAM) - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; else - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, - process_data_blocks, - sizeof(struct amdtp_am824)); + process_ctx_payloads, sizeof(struct amdtp_am824)); } EXPORT_SYMBOL_GPL(amdtp_am824_init); diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h index 4adbbf789cbe..16c7f6605511 100644 --- a/sound/firewire/amdtp-stream-trace.h +++ b/sound/firewire/amdtp-stream-trace.h @@ -14,8 +14,8 @@ #include <linux/tracepoint.h> TRACE_EVENT(amdtp_packet, - TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int index), - TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, index), + TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int data_block_counter, unsigned int index), + TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, data_block_counter, index), TP_STRUCT__entry( __field(unsigned int, second) __field(unsigned int, cycle) @@ -47,7 +47,7 @@ TRACE_EVENT(amdtp_packet, } __entry->payload_quadlets = payload_length / sizeof(__be32); __entry->data_blocks = data_blocks; - __entry->data_block_counter = s->data_block_counter, + __entry->data_block_counter = data_block_counter, __entry->packet_index = s->packet_index; __entry->irq = !!in_interrupt(); __entry->index = index; diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 4d71d74707cf..e50e28f77e74 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -74,16 +74,16 @@ 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 + * @process_ctx_payloads: callback handler to process payloads of isoc context * @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, - amdtp_stream_process_data_blocks_t process_data_blocks, + amdtp_stream_process_ctx_payloads_t process_ctx_payloads, unsigned int protocol_size) { - if (process_data_blocks == NULL) + if (process_ctx_payloads == NULL) return -EINVAL; s->protocol = kzalloc(protocol_size, GFP_KERNEL); @@ -102,7 +102,10 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->callbacked = false; s->fmt = fmt; - s->process_data_blocks = process_data_blocks; + s->process_ctx_payloads = process_ctx_payloads; + + if (dir == AMDTP_OUT_STREAM) + s->ctx_data.rx.syt_override = -1; return 0; } @@ -473,12 +476,12 @@ static inline int queue_in_packet(struct amdtp_stream *s, } static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], - unsigned int syt) + unsigned int data_block_counter, unsigned int syt) { cip_header[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) | - s->data_block_counter); + data_block_counter); cip_header[1] = cpu_to_be32(CIP_EOH | ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) | ((s->ctx_data.rx.fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) | @@ -487,8 +490,9 @@ static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, struct fw_iso_packet *params, - unsigned int data_blocks, unsigned int syt, - unsigned int index) + unsigned int data_blocks, + unsigned int data_block_counter, + unsigned int syt, unsigned int index) { unsigned int payload_length; __be32 *cip_header; @@ -496,14 +500,9 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, payload_length = data_blocks * sizeof(__be32) * s->data_block_quadlets; params->payload_length = payload_length; - if (s->flags & CIP_DBC_IS_END_EVENT) { - s->data_block_counter = - (s->data_block_counter + data_blocks) & 0xff; - } - if (!(s->flags & CIP_NO_HEADER)) { cip_header = (__be32 *)params->header; - generate_cip_header(s, cip_header, syt); + generate_cip_header(s, cip_header, data_block_counter, syt); params->header_length = 2 * sizeof(__be32); payload_length += params->header_length; } else { @@ -511,23 +510,19 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, } trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks, - index); - - if (!(s->flags & CIP_DBC_IS_END_EVENT)) { - s->data_block_counter = - (s->data_block_counter + data_blocks) & 0xff; - } + data_block_counter, index); } static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, unsigned int payload_length, - unsigned int *data_blocks, unsigned int *dbc, - unsigned int *syt) + unsigned int *data_blocks, + unsigned int *data_block_counter, unsigned int *syt) { u32 cip_header[2]; unsigned int sph; unsigned int fmt; unsigned int fdf; + unsigned int dbc; bool lost; cip_header[0] = be32_to_cpu(buf[0]); @@ -579,17 +574,16 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, } /* Check data block counter continuity */ - *dbc = cip_header[0] & CIP_DBC_MASK; + dbc = cip_header[0] & CIP_DBC_MASK; if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) && - s->data_block_counter != UINT_MAX) - *dbc = s->data_block_counter; + *data_block_counter != UINT_MAX) + dbc = *data_block_counter; - if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) && - *dbc == s->ctx_data.tx.first_dbc) || - s->data_block_counter == UINT_MAX) { + if ((dbc == 0x00 && (s->flags & CIP_SKIP_DBC_ZERO_CHECK)) || + *data_block_counter == UINT_MAX) { lost = false; } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) { - lost = *dbc != s->data_block_counter; + lost = dbc != *data_block_counter; } else { unsigned int dbc_interval; @@ -598,16 +592,18 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, else dbc_interval = *data_blocks; - lost = *dbc != ((s->data_block_counter + dbc_interval) & 0xff); + lost = dbc != ((*data_block_counter + dbc_interval) & 0xff); } if (lost) { dev_err(&s->unit->device, "Detect discontinuity of CIP: %02X %02X\n", - s->data_block_counter, *dbc); + *data_block_counter, dbc); return -EIO; } + *data_block_counter = dbc; + *syt = cip_header[1] & CIP_SYT_MASK; return 0; @@ -616,10 +612,10 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, const __be32 *ctx_header, unsigned int *payload_length, - unsigned int *data_blocks, unsigned int *syt, - unsigned int index) + unsigned int *data_blocks, + unsigned int *data_block_counter, + unsigned int *syt, unsigned int index) { - unsigned int dbc; const __be32 *cip_header; int err; @@ -635,7 +631,7 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, if (!(s->flags & CIP_NO_HEADER)) { cip_header = ctx_header + 2; err = check_cip_header(s, cip_header, *payload_length, - data_blocks, &dbc, syt); + data_blocks, data_block_counter, syt); if (err < 0) return err; } else { @@ -645,16 +641,12 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, s->data_block_quadlets; *syt = 0; - if (s->data_block_counter != UINT_MAX) - dbc = s->data_block_counter; - else - dbc = 0; + if (*data_block_counter == UINT_MAX) + *data_block_counter = 0; } - s->data_block_counter = dbc; - trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks, - index); + *data_block_counter, index); return err; } @@ -686,6 +678,80 @@ static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp) return increment_cycle_count(cycle, QUEUE_LENGTH); } +static int generate_device_pkt_descs(struct amdtp_stream *s, + struct pkt_desc *descs, + const __be32 *ctx_header, + unsigned int packets) +{ + unsigned int dbc = s->data_block_counter; + int i; + int err; + + for (i = 0; i < packets; ++i) { + struct pkt_desc *desc = descs + i; + unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; + unsigned int cycle; + unsigned int payload_length; + unsigned int data_blocks; + unsigned int syt; + + cycle = compute_cycle_count(ctx_header[1]); + + err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, + &data_blocks, &dbc, &syt, i); + if (err < 0) + return err; + + desc->cycle = cycle; + desc->syt = syt; + desc->data_blocks = data_blocks; + desc->data_block_counter = dbc; + desc->ctx_payload = s->buffer.packets[index].buffer; + + if (!(s->flags & CIP_DBC_IS_END_EVENT)) + dbc = (dbc + desc->data_blocks) & 0xff; + + ctx_header += + s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); + } + + s->data_block_counter = dbc; + + return 0; +} + +static void generate_ideal_pkt_descs(struct amdtp_stream *s, + struct pkt_desc *descs, + const __be32 *ctx_header, + unsigned int packets) +{ + unsigned int dbc = s->data_block_counter; + int i; + + for (i = 0; i < packets; ++i) { + struct pkt_desc *desc = descs + i; + unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; + + desc->cycle = compute_it_cycle(*ctx_header); + desc->syt = calculate_syt(s, desc->cycle); + desc->data_blocks = calculate_data_blocks(s, desc->syt); + + if (s->flags & CIP_DBC_IS_END_EVENT) + dbc = (dbc + desc->data_blocks) & 0xff; + + desc->data_block_counter = dbc; + + if (!(s->flags & CIP_DBC_IS_END_EVENT)) + dbc = (dbc + desc->data_blocks) & 0xff; + + desc->ctx_payload = s->buffer.packets[index].buffer; + + ++ctx_header; + } + + s->data_block_counter = dbc; +} + static inline void cancel_stream(struct amdtp_stream *s) { s->packet_index = -1; @@ -694,6 +760,19 @@ static inline void cancel_stream(struct amdtp_stream *s) WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); } +static void process_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets) +{ + struct snd_pcm_substream *pcm; + unsigned int pcm_frames; + + pcm = READ_ONCE(s->pcm); + pcm_frames = s->process_ctx_payloads(s, descs, packets, pcm); + if (pcm) + update_pcm_pointers(s, pcm, pcm_frames); +} + static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, size_t header_length, void *header, void *private_data) @@ -706,38 +785,31 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, if (s->packet_index < 0) return; + generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets); + + process_ctx_payloads(s, s->pkt_descs, packets); + for (i = 0; i < packets; ++i) { - u32 cycle; + const struct pkt_desc *desc = s->pkt_descs + i; unsigned int syt; - unsigned int data_blocks; - __be32 *buffer; - unsigned int pcm_frames; struct { struct fw_iso_packet params; __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)]; } template = { {0}, {0} }; - struct snd_pcm_substream *pcm; - cycle = compute_it_cycle(*ctx_header); - syt = calculate_syt(s, cycle); - data_blocks = calculate_data_blocks(s, syt); - buffer = s->buffer.packets[s->packet_index].buffer; - pcm_frames = s->process_data_blocks(s, buffer, data_blocks, - &syt); + if (s->ctx_data.rx.syt_override < 0) + syt = desc->syt; + else + syt = s->ctx_data.rx.syt_override; - build_it_pkt_header(s, cycle, &template.params, data_blocks, + build_it_pkt_header(s, desc->cycle, &template.params, + desc->data_blocks, desc->data_block_counter, syt, i); if (queue_out_packet(s, &template.params) < 0) { cancel_stream(s); return; } - - pcm = READ_ONCE(s->pcm); - if (pcm && pcm_frames > 0) - update_pcm_pointers(s, pcm, pcm_frames); - - ++ctx_header; } fw_iso_context_queue_flush(s->context); @@ -748,8 +820,10 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, void *private_data) { struct amdtp_stream *s = private_data; - unsigned int i, packets; + unsigned int packets; __be32 *ctx_header = header; + int i; + int err; if (s->packet_index < 0) return; @@ -757,48 +831,23 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, // The number of packets in buffer. packets = header_length / s->ctx_data.tx.ctx_header_size; - for (i = 0; i < packets; i++) { - u32 cycle; - unsigned int payload_length; - unsigned int data_blocks; - unsigned int syt; - __be32 *buffer; - unsigned int pcm_frames = 0; - struct fw_iso_packet params = {0}; - struct snd_pcm_substream *pcm; - int err; - - cycle = compute_cycle_count(ctx_header[1]); - err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, - &data_blocks, &syt, i); - if (err < 0 && err != -EAGAIN) - break; - - if (err >= 0) { - buffer = s->buffer.packets[s->packet_index].buffer; - pcm_frames = s->process_data_blocks(s, buffer, - data_blocks, &syt); - - if (!(s->flags & CIP_DBC_IS_END_EVENT)) { - s->data_block_counter += data_blocks; - s->data_block_counter &= 0xff; - } + err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets); + if (err < 0) { + if (err != -EAGAIN) { + cancel_stream(s); + return; } - - if (queue_in_packet(s, ¶ms) < 0) - break; - - pcm = READ_ONCE(s->pcm); - if (pcm && pcm_frames > 0) - update_pcm_pointers(s, pcm, pcm_frames); - - ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); + } else { + process_ctx_payloads(s, s->pkt_descs, packets); } - /* Queueing error or detecting invalid payload. */ - if (i < packets) { - cancel_stream(s); - return; + for (i = 0; i < packets; ++i) { + struct fw_iso_packet params = {0}; + + if (queue_in_packet(s, ¶ms) < 0) { + cancel_stream(s); + return; + } } fw_iso_context_queue_flush(s->context); @@ -845,7 +894,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI * device can be started. */ -int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) +static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) { static const struct { unsigned int data_block; @@ -932,6 +981,13 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) else s->tag = TAG_CIP; + s->pkt_descs = kcalloc(INTERRUPT_INTERVAL, sizeof(*s->pkt_descs), + GFP_KERNEL); + if (!s->pkt_descs) { + err = -ENOMEM; + goto err_context; + } + s->packet_index = 0; do { struct fw_iso_packet params; @@ -943,7 +999,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) err = queue_out_packet(s, ¶ms); } if (err < 0) - goto err_context; + goto err_pkt_descs; } while (s->packet_index > 0); /* NOTE: TAG1 matches CIP. This just affects in stream. */ @@ -954,12 +1010,13 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) s->callbacked = false; err = fw_iso_context_start(s->context, -1, 0, tag); if (err < 0) - goto err_context; + goto err_pkt_descs; mutex_unlock(&s->mutex); return 0; - +err_pkt_descs: + kfree(s->pkt_descs); err_context: fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); @@ -970,7 +1027,6 @@ err_unlock: return err; } -EXPORT_SYMBOL(amdtp_stream_start); /** * amdtp_stream_pcm_pointer - get the PCM buffer position @@ -1041,7 +1097,7 @@ EXPORT_SYMBOL(amdtp_stream_update); * All PCM and MIDI devices of the stream must be stopped before the stream * itself can be stopped. */ -void amdtp_stream_stop(struct amdtp_stream *s) +static void amdtp_stream_stop(struct amdtp_stream *s) { mutex_lock(&s->mutex); @@ -1055,12 +1111,12 @@ void amdtp_stream_stop(struct amdtp_stream *s) fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); iso_packets_buffer_destroy(&s->buffer, s->unit); + kfree(s->pkt_descs); s->callbacked = false; mutex_unlock(&s->mutex); } -EXPORT_SYMBOL(amdtp_stream_stop); /** * amdtp_stream_pcm_abort - abort the running PCM device @@ -1078,3 +1134,92 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s) snd_pcm_stop_xrun(pcm); } EXPORT_SYMBOL(amdtp_stream_pcm_abort); + +/** + * amdtp_domain_init - initialize an AMDTP domain structure + * @d: the AMDTP domain to initialize. + */ +int amdtp_domain_init(struct amdtp_domain *d) +{ + INIT_LIST_HEAD(&d->streams); + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_domain_init); + +/** + * amdtp_domain_destroy - destroy an AMDTP domain structure + * @d: the AMDTP domain to destroy. + */ +void amdtp_domain_destroy(struct amdtp_domain *d) +{ + // At present nothing to do. + return; +} +EXPORT_SYMBOL_GPL(amdtp_domain_destroy); + +/** + * amdtp_domain_add_stream - register isoc context into the domain. + * @d: the AMDTP domain. + * @s: the AMDTP stream. + * @channel: the isochronous channel on the bus. + * @speed: firewire speed code. + */ +int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, + int channel, int speed) +{ + struct amdtp_stream *tmp; + + list_for_each_entry(tmp, &d->streams, list) { + if (s == tmp) + return -EBUSY; + } + + list_add(&s->list, &d->streams); + + s->channel = channel; + s->speed = speed; + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_domain_add_stream); + +/** + * amdtp_domain_start - start sending packets for isoc context in the domain. + * @d: the AMDTP domain. + */ +int amdtp_domain_start(struct amdtp_domain *d) +{ + struct amdtp_stream *s; + int err = 0; + + list_for_each_entry(s, &d->streams, list) { + err = amdtp_stream_start(s, s->channel, s->speed); + if (err < 0) + break; + } + + if (err < 0) { + list_for_each_entry(s, &d->streams, list) + amdtp_stream_stop(s); + } + + return err; +} +EXPORT_SYMBOL_GPL(amdtp_domain_start); + +/** + * amdtp_domain_stop - stop sending packets for isoc context in the same domain. + * @d: the AMDTP domain to which the isoc contexts belong. + */ +void amdtp_domain_stop(struct amdtp_domain *d) +{ + struct amdtp_stream *s, *next; + + list_for_each_entry_safe(s, next, &d->streams, list) { + list_del(&s->list); + + amdtp_stream_stop(s); + } +} +EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 3942894c11ac..bbbca964b9b4 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -33,6 +33,8 @@ * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include * valid EOH. * @CIP_NO_HEADERS: a lack of headers in packets + * @CIP_UNALIGHED_DBC: Only for in-stream. The value of dbc is not alighed to + * the value of current SYT_INTERVAL; e.g. initial value is not zero. */ enum cip_flags { CIP_NONBLOCKING = 0x00, @@ -45,6 +47,7 @@ enum cip_flags { CIP_JUMBO_PAYLOAD = 0x40, CIP_HEADER_WITHOUT_EOH = 0x80, CIP_NO_HEADER = 0x100, + CIP_UNALIGHED_DBC = 0x200, }; /** @@ -91,12 +94,20 @@ enum amdtp_stream_direction { AMDTP_IN_STREAM }; +struct pkt_desc { + u32 cycle; + u32 syt; + unsigned int data_blocks; + unsigned int data_block_counter; + __be32 *ctx_payload; +}; + struct amdtp_stream; -typedef unsigned int (*amdtp_stream_process_data_blocks_t)( +typedef unsigned int (*amdtp_stream_process_ctx_payloads_t)( struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt); + const struct pkt_desc *desc, + unsigned int packets, + struct snd_pcm_substream *pcm); struct amdtp_stream { struct fw_unit *unit; enum cip_flags flags; @@ -107,6 +118,7 @@ struct amdtp_stream { struct fw_iso_context *context; struct i |