diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2011-09-04 16:12:48 -0400 |
---|---|---|
committer | Clemens Ladisch <clemens@ladisch.de> | 2013-10-20 16:07:57 -0400 |
commit | e84d15f619c13e83b33023c84527ee35ef01b6b4 (patch) | |
tree | a5d06e046895ebc5a14d06c93fdd4f39eb7c840a /sound/firewire/amdtp.c | |
parent | d13109673ac49cd4b992df17238ee030be7ed7f0 (diff) |
ALSA: dice, firewire-lib: add blocking mode
Allow AMDTP output streams to use blocking mode.
Use it for DICE devices, because the old DICE-II chip will in some cases
not be able to lock to non-blocking streams (erratum E7).
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r-- | sound/firewire/amdtp.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index ea995af6d049..efb2e2947ce7 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c | |||
@@ -42,9 +42,6 @@ static void pcm_period_tasklet(unsigned long data); | |||
42 | int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, | 42 | int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, |
43 | enum cip_out_flags flags) | 43 | enum cip_out_flags flags) |
44 | { | 44 | { |
45 | if (flags != CIP_NONBLOCKING) | ||
46 | return -EINVAL; | ||
47 | |||
48 | s->unit = fw_unit_get(unit); | 45 | s->unit = fw_unit_get(unit); |
49 | s->flags = flags; | 46 | s->flags = flags; |
50 | s->context = ERR_PTR(-1); | 47 | s->context = ERR_PTR(-1); |
@@ -96,12 +93,20 @@ void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate) | |||
96 | return; | 93 | return; |
97 | 94 | ||
98 | for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) | 95 | for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc) |
99 | if (rate_info[sfc].rate == rate) { | 96 | if (rate_info[sfc].rate == rate) |
100 | s->sfc = sfc; | 97 | goto sfc_found; |
101 | s->syt_interval = rate_info[sfc].syt_interval; | ||
102 | return; | ||
103 | } | ||
104 | WARN_ON(1); | 98 | WARN_ON(1); |
99 | return; | ||
100 | |||
101 | sfc_found: | ||
102 | s->sfc = sfc; | ||
103 | s->syt_interval = rate_info[sfc].syt_interval; | ||
104 | |||
105 | /* default buffering in the device */ | ||
106 | s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; | ||
107 | if (s->flags & CIP_BLOCKING) | ||
108 | /* additional buffering needed to adjust for no-data packets */ | ||
109 | s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate; | ||
105 | } | 110 | } |
106 | EXPORT_SYMBOL(amdtp_out_stream_set_rate); | 111 | EXPORT_SYMBOL(amdtp_out_stream_set_rate); |
107 | 112 | ||
@@ -110,25 +115,15 @@ EXPORT_SYMBOL(amdtp_out_stream_set_rate); | |||
110 | * @s: the AMDTP output stream | 115 | * @s: the AMDTP output stream |
111 | * | 116 | * |
112 | * This function must not be called before the stream has been configured | 117 | * This function must not be called before the stream has been configured |
113 | * with amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and | 118 | * with amdtp_out_stream_set_rate(), amdtp_out_stream_set_pcm(), and |
114 | * amdtp_out_stream_set_midi(). | 119 | * amdtp_out_stream_set_midi(). |
115 | */ | 120 | */ |
116 | unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) | 121 | unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s) |
117 | { | 122 | { |
118 | static const unsigned int max_data_blocks[] = { | ||
119 | [CIP_SFC_32000] = 4, | ||
120 | [CIP_SFC_44100] = 6, | ||
121 | [CIP_SFC_48000] = 6, | ||
122 | [CIP_SFC_88200] = 12, | ||
123 | [CIP_SFC_96000] = 12, | ||
124 | [CIP_SFC_176400] = 23, | ||
125 | [CIP_SFC_192000] = 24, | ||
126 | }; | ||
127 | |||
128 | s->data_block_quadlets = s->pcm_channels; | 123 | s->data_block_quadlets = s->pcm_channels; |
129 | s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); | 124 | s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8); |
130 | 125 | ||
131 | return 8 + max_data_blocks[s->sfc] * 4 * s->data_block_quadlets; | 126 | return 8 + s->syt_interval * s->data_block_quadlets * 4; |
132 | } | 127 | } |
133 | EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); | 128 | EXPORT_SYMBOL(amdtp_out_stream_get_max_payload); |
134 | 129 | ||
@@ -248,7 +243,7 @@ static unsigned int calculate_syt(struct amdtp_out_stream *s, | |||
248 | s->last_syt_offset = syt_offset; | 243 | s->last_syt_offset = syt_offset; |
249 | 244 | ||
250 | if (syt_offset < TICKS_PER_CYCLE) { | 245 | if (syt_offset < TICKS_PER_CYCLE) { |
251 | syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; | 246 | syt_offset += s->transfer_delay; |
252 | syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12; | 247 | syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12; |
253 | syt += syt_offset % TICKS_PER_CYCLE; | 248 | syt += syt_offset % TICKS_PER_CYCLE; |
254 | 249 | ||
@@ -344,8 +339,17 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) | |||
344 | return; | 339 | return; |
345 | index = s->packet_index; | 340 | index = s->packet_index; |
346 | 341 | ||
347 | data_blocks = calculate_data_blocks(s); | ||
348 | syt = calculate_syt(s, cycle); | 342 | syt = calculate_syt(s, cycle); |
343 | if (!(s->flags & CIP_BLOCKING)) { | ||
344 | data_blocks = calculate_data_blocks(s); | ||
345 | } else { | ||
346 | if (syt != 0xffff) { | ||
347 | data_blocks = s->syt_interval; | ||
348 | } else { | ||
349 | data_blocks = 0; | ||
350 | syt = 0xffffff; | ||
351 | } | ||
352 | } | ||
349 | 353 | ||
350 | buffer = s->buffer.packets[index].buffer; | 354 | buffer = s->buffer.packets[index].buffer; |
351 | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | | 355 | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | |
@@ -455,9 +459,9 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s) | |||
455 | * @speed: firewire speed code | 459 | * @speed: firewire speed code |
456 | * | 460 | * |
457 | * The stream cannot be started until it has been configured with | 461 | * The stream cannot be started until it has been configured with |
458 | * amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and | 462 | * amdtp_out_stream_set_rate(), amdtp_out_stream_set_pcm(), |
459 | * amdtp_out_stream_set_midi(); and it must be started before any | 463 | * amdtp_out_stream_set_midi(), and amdtp_out_stream_set_format(); |
460 | * PCM or MIDI device can be started. | 464 | * and it must be started before any PCM or MIDI device can be started. |
461 | */ | 465 | */ |
462 | int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) | 466 | int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) |
463 | { | 467 | { |