1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * motu-stream.c - a part of driver for MOTU FireWire series
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "motu.h"
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define CALLBACK_TIMEOUT 200
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define ISOC_COMM_CONTROL_OFFSET 0x0b00
13*4882a593Smuzhiyun #define ISOC_COMM_CONTROL_MASK 0xffff0000
14*4882a593Smuzhiyun #define CHANGE_RX_ISOC_COMM_STATE 0x80000000
15*4882a593Smuzhiyun #define RX_ISOC_COMM_IS_ACTIVATED 0x40000000
16*4882a593Smuzhiyun #define RX_ISOC_COMM_CHANNEL_MASK 0x3f000000
17*4882a593Smuzhiyun #define RX_ISOC_COMM_CHANNEL_SHIFT 24
18*4882a593Smuzhiyun #define CHANGE_TX_ISOC_COMM_STATE 0x00800000
19*4882a593Smuzhiyun #define TX_ISOC_COMM_IS_ACTIVATED 0x00400000
20*4882a593Smuzhiyun #define TX_ISOC_COMM_CHANNEL_MASK 0x003f0000
21*4882a593Smuzhiyun #define TX_ISOC_COMM_CHANNEL_SHIFT 16
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define PACKET_FORMAT_OFFSET 0x0b10
24*4882a593Smuzhiyun #define TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080
25*4882a593Smuzhiyun #define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040
26*4882a593Smuzhiyun #define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f
27*4882a593Smuzhiyun
keep_resources(struct snd_motu * motu,unsigned int rate,struct amdtp_stream * stream)28*4882a593Smuzhiyun static int keep_resources(struct snd_motu *motu, unsigned int rate,
29*4882a593Smuzhiyun struct amdtp_stream *stream)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun struct fw_iso_resources *resources;
32*4882a593Smuzhiyun struct snd_motu_packet_format *packet_format;
33*4882a593Smuzhiyun unsigned int midi_ports = 0;
34*4882a593Smuzhiyun int err;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun if (stream == &motu->rx_stream) {
37*4882a593Smuzhiyun resources = &motu->rx_resources;
38*4882a593Smuzhiyun packet_format = &motu->rx_packet_formats;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
41*4882a593Smuzhiyun (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
42*4882a593Smuzhiyun midi_ports = 1;
43*4882a593Smuzhiyun } else {
44*4882a593Smuzhiyun resources = &motu->tx_resources;
45*4882a593Smuzhiyun packet_format = &motu->tx_packet_formats;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
48*4882a593Smuzhiyun (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
49*4882a593Smuzhiyun midi_ports = 1;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun err = amdtp_motu_set_parameters(stream, rate, midi_ports,
53*4882a593Smuzhiyun packet_format);
54*4882a593Smuzhiyun if (err < 0)
55*4882a593Smuzhiyun return err;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun return fw_iso_resources_allocate(resources,
58*4882a593Smuzhiyun amdtp_stream_get_max_payload(stream),
59*4882a593Smuzhiyun fw_parent_device(motu->unit)->max_speed);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
begin_session(struct snd_motu * motu)62*4882a593Smuzhiyun static int begin_session(struct snd_motu *motu)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun __be32 reg;
65*4882a593Smuzhiyun u32 data;
66*4882a593Smuzhiyun int err;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun // Configure the unit to start isochronous communication.
69*4882a593Smuzhiyun err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®,
70*4882a593Smuzhiyun sizeof(reg));
71*4882a593Smuzhiyun if (err < 0)
72*4882a593Smuzhiyun return err;
73*4882a593Smuzhiyun data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
76*4882a593Smuzhiyun (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
77*4882a593Smuzhiyun CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
78*4882a593Smuzhiyun (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun reg = cpu_to_be32(data);
81*4882a593Smuzhiyun return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®,
82*4882a593Smuzhiyun sizeof(reg));
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
finish_session(struct snd_motu * motu)85*4882a593Smuzhiyun static void finish_session(struct snd_motu *motu)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun __be32 reg;
88*4882a593Smuzhiyun u32 data;
89*4882a593Smuzhiyun int err;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun err = snd_motu_protocol_switch_fetching_mode(motu, false);
92*4882a593Smuzhiyun if (err < 0)
93*4882a593Smuzhiyun return;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®,
96*4882a593Smuzhiyun sizeof(reg));
97*4882a593Smuzhiyun if (err < 0)
98*4882a593Smuzhiyun return;
99*4882a593Smuzhiyun data = be32_to_cpu(reg);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
102*4882a593Smuzhiyun data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun reg = cpu_to_be32(data);
105*4882a593Smuzhiyun snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®,
106*4882a593Smuzhiyun sizeof(reg));
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
snd_motu_stream_cache_packet_formats(struct snd_motu * motu)109*4882a593Smuzhiyun int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun int err;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun err = snd_motu_protocol_cache_packet_formats(motu);
114*4882a593Smuzhiyun if (err < 0)
115*4882a593Smuzhiyun return err;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) {
118*4882a593Smuzhiyun motu->tx_packet_formats.midi_flag_offset = 4;
119*4882a593Smuzhiyun motu->tx_packet_formats.midi_byte_offset = 6;
120*4882a593Smuzhiyun } else if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q) {
121*4882a593Smuzhiyun motu->tx_packet_formats.midi_flag_offset = 8;
122*4882a593Smuzhiyun motu->tx_packet_formats.midi_byte_offset = 7;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) {
126*4882a593Smuzhiyun motu->rx_packet_formats.midi_flag_offset = 4;
127*4882a593Smuzhiyun motu->rx_packet_formats.midi_byte_offset = 6;
128*4882a593Smuzhiyun } else if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) {
129*4882a593Smuzhiyun motu->rx_packet_formats.midi_flag_offset = 8;
130*4882a593Smuzhiyun motu->rx_packet_formats.midi_byte_offset = 7;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
snd_motu_stream_reserve_duplex(struct snd_motu * motu,unsigned int rate,unsigned int frames_per_period,unsigned int frames_per_buffer)136*4882a593Smuzhiyun int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
137*4882a593Smuzhiyun unsigned int frames_per_period,
138*4882a593Smuzhiyun unsigned int frames_per_buffer)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun unsigned int curr_rate;
141*4882a593Smuzhiyun int err;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun err = snd_motu_protocol_get_clock_rate(motu, &curr_rate);
144*4882a593Smuzhiyun if (err < 0)
145*4882a593Smuzhiyun return err;
146*4882a593Smuzhiyun if (rate == 0)
147*4882a593Smuzhiyun rate = curr_rate;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (motu->substreams_counter == 0 || curr_rate != rate) {
150*4882a593Smuzhiyun amdtp_domain_stop(&motu->domain);
151*4882a593Smuzhiyun finish_session(motu);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun fw_iso_resources_free(&motu->tx_resources);
154*4882a593Smuzhiyun fw_iso_resources_free(&motu->rx_resources);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun err = snd_motu_protocol_set_clock_rate(motu, rate);
157*4882a593Smuzhiyun if (err < 0) {
158*4882a593Smuzhiyun dev_err(&motu->unit->device,
159*4882a593Smuzhiyun "fail to set sampling rate: %d\n", err);
160*4882a593Smuzhiyun return err;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun err = snd_motu_stream_cache_packet_formats(motu);
164*4882a593Smuzhiyun if (err < 0)
165*4882a593Smuzhiyun return err;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun err = keep_resources(motu, rate, &motu->tx_stream);
168*4882a593Smuzhiyun if (err < 0)
169*4882a593Smuzhiyun return err;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun err = keep_resources(motu, rate, &motu->rx_stream);
172*4882a593Smuzhiyun if (err < 0) {
173*4882a593Smuzhiyun fw_iso_resources_free(&motu->tx_resources);
174*4882a593Smuzhiyun return err;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun err = amdtp_domain_set_events_per_period(&motu->domain,
178*4882a593Smuzhiyun frames_per_period, frames_per_buffer);
179*4882a593Smuzhiyun if (err < 0) {
180*4882a593Smuzhiyun fw_iso_resources_free(&motu->tx_resources);
181*4882a593Smuzhiyun fw_iso_resources_free(&motu->rx_resources);
182*4882a593Smuzhiyun return err;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
ensure_packet_formats(struct snd_motu * motu)189*4882a593Smuzhiyun static int ensure_packet_formats(struct snd_motu *motu)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun __be32 reg;
192*4882a593Smuzhiyun u32 data;
193*4882a593Smuzhiyun int err;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, ®,
196*4882a593Smuzhiyun sizeof(reg));
197*4882a593Smuzhiyun if (err < 0)
198*4882a593Smuzhiyun return err;
199*4882a593Smuzhiyun data = be32_to_cpu(reg);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
202*4882a593Smuzhiyun RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
203*4882a593Smuzhiyun TX_PACKET_TRANSMISSION_SPEED_MASK);
204*4882a593Smuzhiyun if (motu->spec->tx_fixed_pcm_chunks[0] == motu->tx_packet_formats.pcm_chunks[0])
205*4882a593Smuzhiyun data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
206*4882a593Smuzhiyun if (motu->spec->rx_fixed_pcm_chunks[0] == motu->rx_packet_formats.pcm_chunks[0])
207*4882a593Smuzhiyun data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
208*4882a593Smuzhiyun data |= fw_parent_device(motu->unit)->max_speed;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun reg = cpu_to_be32(data);
211*4882a593Smuzhiyun return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, ®,
212*4882a593Smuzhiyun sizeof(reg));
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
snd_motu_stream_start_duplex(struct snd_motu * motu)215*4882a593Smuzhiyun int snd_motu_stream_start_duplex(struct snd_motu *motu)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun unsigned int generation = motu->rx_resources.generation;
218*4882a593Smuzhiyun int err = 0;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if (motu->substreams_counter == 0)
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (amdtp_streaming_error(&motu->rx_stream) ||
224*4882a593Smuzhiyun amdtp_streaming_error(&motu->tx_stream)) {
225*4882a593Smuzhiyun amdtp_domain_stop(&motu->domain);
226*4882a593Smuzhiyun finish_session(motu);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun if (generation != fw_parent_device(motu->unit)->card->generation) {
230*4882a593Smuzhiyun err = fw_iso_resources_update(&motu->rx_resources);
231*4882a593Smuzhiyun if (err < 0)
232*4882a593Smuzhiyun return err;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun err = fw_iso_resources_update(&motu->tx_resources);
235*4882a593Smuzhiyun if (err < 0)
236*4882a593Smuzhiyun return err;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (!amdtp_stream_running(&motu->rx_stream)) {
240*4882a593Smuzhiyun int spd = fw_parent_device(motu->unit)->max_speed;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun err = ensure_packet_formats(motu);
243*4882a593Smuzhiyun if (err < 0)
244*4882a593Smuzhiyun return err;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun err = begin_session(motu);
247*4882a593Smuzhiyun if (err < 0) {
248*4882a593Smuzhiyun dev_err(&motu->unit->device,
249*4882a593Smuzhiyun "fail to start isochronous comm: %d\n", err);
250*4882a593Smuzhiyun goto stop_streams;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun err = amdtp_domain_add_stream(&motu->domain, &motu->tx_stream,
254*4882a593Smuzhiyun motu->tx_resources.channel, spd);
255*4882a593Smuzhiyun if (err < 0)
256*4882a593Smuzhiyun goto stop_streams;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun err = amdtp_domain_add_stream(&motu->domain, &motu->rx_stream,
259*4882a593Smuzhiyun motu->rx_resources.channel, spd);
260*4882a593Smuzhiyun if (err < 0)
261*4882a593Smuzhiyun goto stop_streams;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun err = amdtp_domain_start(&motu->domain, 0);
264*4882a593Smuzhiyun if (err < 0)
265*4882a593Smuzhiyun goto stop_streams;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (!amdtp_stream_wait_callback(&motu->tx_stream,
268*4882a593Smuzhiyun CALLBACK_TIMEOUT) ||
269*4882a593Smuzhiyun !amdtp_stream_wait_callback(&motu->rx_stream,
270*4882a593Smuzhiyun CALLBACK_TIMEOUT)) {
271*4882a593Smuzhiyun err = -ETIMEDOUT;
272*4882a593Smuzhiyun goto stop_streams;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun err = snd_motu_protocol_switch_fetching_mode(motu, true);
276*4882a593Smuzhiyun if (err < 0) {
277*4882a593Smuzhiyun dev_err(&motu->unit->device,
278*4882a593Smuzhiyun "fail to enable frame fetching: %d\n", err);
279*4882a593Smuzhiyun goto stop_streams;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun return 0;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun stop_streams:
286*4882a593Smuzhiyun amdtp_domain_stop(&motu->domain);
287*4882a593Smuzhiyun finish_session(motu);
288*4882a593Smuzhiyun return err;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
snd_motu_stream_stop_duplex(struct snd_motu * motu)291*4882a593Smuzhiyun void snd_motu_stream_stop_duplex(struct snd_motu *motu)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun if (motu->substreams_counter == 0) {
294*4882a593Smuzhiyun amdtp_domain_stop(&motu->domain);
295*4882a593Smuzhiyun finish_session(motu);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun fw_iso_resources_free(&motu->tx_resources);
298*4882a593Smuzhiyun fw_iso_resources_free(&motu->rx_resources);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
init_stream(struct snd_motu * motu,struct amdtp_stream * s)302*4882a593Smuzhiyun static int init_stream(struct snd_motu *motu, struct amdtp_stream *s)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun struct fw_iso_resources *resources;
305*4882a593Smuzhiyun enum amdtp_stream_direction dir;
306*4882a593Smuzhiyun int err;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (s == &motu->tx_stream) {
309*4882a593Smuzhiyun resources = &motu->tx_resources;
310*4882a593Smuzhiyun dir = AMDTP_IN_STREAM;
311*4882a593Smuzhiyun } else {
312*4882a593Smuzhiyun resources = &motu->rx_resources;
313*4882a593Smuzhiyun dir = AMDTP_OUT_STREAM;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun err = fw_iso_resources_init(resources, motu->unit);
317*4882a593Smuzhiyun if (err < 0)
318*4882a593Smuzhiyun return err;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun err = amdtp_motu_init(s, motu->unit, dir, motu->spec);
321*4882a593Smuzhiyun if (err < 0)
322*4882a593Smuzhiyun fw_iso_resources_destroy(resources);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun return err;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
destroy_stream(struct snd_motu * motu,struct amdtp_stream * s)327*4882a593Smuzhiyun static void destroy_stream(struct snd_motu *motu, struct amdtp_stream *s)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun amdtp_stream_destroy(s);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (s == &motu->tx_stream)
332*4882a593Smuzhiyun fw_iso_resources_destroy(&motu->tx_resources);
333*4882a593Smuzhiyun else
334*4882a593Smuzhiyun fw_iso_resources_destroy(&motu->rx_resources);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
snd_motu_stream_init_duplex(struct snd_motu * motu)337*4882a593Smuzhiyun int snd_motu_stream_init_duplex(struct snd_motu *motu)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun int err;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun err = init_stream(motu, &motu->tx_stream);
342*4882a593Smuzhiyun if (err < 0)
343*4882a593Smuzhiyun return err;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun err = init_stream(motu, &motu->rx_stream);
346*4882a593Smuzhiyun if (err < 0) {
347*4882a593Smuzhiyun destroy_stream(motu, &motu->tx_stream);
348*4882a593Smuzhiyun return err;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun err = amdtp_domain_init(&motu->domain);
352*4882a593Smuzhiyun if (err < 0) {
353*4882a593Smuzhiyun destroy_stream(motu, &motu->tx_stream);
354*4882a593Smuzhiyun destroy_stream(motu, &motu->rx_stream);
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun return err;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun // This function should be called before starting streams or after stopping
361*4882a593Smuzhiyun // streams.
snd_motu_stream_destroy_duplex(struct snd_motu * motu)362*4882a593Smuzhiyun void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun amdtp_domain_destroy(&motu->domain);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun destroy_stream(motu, &motu->rx_stream);
367*4882a593Smuzhiyun destroy_stream(motu, &motu->tx_stream);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun motu->substreams_counter = 0;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
motu_lock_changed(struct snd_motu * motu)372*4882a593Smuzhiyun static void motu_lock_changed(struct snd_motu *motu)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun motu->dev_lock_changed = true;
375*4882a593Smuzhiyun wake_up(&motu->hwdep_wait);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
snd_motu_stream_lock_try(struct snd_motu * motu)378*4882a593Smuzhiyun int snd_motu_stream_lock_try(struct snd_motu *motu)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun int err;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun spin_lock_irq(&motu->lock);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun if (motu->dev_lock_count < 0) {
385*4882a593Smuzhiyun err = -EBUSY;
386*4882a593Smuzhiyun goto out;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (motu->dev_lock_count++ == 0)
390*4882a593Smuzhiyun motu_lock_changed(motu);
391*4882a593Smuzhiyun err = 0;
392*4882a593Smuzhiyun out:
393*4882a593Smuzhiyun spin_unlock_irq(&motu->lock);
394*4882a593Smuzhiyun return err;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
snd_motu_stream_lock_release(struct snd_motu * motu)397*4882a593Smuzhiyun void snd_motu_stream_lock_release(struct snd_motu *motu)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun spin_lock_irq(&motu->lock);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (WARN_ON(motu->dev_lock_count <= 0))
402*4882a593Smuzhiyun goto out;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (--motu->dev_lock_count == 0)
405*4882a593Smuzhiyun motu_lock_changed(motu);
406*4882a593Smuzhiyun out:
407*4882a593Smuzhiyun spin_unlock_irq(&motu->lock);
408*4882a593Smuzhiyun }
409