blob: 4c4c4fff62726be04b55a598d36b9bec7fee0549 [file] [log] [blame]
Takashi Sakamoto6eb6c812014-11-29 00:59:14 +09001/*
2 * dice_stream.c - a part of driver for DICE based devices
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6 *
7 * Licensed under the terms of the GNU General Public License, version 2.
8 */
9
10#include "dice.h"
11
12const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
13 /* mode 0 */
14 [0] = 32000,
15 [1] = 44100,
16 [2] = 48000,
17 /* mode 1 */
18 [3] = 88200,
19 [4] = 96000,
20 /* mode 2 */
21 [5] = 176400,
22 [6] = 192000,
23};
24
25int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
26 unsigned int *mode)
27{
28 int i;
29
30 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
31 if (!(dice->clock_caps & BIT(i)))
32 continue;
33 if (snd_dice_rates[i] != rate)
34 continue;
35
36 *mode = (i - 1) / 2;
37 return 0;
38 }
39 return -EINVAL;
40}
41
42int snd_dice_stream_start_packets(struct snd_dice *dice)
43{
44 int err;
45
46 if (amdtp_stream_running(&dice->rx_stream))
47 return 0;
48
49 err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel,
50 fw_parent_device(dice->unit)->max_speed);
51 if (err < 0)
52 return err;
53
54 err = snd_dice_transaction_set_enable(dice);
55 if (err < 0) {
56 amdtp_stream_stop(&dice->rx_stream);
57 return err;
58 }
59
60 return 0;
61}
62
63int snd_dice_stream_start(struct snd_dice *dice)
64{
65 __be32 channel;
66 int err;
67
68 if (!dice->rx_resources.allocated) {
69 err = fw_iso_resources_allocate(&dice->rx_resources,
70 amdtp_stream_get_max_payload(&dice->rx_stream),
71 fw_parent_device(dice->unit)->max_speed);
72 if (err < 0)
73 goto error;
74
75 channel = cpu_to_be32(dice->rx_resources.channel);
76 err = snd_dice_transaction_write_tx(dice, RX_ISOCHRONOUS,
77 &channel, 4);
78 if (err < 0)
79 goto err_resources;
80 }
81
82 err = snd_dice_stream_start_packets(dice);
83 if (err < 0)
84 goto err_rx_channel;
85
86 return 0;
87
88err_rx_channel:
89 channel = cpu_to_be32((u32)-1);
90 snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4);
91err_resources:
92 fw_iso_resources_free(&dice->rx_resources);
93error:
94 return err;
95}
96
97void snd_dice_stream_stop_packets(struct snd_dice *dice)
98{
Takashi Sakamotoc50fb912014-11-29 00:59:15 +090099 if (!amdtp_stream_running(&dice->rx_stream))
100 return;
101
102 snd_dice_transaction_clear_enable(dice);
103 amdtp_stream_stop(&dice->rx_stream);
Takashi Sakamoto6eb6c812014-11-29 00:59:14 +0900104}
105
106void snd_dice_stream_stop(struct snd_dice *dice)
107{
108 __be32 channel;
109
110 snd_dice_stream_stop_packets(dice);
111
112 if (!dice->rx_resources.allocated)
113 return;
114
115 channel = cpu_to_be32((u32)-1);
116 snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4);
117
118 fw_iso_resources_free(&dice->rx_resources);
119}
120
121int snd_dice_stream_init(struct snd_dice *dice)
122{
123 int err;
124
125 err = fw_iso_resources_init(&dice->rx_resources, dice->unit);
126 if (err < 0)
127 goto end;
128 dice->rx_resources.channels_mask = 0x00000000ffffffffuLL;
129
130 err = amdtp_stream_init(&dice->rx_stream, dice->unit, AMDTP_OUT_STREAM,
131 CIP_BLOCKING);
132 if (err < 0)
133 goto error;
134
135 err = snd_dice_transaction_set_clock_source(dice, CLOCK_SOURCE_ARX1);
136 if (err < 0)
137 goto error;
138end:
139 return err;
140error:
141 amdtp_stream_destroy(&dice->rx_stream);
142 fw_iso_resources_destroy(&dice->rx_resources);
143 return err;
144}
145
146void snd_dice_stream_destroy(struct snd_dice *dice)
147{
148 amdtp_stream_pcm_abort(&dice->rx_stream);
149 snd_dice_stream_stop(dice);
150 amdtp_stream_destroy(&dice->rx_stream);
151 fw_iso_resources_destroy(&dice->rx_resources);
152}
153
154void snd_dice_stream_update(struct snd_dice *dice)
155{
156 /*
157 * On a bus reset, the DICE firmware disables streaming and then goes
158 * off contemplating its own navel for hundreds of milliseconds before
159 * it can react to any of our attempts to reenable streaming. This
160 * means that we lose synchronization anyway, so we force our streams
161 * to stop so that the application can restart them in an orderly
162 * manner.
163 */
164 dice->global_enabled = false;
165
166 amdtp_stream_pcm_abort(&dice->rx_stream);
167 snd_dice_stream_stop_packets(dice);
168 fw_iso_resources_update(&dice->rx_resources);
169}
170
171static void dice_lock_changed(struct snd_dice *dice)
172{
173 dice->dev_lock_changed = true;
174 wake_up(&dice->hwdep_wait);
175}
176
177int snd_dice_stream_lock_try(struct snd_dice *dice)
178{
179 int err;
180
181 spin_lock_irq(&dice->lock);
182
183 if (dice->dev_lock_count < 0) {
184 err = -EBUSY;
185 goto out;
186 }
187
188 if (dice->dev_lock_count++ == 0)
189 dice_lock_changed(dice);
190 err = 0;
191out:
192 spin_unlock_irq(&dice->lock);
193 return err;
194}
195
196void snd_dice_stream_lock_release(struct snd_dice *dice)
197{
198 spin_lock_irq(&dice->lock);
199
200 if (WARN_ON(dice->dev_lock_count <= 0))
201 goto out;
202
203 if (--dice->dev_lock_count == 0)
204 dice_lock_changed(dice);
205out:
206 spin_unlock_irq(&dice->lock);
207}