Loading sound/firewire/amdtp.c +126 −29 Original line number Diff line number Diff line Loading @@ -65,42 +65,66 @@ void amdtp_out_stream_destroy(struct amdtp_out_stream *s) } EXPORT_SYMBOL(amdtp_out_stream_destroy); unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = { [CIP_SFC_32000] = 8, [CIP_SFC_44100] = 8, [CIP_SFC_48000] = 8, [CIP_SFC_88200] = 16, [CIP_SFC_96000] = 16, [CIP_SFC_176400] = 32, [CIP_SFC_192000] = 32, }; EXPORT_SYMBOL(amdtp_syt_intervals); /** * amdtp_out_stream_set_rate - set the sample rate * amdtp_out_stream_set_parameters - set stream parameters * @s: the AMDTP output 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) * * The sample rate must be set before the stream is started, and must not be * The parameters must be set before the stream is started, and must not be * changed while the stream is running. */ void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s, unsigned int rate, unsigned int pcm_channels, unsigned int midi_ports) { static const struct { unsigned int rate; unsigned int syt_interval; } rate_info[] = { [CIP_SFC_32000] = { 32000, 8, }, [CIP_SFC_44100] = { 44100, 8, }, [CIP_SFC_48000] = { 48000, 8, }, [CIP_SFC_88200] = { 88200, 16, }, [CIP_SFC_96000] = { 96000, 16, }, [CIP_SFC_176400] = { 176400, 32, }, [CIP_SFC_192000] = { 192000, 32, }, static const unsigned int rates[] = { [CIP_SFC_32000] = 32000, [CIP_SFC_44100] = 44100, [CIP_SFC_48000] = 48000, [CIP_SFC_88200] = 88200, [CIP_SFC_96000] = 96000, [CIP_SFC_176400] = 176400, [CIP_SFC_192000] = 192000, }; unsigned int sfc; if (WARN_ON(amdtp_out_stream_running(s))) return; for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) if (rate_info[sfc].rate == rate) for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc) if (rates[sfc] == rate) goto sfc_found; WARN_ON(1); return; sfc_found: s->dual_wire = (s->flags & CIP_HI_DUALWIRE) && sfc > CIP_SFC_96000; if (s->dual_wire) { sfc -= 2; rate /= 2; pcm_channels *= 2; } s->sfc = sfc; s->syt_interval = rate_info[sfc].syt_interval; s->data_block_quadlets = pcm_channels + DIV_ROUND_UP(midi_ports, 8); s->pcm_channels = pcm_channels; s->midi_ports = midi_ports; s->syt_interval = amdtp_syt_intervals[sfc]; /* default buffering in the device */ s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; Loading @@ -108,21 +132,17 @@ void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) /* additional buffering needed to adjust for no-data packets */ s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate; } EXPORT_SYMBOL(amdtp_out_stream_set_rate); EXPORT_SYMBOL(amdtp_out_stream_set_parameters); /** * amdtp_out_stream_get_max_payload - get the stream's packet size * @s: the AMDTP output stream * * This function must not be called before the stream has been configured * with amdtp_out_stream_set_rate(), amdtp_out_stream_set_pcm(), and * amdtp_out_stream_set_midi(). * with amdtp_out_stream_set_parameters(). */ unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) { s->data_block_quadlets = s->pcm_channels; s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); return 8 + s->syt_interval * s->data_block_quadlets * 4; } EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); Loading @@ -133,14 +153,21 @@ static void amdtp_write_s16(struct amdtp_out_stream *s, static void amdtp_write_s32(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); static void amdtp_write_s32_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); /** * amdtp_out_stream_set_pcm_format - set the PCM format * @s: the AMDTP output stream to configure * @format: the format of the ALSA PCM device * * The sample format must be set before the stream is started, and must not be * changed while the stream is running. * The sample format must be set after the other paramters (rate/PCM channels/ * MIDI) and before the stream is started, and must not be changed while the * stream is running. */ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, snd_pcm_format_t format) Loading @@ -153,9 +180,15 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, WARN_ON(1); /* fall through */ case SNDRV_PCM_FORMAT_S16: if (s->dual_wire) s->transfer_samples = amdtp_write_s16_dualwire; else s->transfer_samples = amdtp_write_s16; break; case SNDRV_PCM_FORMAT_S32: if (s->dual_wire) s->transfer_samples = amdtp_write_s32_dualwire; else s->transfer_samples = amdtp_write_s32; break; } Loading Loading @@ -305,6 +338,68 @@ static void amdtp_write_s16(struct amdtp_out_stream *s, } } static void amdtp_write_s32_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) { struct snd_pcm_runtime *runtime = pcm->runtime; unsigned int channels, frame_adjust_1, frame_adjust_2, i, c; const u32 *src; channels = s->pcm_channels; src = (void *)runtime->dma_area + s->pcm_buffer_pointer * (runtime->frame_bits / 8); frame_adjust_1 = channels - 1; frame_adjust_2 = 1 - (s->data_block_quadlets - channels); channels /= 2; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src >> 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_1; for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src >> 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_2; } } static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) { struct snd_pcm_runtime *runtime = pcm->runtime; unsigned int channels, frame_adjust_1, frame_adjust_2, i, c; const u16 *src; channels = s->pcm_channels; src = (void *)runtime->dma_area + s->pcm_buffer_pointer * (runtime->frame_bits / 8); frame_adjust_1 = channels - 1; frame_adjust_2 = 1 - (s->data_block_quadlets - channels); channels /= 2; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src << 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_1; for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src << 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_2; } } static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s, __be32 *buffer, unsigned int frames) { Loading Loading @@ -390,6 +485,9 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) s->packet_index = index; if (pcm) { if (s->dual_wire) data_blocks *= 2; ptr = s->pcm_buffer_pointer + data_blocks; if (ptr >= pcm->runtime->buffer_size) ptr -= pcm->runtime->buffer_size; Loading Loading @@ -459,8 +557,7 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s) * @speed: firewire speed code * * The stream cannot be started until it has been configured with * amdtp_out_stream_set_rate(), amdtp_out_stream_set_pcm(), * amdtp_out_stream_set_midi(), and amdtp_out_stream_set_format(); * amdtp_out_stream_set_parameters() and amdtp_out_stream_set_pcm_format(), * and it must be started before any PCM or MIDI device can be started. */ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) Loading sound/firewire/amdtp.h +13 −28 Original line number Diff line number Diff line Loading @@ -15,10 +15,15 @@ * @CIP_BLOCKING: In blocking mode, each packet contains either zero or * SYT_INTERVAL samples, with these two types alternating so that * the overall sample rate comes out right. * @CIP_HI_DUALWIRE: At rates above 96 kHz, pretend that the stream runs * at half the actual sample rate with twice the number of channels; * two samples of a channel are stored consecutively in the packet. * Requires blocking mode and SYT_INTERVAL-aligned PCM buffer size. */ enum cip_out_flags { CIP_NONBLOCKING = 0x00, CIP_BLOCKING = 0x01, CIP_HI_DUALWIRE = 0x02, }; /** Loading @@ -32,6 +37,7 @@ enum cip_sfc { CIP_SFC_96000 = 4, CIP_SFC_176400 = 5, CIP_SFC_192000 = 6, CIP_SFC_COUNT }; #define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ Loading @@ -48,6 +54,7 @@ struct amdtp_out_stream { struct mutex mutex; enum cip_sfc sfc; bool dual_wire; unsigned int data_block_quadlets; unsigned int pcm_channels; unsigned int midi_ports; Loading Loading @@ -80,7 +87,10 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, enum cip_out_flags flags); void amdtp_out_stream_destroy(struct amdtp_out_stream *s); void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate); void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s, unsigned int rate, unsigned int pcm_channels, unsigned int midi_ports); unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s); int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed); Loading @@ -93,38 +103,13 @@ void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s); unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s); void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s); extern unsigned int amdtp_syt_intervals[CIP_SFC_COUNT]; static inline bool amdtp_out_stream_running(struct amdtp_out_stream *s) { return !IS_ERR(s->context); } /** * amdtp_out_stream_set_pcm - configure format of PCM samples * @s: the AMDTP output stream to be configured * @pcm_channels: the number of PCM samples in each data block, to be encoded * as AM824 multi-bit linear audio * * This function must not be called while the stream is running. */ static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s, unsigned int pcm_channels) { s->pcm_channels = pcm_channels; } /** * amdtp_out_stream_set_midi - configure format of MIDI data * @s: the AMDTP output stream to be configured * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) * * This function must not be called while the stream is running. */ static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s, unsigned int midi_ports) { s->midi_ports = midi_ports; } /** * amdtp_out_streaming_error - check for streaming error * @s: the AMDTP output stream Loading sound/firewire/dice.c +21 −8 Original line number Diff line number Diff line Loading @@ -375,7 +375,7 @@ static int dice_open(struct snd_pcm_substream *substream) struct dice *dice = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; __be32 clock_sel, number_audio, number_midi; unsigned int rate; unsigned int rate_index, rate; int err; err = dice_try_lock(dice); Loading @@ -387,12 +387,13 @@ static int dice_open(struct snd_pcm_substream *substream) &clock_sel, 4); if (err < 0) goto err_lock; rate = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT; if (rate >= ARRAY_SIZE(dice_rates)) { rate_index = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT; if (rate_index >= ARRAY_SIZE(dice_rates)) { err = -ENXIO; goto err_lock; } rate = dice_rates[rate]; rate = dice_rates[rate_index]; err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, rx_address(dice, RX_NUMBER_AUDIO), Loading @@ -413,9 +414,20 @@ static int dice_open(struct snd_pcm_substream *substream) runtime->hw.channels_min = be32_to_cpu(number_audio); runtime->hw.channels_max = be32_to_cpu(number_audio); amdtp_out_stream_set_rate(&dice->stream, rate); amdtp_out_stream_set_pcm(&dice->stream, be32_to_cpu(number_audio)); amdtp_out_stream_set_midi(&dice->stream, be32_to_cpu(number_midi)); amdtp_out_stream_set_parameters(&dice->stream, rate, be32_to_cpu(number_audio), be32_to_cpu(number_midi)); err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, amdtp_syt_intervals[rate_index]); if (err < 0) goto err_lock; err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, amdtp_syt_intervals[rate_index]); if (err < 0) goto err_lock; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, Loading Loading @@ -993,7 +1005,8 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) goto err_notification_handler; dice->resources.channels_mask = 0x00000000ffffffffuLL; err = amdtp_out_stream_init(&dice->stream, unit, CIP_BLOCKING); err = amdtp_out_stream_init(&dice->stream, unit, CIP_BLOCKING | CIP_HI_DUALWIRE); if (err < 0) goto err_resources; Loading sound/firewire/speakers.c +4 −2 Original line number Diff line number Diff line Loading @@ -245,8 +245,10 @@ static int fwspk_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto error; amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params)); amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params)); amdtp_out_stream_set_parameters(&fwspk->stream, params_rate(hw_params), params_channels(hw_params), 0); amdtp_out_stream_set_pcm_format(&fwspk->stream, params_format(hw_params)); Loading Loading
sound/firewire/amdtp.c +126 −29 Original line number Diff line number Diff line Loading @@ -65,42 +65,66 @@ void amdtp_out_stream_destroy(struct amdtp_out_stream *s) } EXPORT_SYMBOL(amdtp_out_stream_destroy); unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = { [CIP_SFC_32000] = 8, [CIP_SFC_44100] = 8, [CIP_SFC_48000] = 8, [CIP_SFC_88200] = 16, [CIP_SFC_96000] = 16, [CIP_SFC_176400] = 32, [CIP_SFC_192000] = 32, }; EXPORT_SYMBOL(amdtp_syt_intervals); /** * amdtp_out_stream_set_rate - set the sample rate * amdtp_out_stream_set_parameters - set stream parameters * @s: the AMDTP output 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) * * The sample rate must be set before the stream is started, and must not be * The parameters must be set before the stream is started, and must not be * changed while the stream is running. */ void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s, unsigned int rate, unsigned int pcm_channels, unsigned int midi_ports) { static const struct { unsigned int rate; unsigned int syt_interval; } rate_info[] = { [CIP_SFC_32000] = { 32000, 8, }, [CIP_SFC_44100] = { 44100, 8, }, [CIP_SFC_48000] = { 48000, 8, }, [CIP_SFC_88200] = { 88200, 16, }, [CIP_SFC_96000] = { 96000, 16, }, [CIP_SFC_176400] = { 176400, 32, }, [CIP_SFC_192000] = { 192000, 32, }, static const unsigned int rates[] = { [CIP_SFC_32000] = 32000, [CIP_SFC_44100] = 44100, [CIP_SFC_48000] = 48000, [CIP_SFC_88200] = 88200, [CIP_SFC_96000] = 96000, [CIP_SFC_176400] = 176400, [CIP_SFC_192000] = 192000, }; unsigned int sfc; if (WARN_ON(amdtp_out_stream_running(s))) return; for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) if (rate_info[sfc].rate == rate) for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc) if (rates[sfc] == rate) goto sfc_found; WARN_ON(1); return; sfc_found: s->dual_wire = (s->flags & CIP_HI_DUALWIRE) && sfc > CIP_SFC_96000; if (s->dual_wire) { sfc -= 2; rate /= 2; pcm_channels *= 2; } s->sfc = sfc; s->syt_interval = rate_info[sfc].syt_interval; s->data_block_quadlets = pcm_channels + DIV_ROUND_UP(midi_ports, 8); s->pcm_channels = pcm_channels; s->midi_ports = midi_ports; s->syt_interval = amdtp_syt_intervals[sfc]; /* default buffering in the device */ s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; Loading @@ -108,21 +132,17 @@ void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) /* additional buffering needed to adjust for no-data packets */ s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate; } EXPORT_SYMBOL(amdtp_out_stream_set_rate); EXPORT_SYMBOL(amdtp_out_stream_set_parameters); /** * amdtp_out_stream_get_max_payload - get the stream's packet size * @s: the AMDTP output stream * * This function must not be called before the stream has been configured * with amdtp_out_stream_set_rate(), amdtp_out_stream_set_pcm(), and * amdtp_out_stream_set_midi(). * with amdtp_out_stream_set_parameters(). */ unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) { s->data_block_quadlets = s->pcm_channels; s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); return 8 + s->syt_interval * s->data_block_quadlets * 4; } EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); Loading @@ -133,14 +153,21 @@ static void amdtp_write_s16(struct amdtp_out_stream *s, static void amdtp_write_s32(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); static void amdtp_write_s32_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames); /** * amdtp_out_stream_set_pcm_format - set the PCM format * @s: the AMDTP output stream to configure * @format: the format of the ALSA PCM device * * The sample format must be set before the stream is started, and must not be * changed while the stream is running. * The sample format must be set after the other paramters (rate/PCM channels/ * MIDI) and before the stream is started, and must not be changed while the * stream is running. */ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, snd_pcm_format_t format) Loading @@ -153,9 +180,15 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, WARN_ON(1); /* fall through */ case SNDRV_PCM_FORMAT_S16: if (s->dual_wire) s->transfer_samples = amdtp_write_s16_dualwire; else s->transfer_samples = amdtp_write_s16; break; case SNDRV_PCM_FORMAT_S32: if (s->dual_wire) s->transfer_samples = amdtp_write_s32_dualwire; else s->transfer_samples = amdtp_write_s32; break; } Loading Loading @@ -305,6 +338,68 @@ static void amdtp_write_s16(struct amdtp_out_stream *s, } } static void amdtp_write_s32_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) { struct snd_pcm_runtime *runtime = pcm->runtime; unsigned int channels, frame_adjust_1, frame_adjust_2, i, c; const u32 *src; channels = s->pcm_channels; src = (void *)runtime->dma_area + s->pcm_buffer_pointer * (runtime->frame_bits / 8); frame_adjust_1 = channels - 1; frame_adjust_2 = 1 - (s->data_block_quadlets - channels); channels /= 2; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src >> 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_1; for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src >> 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_2; } } static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s, struct snd_pcm_substream *pcm, __be32 *buffer, unsigned int frames) { struct snd_pcm_runtime *runtime = pcm->runtime; unsigned int channels, frame_adjust_1, frame_adjust_2, i, c; const u16 *src; channels = s->pcm_channels; src = (void *)runtime->dma_area + s->pcm_buffer_pointer * (runtime->frame_bits / 8); frame_adjust_1 = channels - 1; frame_adjust_2 = 1 - (s->data_block_quadlets - channels); channels /= 2; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src << 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_1; for (c = 0; c < channels; ++c) { *buffer = cpu_to_be32((*src << 8) | 0x40000000); src++; buffer += 2; } buffer -= frame_adjust_2; } } static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s, __be32 *buffer, unsigned int frames) { Loading Loading @@ -390,6 +485,9 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) s->packet_index = index; if (pcm) { if (s->dual_wire) data_blocks *= 2; ptr = s->pcm_buffer_pointer + data_blocks; if (ptr >= pcm->runtime->buffer_size) ptr -= pcm->runtime->buffer_size; Loading Loading @@ -459,8 +557,7 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s) * @speed: firewire speed code * * The stream cannot be started until it has been configured with * amdtp_out_stream_set_rate(), amdtp_out_stream_set_pcm(), * amdtp_out_stream_set_midi(), and amdtp_out_stream_set_format(); * amdtp_out_stream_set_parameters() and amdtp_out_stream_set_pcm_format(), * and it must be started before any PCM or MIDI device can be started. */ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) Loading
sound/firewire/amdtp.h +13 −28 Original line number Diff line number Diff line Loading @@ -15,10 +15,15 @@ * @CIP_BLOCKING: In blocking mode, each packet contains either zero or * SYT_INTERVAL samples, with these two types alternating so that * the overall sample rate comes out right. * @CIP_HI_DUALWIRE: At rates above 96 kHz, pretend that the stream runs * at half the actual sample rate with twice the number of channels; * two samples of a channel are stored consecutively in the packet. * Requires blocking mode and SYT_INTERVAL-aligned PCM buffer size. */ enum cip_out_flags { CIP_NONBLOCKING = 0x00, CIP_BLOCKING = 0x01, CIP_HI_DUALWIRE = 0x02, }; /** Loading @@ -32,6 +37,7 @@ enum cip_sfc { CIP_SFC_96000 = 4, CIP_SFC_176400 = 5, CIP_SFC_192000 = 6, CIP_SFC_COUNT }; #define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \ Loading @@ -48,6 +54,7 @@ struct amdtp_out_stream { struct mutex mutex; enum cip_sfc sfc; bool dual_wire; unsigned int data_block_quadlets; unsigned int pcm_channels; unsigned int midi_ports; Loading Loading @@ -80,7 +87,10 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, enum cip_out_flags flags); void amdtp_out_stream_destroy(struct amdtp_out_stream *s); void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate); void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s, unsigned int rate, unsigned int pcm_channels, unsigned int midi_ports); unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s); int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed); Loading @@ -93,38 +103,13 @@ void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s); unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s); void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s); extern unsigned int amdtp_syt_intervals[CIP_SFC_COUNT]; static inline bool amdtp_out_stream_running(struct amdtp_out_stream *s) { return !IS_ERR(s->context); } /** * amdtp_out_stream_set_pcm - configure format of PCM samples * @s: the AMDTP output stream to be configured * @pcm_channels: the number of PCM samples in each data block, to be encoded * as AM824 multi-bit linear audio * * This function must not be called while the stream is running. */ static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s, unsigned int pcm_channels) { s->pcm_channels = pcm_channels; } /** * amdtp_out_stream_set_midi - configure format of MIDI data * @s: the AMDTP output stream to be configured * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) * * This function must not be called while the stream is running. */ static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s, unsigned int midi_ports) { s->midi_ports = midi_ports; } /** * amdtp_out_streaming_error - check for streaming error * @s: the AMDTP output stream Loading
sound/firewire/dice.c +21 −8 Original line number Diff line number Diff line Loading @@ -375,7 +375,7 @@ static int dice_open(struct snd_pcm_substream *substream) struct dice *dice = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; __be32 clock_sel, number_audio, number_midi; unsigned int rate; unsigned int rate_index, rate; int err; err = dice_try_lock(dice); Loading @@ -387,12 +387,13 @@ static int dice_open(struct snd_pcm_substream *substream) &clock_sel, 4); if (err < 0) goto err_lock; rate = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT; if (rate >= ARRAY_SIZE(dice_rates)) { rate_index = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT; if (rate_index >= ARRAY_SIZE(dice_rates)) { err = -ENXIO; goto err_lock; } rate = dice_rates[rate]; rate = dice_rates[rate_index]; err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, rx_address(dice, RX_NUMBER_AUDIO), Loading @@ -413,9 +414,20 @@ static int dice_open(struct snd_pcm_substream *substream) runtime->hw.channels_min = be32_to_cpu(number_audio); runtime->hw.channels_max = be32_to_cpu(number_audio); amdtp_out_stream_set_rate(&dice->stream, rate); amdtp_out_stream_set_pcm(&dice->stream, be32_to_cpu(number_audio)); amdtp_out_stream_set_midi(&dice->stream, be32_to_cpu(number_midi)); amdtp_out_stream_set_parameters(&dice->stream, rate, be32_to_cpu(number_audio), be32_to_cpu(number_midi)); err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, amdtp_syt_intervals[rate_index]); if (err < 0) goto err_lock; err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, amdtp_syt_intervals[rate_index]); if (err < 0) goto err_lock; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, Loading Loading @@ -993,7 +1005,8 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) goto err_notification_handler; dice->resources.channels_mask = 0x00000000ffffffffuLL; err = amdtp_out_stream_init(&dice->stream, unit, CIP_BLOCKING); err = amdtp_out_stream_init(&dice->stream, unit, CIP_BLOCKING | CIP_HI_DUALWIRE); if (err < 0) goto err_resources; Loading
sound/firewire/speakers.c +4 −2 Original line number Diff line number Diff line Loading @@ -245,8 +245,10 @@ static int fwspk_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto error; amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params)); amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params)); amdtp_out_stream_set_parameters(&fwspk->stream, params_rate(hw_params), params_channels(hw_params), 0); amdtp_out_stream_set_pcm_format(&fwspk->stream, params_format(hw_params)); Loading