1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * oxfw_stream.c - a part of driver for OXFW970/971 based devices
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2014 Takashi Sakamoto
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "oxfw.h"
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
12*4882a593Smuzhiyun #define CALLBACK_TIMEOUT 200
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun * According to datasheet of Oxford Semiconductor:
16*4882a593Smuzhiyun * OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
17*4882a593Smuzhiyun * OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun static const unsigned int oxfw_rate_table[] = {
20*4882a593Smuzhiyun [0] = 32000,
21*4882a593Smuzhiyun [1] = 44100,
22*4882a593Smuzhiyun [2] = 48000,
23*4882a593Smuzhiyun [3] = 88200,
24*4882a593Smuzhiyun [4] = 96000,
25*4882a593Smuzhiyun [5] = 192000,
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * See Table 5.7 – Sampling frequency for Multi-bit Audio
30*4882a593Smuzhiyun * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun static const unsigned int avc_stream_rate_table[] = {
33*4882a593Smuzhiyun [0] = 0x02,
34*4882a593Smuzhiyun [1] = 0x03,
35*4882a593Smuzhiyun [2] = 0x04,
36*4882a593Smuzhiyun [3] = 0x0a,
37*4882a593Smuzhiyun [4] = 0x05,
38*4882a593Smuzhiyun [5] = 0x07,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
set_rate(struct snd_oxfw * oxfw,unsigned int rate)41*4882a593Smuzhiyun static int set_rate(struct snd_oxfw *oxfw, unsigned int rate)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun int err;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun err = avc_general_set_sig_fmt(oxfw->unit, rate,
46*4882a593Smuzhiyun AVC_GENERAL_PLUG_DIR_IN, 0);
47*4882a593Smuzhiyun if (err < 0)
48*4882a593Smuzhiyun goto end;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (oxfw->has_output)
51*4882a593Smuzhiyun err = avc_general_set_sig_fmt(oxfw->unit, rate,
52*4882a593Smuzhiyun AVC_GENERAL_PLUG_DIR_OUT, 0);
53*4882a593Smuzhiyun end:
54*4882a593Smuzhiyun return err;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
set_stream_format(struct snd_oxfw * oxfw,struct amdtp_stream * s,unsigned int rate,unsigned int pcm_channels)57*4882a593Smuzhiyun static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
58*4882a593Smuzhiyun unsigned int rate, unsigned int pcm_channels)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun u8 **formats;
61*4882a593Smuzhiyun struct snd_oxfw_stream_formation formation;
62*4882a593Smuzhiyun enum avc_general_plug_dir dir;
63*4882a593Smuzhiyun unsigned int len;
64*4882a593Smuzhiyun int i, err;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (s == &oxfw->tx_stream) {
67*4882a593Smuzhiyun formats = oxfw->tx_stream_formats;
68*4882a593Smuzhiyun dir = AVC_GENERAL_PLUG_DIR_OUT;
69*4882a593Smuzhiyun } else {
70*4882a593Smuzhiyun formats = oxfw->rx_stream_formats;
71*4882a593Smuzhiyun dir = AVC_GENERAL_PLUG_DIR_IN;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* Seek stream format for requirements. */
75*4882a593Smuzhiyun for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
76*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(formats[i], &formation);
77*4882a593Smuzhiyun if (err < 0)
78*4882a593Smuzhiyun return err;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if ((formation.rate == rate) && (formation.pcm == pcm_channels))
81*4882a593Smuzhiyun break;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
84*4882a593Smuzhiyun return -EINVAL;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* If assumed, just change rate. */
87*4882a593Smuzhiyun if (oxfw->assumed)
88*4882a593Smuzhiyun return set_rate(oxfw, rate);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* Calculate format length. */
91*4882a593Smuzhiyun len = 5 + formats[i][4] * 2;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
94*4882a593Smuzhiyun if (err < 0)
95*4882a593Smuzhiyun return err;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /* Some requests just after changing format causes freezing. */
98*4882a593Smuzhiyun msleep(100);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
start_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)103*4882a593Smuzhiyun static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun struct cmp_connection *conn;
106*4882a593Smuzhiyun int err;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (stream == &oxfw->rx_stream)
109*4882a593Smuzhiyun conn = &oxfw->in_conn;
110*4882a593Smuzhiyun else
111*4882a593Smuzhiyun conn = &oxfw->out_conn;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun err = cmp_connection_establish(conn);
114*4882a593Smuzhiyun if (err < 0)
115*4882a593Smuzhiyun return err;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun err = amdtp_domain_add_stream(&oxfw->domain, stream,
118*4882a593Smuzhiyun conn->resources.channel, conn->speed);
119*4882a593Smuzhiyun if (err < 0) {
120*4882a593Smuzhiyun cmp_connection_break(conn);
121*4882a593Smuzhiyun return err;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return 0;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
check_connection_used_by_others(struct snd_oxfw * oxfw,struct amdtp_stream * stream)127*4882a593Smuzhiyun static int check_connection_used_by_others(struct snd_oxfw *oxfw,
128*4882a593Smuzhiyun struct amdtp_stream *stream)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun struct cmp_connection *conn;
131*4882a593Smuzhiyun bool used;
132*4882a593Smuzhiyun int err;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (stream == &oxfw->tx_stream)
135*4882a593Smuzhiyun conn = &oxfw->out_conn;
136*4882a593Smuzhiyun else
137*4882a593Smuzhiyun conn = &oxfw->in_conn;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun err = cmp_connection_check_used(conn, &used);
140*4882a593Smuzhiyun if ((err >= 0) && used && !amdtp_stream_running(stream)) {
141*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
142*4882a593Smuzhiyun "Connection established by others: %cPCR[%d]\n",
143*4882a593Smuzhiyun (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
144*4882a593Smuzhiyun conn->pcr_index);
145*4882a593Smuzhiyun err = -EBUSY;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return err;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
init_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)151*4882a593Smuzhiyun static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun struct cmp_connection *conn;
154*4882a593Smuzhiyun enum cmp_direction c_dir;
155*4882a593Smuzhiyun enum amdtp_stream_direction s_dir;
156*4882a593Smuzhiyun int err;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun if (stream == &oxfw->tx_stream) {
159*4882a593Smuzhiyun conn = &oxfw->out_conn;
160*4882a593Smuzhiyun c_dir = CMP_OUTPUT;
161*4882a593Smuzhiyun s_dir = AMDTP_IN_STREAM;
162*4882a593Smuzhiyun } else {
163*4882a593Smuzhiyun conn = &oxfw->in_conn;
164*4882a593Smuzhiyun c_dir = CMP_INPUT;
165*4882a593Smuzhiyun s_dir = AMDTP_OUT_STREAM;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
169*4882a593Smuzhiyun if (err < 0)
170*4882a593Smuzhiyun return err;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
173*4882a593Smuzhiyun if (err < 0) {
174*4882a593Smuzhiyun cmp_connection_destroy(conn);
175*4882a593Smuzhiyun return err;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun * OXFW starts to transmit packets with non-zero dbc.
180*4882a593Smuzhiyun * OXFW postpone transferring packets till handling any asynchronous
181*4882a593Smuzhiyun * packets. As a result, next isochronous packet includes more data
182*4882a593Smuzhiyun * blocks than IEC 61883-6 defines.
183*4882a593Smuzhiyun */
184*4882a593Smuzhiyun if (stream == &oxfw->tx_stream) {
185*4882a593Smuzhiyun oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD;
186*4882a593Smuzhiyun if (oxfw->wrong_dbs)
187*4882a593Smuzhiyun oxfw->tx_stream.flags |= CIP_WRONG_DBS;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun return 0;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
keep_resources(struct snd_oxfw * oxfw,struct amdtp_stream * stream)193*4882a593Smuzhiyun static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun enum avc_general_plug_dir dir;
196*4882a593Smuzhiyun u8 **formats;
197*4882a593Smuzhiyun struct snd_oxfw_stream_formation formation;
198*4882a593Smuzhiyun struct cmp_connection *conn;
199*4882a593Smuzhiyun int i;
200*4882a593Smuzhiyun int err;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (stream == &oxfw->rx_stream) {
203*4882a593Smuzhiyun dir = AVC_GENERAL_PLUG_DIR_IN;
204*4882a593Smuzhiyun formats = oxfw->rx_stream_formats;
205*4882a593Smuzhiyun conn = &oxfw->in_conn;
206*4882a593Smuzhiyun } else {
207*4882a593Smuzhiyun dir = AVC_GENERAL_PLUG_DIR_OUT;
208*4882a593Smuzhiyun formats = oxfw->tx_stream_formats;
209*4882a593Smuzhiyun conn = &oxfw->out_conn;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
213*4882a593Smuzhiyun if (err < 0)
214*4882a593Smuzhiyun return err;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
217*4882a593Smuzhiyun struct snd_oxfw_stream_formation fmt;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (formats[i] == NULL)
220*4882a593Smuzhiyun break;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(formats[i], &fmt);
223*4882a593Smuzhiyun if (err < 0)
224*4882a593Smuzhiyun return err;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
227*4882a593Smuzhiyun fmt.midi == formation.midi)
228*4882a593Smuzhiyun break;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
231*4882a593Smuzhiyun return -EINVAL;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun // The stream should have one pcm channels at least.
234*4882a593Smuzhiyun if (formation.pcm == 0)
235*4882a593Smuzhiyun return -EINVAL;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
238*4882a593Smuzhiyun formation.midi * 8, false);
239*4882a593Smuzhiyun if (err < 0)
240*4882a593Smuzhiyun return err;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
snd_oxfw_stream_reserve_duplex(struct snd_oxfw * oxfw,struct amdtp_stream * stream,unsigned int rate,unsigned int pcm_channels,unsigned int frames_per_period,unsigned int frames_per_buffer)245*4882a593Smuzhiyun int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
246*4882a593Smuzhiyun struct amdtp_stream *stream,
247*4882a593Smuzhiyun unsigned int rate, unsigned int pcm_channels,
248*4882a593Smuzhiyun unsigned int frames_per_period,
249*4882a593Smuzhiyun unsigned int frames_per_buffer)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct snd_oxfw_stream_formation formation;
252*4882a593Smuzhiyun enum avc_general_plug_dir dir;
253*4882a593Smuzhiyun int err;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun // Considering JACK/FFADO streaming:
256*4882a593Smuzhiyun // TODO: This can be removed hwdep functionality becomes popular.
257*4882a593Smuzhiyun err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
258*4882a593Smuzhiyun if (err < 0)
259*4882a593Smuzhiyun return err;
260*4882a593Smuzhiyun if (oxfw->has_output) {
261*4882a593Smuzhiyun err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
262*4882a593Smuzhiyun if (err < 0)
263*4882a593Smuzhiyun return err;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (stream == &oxfw->tx_stream)
267*4882a593Smuzhiyun dir = AVC_GENERAL_PLUG_DIR_OUT;
268*4882a593Smuzhiyun else
269*4882a593Smuzhiyun dir = AVC_GENERAL_PLUG_DIR_IN;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
272*4882a593Smuzhiyun if (err < 0)
273*4882a593Smuzhiyun return err;
274*4882a593Smuzhiyun if (rate == 0) {
275*4882a593Smuzhiyun rate = formation.rate;
276*4882a593Smuzhiyun pcm_channels = formation.pcm;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun if (formation.rate != rate || formation.pcm != pcm_channels) {
279*4882a593Smuzhiyun amdtp_domain_stop(&oxfw->domain);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun cmp_connection_break(&oxfw->in_conn);
282*4882a593Smuzhiyun cmp_connection_release(&oxfw->in_conn);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun if (oxfw->has_output) {
285*4882a593Smuzhiyun cmp_connection_break(&oxfw->out_conn);
286*4882a593Smuzhiyun cmp_connection_release(&oxfw->out_conn);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (oxfw->substreams_count == 0 ||
291*4882a593Smuzhiyun formation.rate != rate || formation.pcm != pcm_channels) {
292*4882a593Smuzhiyun err = set_stream_format(oxfw, stream, rate, pcm_channels);
293*4882a593Smuzhiyun if (err < 0) {
294*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
295*4882a593Smuzhiyun "fail to set stream format: %d\n", err);
296*4882a593Smuzhiyun return err;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun err = keep_resources(oxfw, &oxfw->rx_stream);
300*4882a593Smuzhiyun if (err < 0)
301*4882a593Smuzhiyun return err;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (oxfw->has_output) {
304*4882a593Smuzhiyun err = keep_resources(oxfw, &oxfw->tx_stream);
305*4882a593Smuzhiyun if (err < 0) {
306*4882a593Smuzhiyun cmp_connection_release(&oxfw->in_conn);
307*4882a593Smuzhiyun return err;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun err = amdtp_domain_set_events_per_period(&oxfw->domain,
312*4882a593Smuzhiyun frames_per_period, frames_per_buffer);
313*4882a593Smuzhiyun if (err < 0) {
314*4882a593Smuzhiyun cmp_connection_release(&oxfw->in_conn);
315*4882a593Smuzhiyun if (oxfw->has_output)
316*4882a593Smuzhiyun cmp_connection_release(&oxfw->out_conn);
317*4882a593Smuzhiyun return err;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun return 0;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
snd_oxfw_stream_start_duplex(struct snd_oxfw * oxfw)324*4882a593Smuzhiyun int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun int err;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun if (oxfw->substreams_count == 0)
329*4882a593Smuzhiyun return -EIO;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (amdtp_streaming_error(&oxfw->rx_stream) ||
332*4882a593Smuzhiyun amdtp_streaming_error(&oxfw->tx_stream)) {
333*4882a593Smuzhiyun amdtp_domain_stop(&oxfw->domain);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun cmp_connection_break(&oxfw->in_conn);
336*4882a593Smuzhiyun if (oxfw->has_output)
337*4882a593Smuzhiyun cmp_connection_break(&oxfw->out_conn);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (!amdtp_stream_running(&oxfw->rx_stream)) {
341*4882a593Smuzhiyun err = start_stream(oxfw, &oxfw->rx_stream);
342*4882a593Smuzhiyun if (err < 0) {
343*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
344*4882a593Smuzhiyun "fail to prepare rx stream: %d\n", err);
345*4882a593Smuzhiyun goto error;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (oxfw->has_output &&
349*4882a593Smuzhiyun !amdtp_stream_running(&oxfw->tx_stream)) {
350*4882a593Smuzhiyun err = start_stream(oxfw, &oxfw->tx_stream);
351*4882a593Smuzhiyun if (err < 0) {
352*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
353*4882a593Smuzhiyun "fail to prepare tx stream: %d\n", err);
354*4882a593Smuzhiyun goto error;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun err = amdtp_domain_start(&oxfw->domain, 0);
359*4882a593Smuzhiyun if (err < 0)
360*4882a593Smuzhiyun goto error;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun // Wait first packet.
363*4882a593Smuzhiyun if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
364*4882a593Smuzhiyun CALLBACK_TIMEOUT)) {
365*4882a593Smuzhiyun err = -ETIMEDOUT;
366*4882a593Smuzhiyun goto error;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (oxfw->has_output) {
370*4882a593Smuzhiyun if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
371*4882a593Smuzhiyun CALLBACK_TIMEOUT)) {
372*4882a593Smuzhiyun err = -ETIMEDOUT;
373*4882a593Smuzhiyun goto error;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun return 0;
379*4882a593Smuzhiyun error:
380*4882a593Smuzhiyun amdtp_domain_stop(&oxfw->domain);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun cmp_connection_break(&oxfw->in_conn);
383*4882a593Smuzhiyun if (oxfw->has_output)
384*4882a593Smuzhiyun cmp_connection_break(&oxfw->out_conn);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return err;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
snd_oxfw_stream_stop_duplex(struct snd_oxfw * oxfw)389*4882a593Smuzhiyun void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun if (oxfw->substreams_count == 0) {
392*4882a593Smuzhiyun amdtp_domain_stop(&oxfw->domain);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun cmp_connection_break(&oxfw->in_conn);
395*4882a593Smuzhiyun cmp_connection_release(&oxfw->in_conn);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (oxfw->has_output) {
398*4882a593Smuzhiyun cmp_connection_break(&oxfw->out_conn);
399*4882a593Smuzhiyun cmp_connection_release(&oxfw->out_conn);
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
destroy_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)404*4882a593Smuzhiyun static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct cmp_connection *conn;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (stream == &oxfw->tx_stream)
409*4882a593Smuzhiyun conn = &oxfw->out_conn;
410*4882a593Smuzhiyun else
411*4882a593Smuzhiyun conn = &oxfw->in_conn;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun amdtp_stream_destroy(stream);
414*4882a593Smuzhiyun cmp_connection_destroy(conn);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
snd_oxfw_stream_init_duplex(struct snd_oxfw * oxfw)417*4882a593Smuzhiyun int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun int err;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun err = init_stream(oxfw, &oxfw->rx_stream);
422*4882a593Smuzhiyun if (err < 0)
423*4882a593Smuzhiyun return err;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun if (oxfw->has_output) {
426*4882a593Smuzhiyun err = init_stream(oxfw, &oxfw->tx_stream);
427*4882a593Smuzhiyun if (err < 0) {
428*4882a593Smuzhiyun destroy_stream(oxfw, &oxfw->rx_stream);
429*4882a593Smuzhiyun return err;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun err = amdtp_domain_init(&oxfw->domain);
434*4882a593Smuzhiyun if (err < 0) {
435*4882a593Smuzhiyun destroy_stream(oxfw, &oxfw->rx_stream);
436*4882a593Smuzhiyun if (oxfw->has_output)
437*4882a593Smuzhiyun destroy_stream(oxfw, &oxfw->tx_stream);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun return err;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun // This function should be called before starting the stream or after stopping
444*4882a593Smuzhiyun // the streams.
snd_oxfw_stream_destroy_duplex(struct snd_oxfw * oxfw)445*4882a593Smuzhiyun void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun amdtp_domain_destroy(&oxfw->domain);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun destroy_stream(oxfw, &oxfw->rx_stream);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (oxfw->has_output)
452*4882a593Smuzhiyun destroy_stream(oxfw, &oxfw->tx_stream);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
snd_oxfw_stream_update_duplex(struct snd_oxfw * oxfw)455*4882a593Smuzhiyun void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun amdtp_domain_stop(&oxfw->domain);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun cmp_connection_break(&oxfw->in_conn);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun amdtp_stream_pcm_abort(&oxfw->rx_stream);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (oxfw->has_output) {
464*4882a593Smuzhiyun cmp_connection_break(&oxfw->out_conn);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun amdtp_stream_pcm_abort(&oxfw->tx_stream);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
snd_oxfw_stream_get_current_formation(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,struct snd_oxfw_stream_formation * formation)470*4882a593Smuzhiyun int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
471*4882a593Smuzhiyun enum avc_general_plug_dir dir,
472*4882a593Smuzhiyun struct snd_oxfw_stream_formation *formation)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun u8 *format;
475*4882a593Smuzhiyun unsigned int len;
476*4882a593Smuzhiyun int err;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
479*4882a593Smuzhiyun format = kmalloc(len, GFP_KERNEL);
480*4882a593Smuzhiyun if (format == NULL)
481*4882a593Smuzhiyun return -ENOMEM;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
484*4882a593Smuzhiyun if (err < 0)
485*4882a593Smuzhiyun goto end;
486*4882a593Smuzhiyun if (len < 3) {
487*4882a593Smuzhiyun err = -EIO;
488*4882a593Smuzhiyun goto end;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(format, formation);
492*4882a593Smuzhiyun end:
493*4882a593Smuzhiyun kfree(format);
494*4882a593Smuzhiyun return err;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /*
498*4882a593Smuzhiyun * See Table 6.16 - AM824 Stream Format
499*4882a593Smuzhiyun * Figure 6.19 - format_information field for AM824 Compound
500*4882a593Smuzhiyun * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
501*4882a593Smuzhiyun * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
502*4882a593Smuzhiyun */
snd_oxfw_stream_parse_format(u8 * format,struct snd_oxfw_stream_formation * formation)503*4882a593Smuzhiyun int snd_oxfw_stream_parse_format(u8 *format,
504*4882a593Smuzhiyun struct snd_oxfw_stream_formation *formation)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun unsigned int i, e, channels, type;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /*
511*4882a593Smuzhiyun * this module can support a hierarchy combination that:
512*4882a593Smuzhiyun * Root: Audio and Music (0x90)
513*4882a593Smuzhiyun * Level 1: AM824 Compound (0x40)
514*4882a593Smuzhiyun */
515*4882a593Smuzhiyun if ((format[0] != 0x90) || (format[1] != 0x40))
516*4882a593Smuzhiyun return -ENXIO;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /* check the sampling rate */
519*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
520*4882a593Smuzhiyun if (format[2] == avc_stream_rate_table[i])
521*4882a593Smuzhiyun break;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun if (i == ARRAY_SIZE(avc_stream_rate_table))
524*4882a593Smuzhiyun return -ENXIO;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun formation->rate = oxfw_rate_table[i];
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun for (e = 0; e < format[4]; e++) {
529*4882a593Smuzhiyun channels = format[5 + e * 2];
530*4882a593Smuzhiyun type = format[6 + e * 2];
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun switch (type) {
533*4882a593Smuzhiyun /* IEC 60958 Conformant, currently handled as MBLA */
534*4882a593Smuzhiyun case 0x00:
535*4882a593Smuzhiyun /* Multi Bit Linear Audio (Raw) */
536*4882a593Smuzhiyun case 0x06:
537*4882a593Smuzhiyun formation->pcm += channels;
538*4882a593Smuzhiyun break;
539*4882a593Smuzhiyun /* MIDI Conformant */
540*4882a593Smuzhiyun case 0x0d:
541*4882a593Smuzhiyun formation->midi = channels;
542*4882a593Smuzhiyun break;
543*4882a593Smuzhiyun /* IEC 61937-3 to 7 */
544*4882a593Smuzhiyun case 0x01:
545*4882a593Smuzhiyun case 0x02:
546*4882a593Smuzhiyun case 0x03:
547*4882a593Smuzhiyun case 0x04:
548*4882a593Smuzhiyun case 0x05:
549*4882a593Smuzhiyun /* Multi Bit Linear Audio */
550*4882a593Smuzhiyun case 0x07: /* DVD-Audio */
551*4882a593Smuzhiyun case 0x0c: /* High Precision */
552*4882a593Smuzhiyun /* One Bit Audio */
553*4882a593Smuzhiyun case 0x08: /* (Plain) Raw */
554*4882a593Smuzhiyun case 0x09: /* (Plain) SACD */
555*4882a593Smuzhiyun case 0x0a: /* (Encoded) Raw */
556*4882a593Smuzhiyun case 0x0b: /* (Encoded) SACD */
557*4882a593Smuzhiyun /* SMPTE Time-Code conformant */
558*4882a593Smuzhiyun case 0x0e:
559*4882a593Smuzhiyun /* Sample Count */
560*4882a593Smuzhiyun case 0x0f:
561*4882a593Smuzhiyun /* Anciliary Data */
562*4882a593Smuzhiyun case 0x10:
563*4882a593Smuzhiyun /* Synchronization Stream (Stereo Raw audio) */
564*4882a593Smuzhiyun case 0x40:
565*4882a593Smuzhiyun /* Don't care */
566*4882a593Smuzhiyun case 0xff:
567*4882a593Smuzhiyun default:
568*4882a593Smuzhiyun return -ENXIO; /* not supported */
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun if (formation->pcm > AM824_MAX_CHANNELS_FOR_PCM ||
573*4882a593Smuzhiyun formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
574*4882a593Smuzhiyun return -ENXIO;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun return 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun static int
assume_stream_formats(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,unsigned int pid,u8 * buf,unsigned int * len,u8 ** formats)580*4882a593Smuzhiyun assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
581*4882a593Smuzhiyun unsigned int pid, u8 *buf, unsigned int *len,
582*4882a593Smuzhiyun u8 **formats)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun struct snd_oxfw_stream_formation formation;
585*4882a593Smuzhiyun unsigned int i, eid;
586*4882a593Smuzhiyun int err;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /* get format at current sampling rate */
589*4882a593Smuzhiyun err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
590*4882a593Smuzhiyun if (err < 0) {
591*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
592*4882a593Smuzhiyun "fail to get current stream format for isoc %s plug %d:%d\n",
593*4882a593Smuzhiyun (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
594*4882a593Smuzhiyun pid, err);
595*4882a593Smuzhiyun goto end;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun /* parse and set stream format */
599*4882a593Smuzhiyun eid = 0;
600*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(buf, &formation);
601*4882a593Smuzhiyun if (err < 0)
602*4882a593Smuzhiyun goto end;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
605*4882a593Smuzhiyun GFP_KERNEL);
606*4882a593Smuzhiyun if (!formats[eid]) {
607*4882a593Smuzhiyun err = -ENOMEM;
608*4882a593Smuzhiyun goto end;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun /* apply the format for each available sampling rate */
612*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
613*4882a593Smuzhiyun if (formation.rate == oxfw_rate_table[i])
614*4882a593Smuzhiyun continue;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun err = avc_general_inquiry_sig_fmt(oxfw->unit,
617*4882a593Smuzhiyun oxfw_rate_table[i],
618*4882a593Smuzhiyun dir, pid);
619*4882a593Smuzhiyun if (err < 0)
620*4882a593Smuzhiyun continue;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun eid++;
623*4882a593Smuzhiyun formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
624*4882a593Smuzhiyun GFP_KERNEL);
625*4882a593Smuzhiyun if (formats[eid] == NULL) {
626*4882a593Smuzhiyun err = -ENOMEM;
627*4882a593Smuzhiyun goto end;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun formats[eid][2] = avc_stream_rate_table[i];
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun err = 0;
633*4882a593Smuzhiyun oxfw->assumed = true;
634*4882a593Smuzhiyun end:
635*4882a593Smuzhiyun return err;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
fill_stream_formats(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,unsigned short pid)638*4882a593Smuzhiyun static int fill_stream_formats(struct snd_oxfw *oxfw,
639*4882a593Smuzhiyun enum avc_general_plug_dir dir,
640*4882a593Smuzhiyun unsigned short pid)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun u8 *buf, **formats;
643*4882a593Smuzhiyun unsigned int len, eid = 0;
644*4882a593Smuzhiyun struct snd_oxfw_stream_formation dummy;
645*4882a593Smuzhiyun int err;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
648*4882a593Smuzhiyun if (buf == NULL)
649*4882a593Smuzhiyun return -ENOMEM;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun if (dir == AVC_GENERAL_PLUG_DIR_OUT)
652*4882a593Smuzhiyun formats = oxfw->tx_stream_formats;
653*4882a593Smuzhiyun else
654*4882a593Smuzhiyun formats = oxfw->rx_stream_formats;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun /* get first entry */
657*4882a593Smuzhiyun len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
658*4882a593Smuzhiyun err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
659*4882a593Smuzhiyun if (err == -ENXIO) {
660*4882a593Smuzhiyun /* LIST subfunction is not implemented */
661*4882a593Smuzhiyun len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
662*4882a593Smuzhiyun err = assume_stream_formats(oxfw, dir, pid, buf, &len,
663*4882a593Smuzhiyun formats);
664*4882a593Smuzhiyun goto end;
665*4882a593Smuzhiyun } else if (err < 0) {
666*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
667*4882a593Smuzhiyun "fail to get stream format %d for isoc %s plug %d:%d\n",
668*4882a593Smuzhiyun eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
669*4882a593Smuzhiyun pid, err);
670*4882a593Smuzhiyun goto end;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun /* LIST subfunction is implemented */
674*4882a593Smuzhiyun while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
675*4882a593Smuzhiyun /* The format is too short. */
676*4882a593Smuzhiyun if (len < 3) {
677*4882a593Smuzhiyun err = -EIO;
678*4882a593Smuzhiyun break;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun /* parse and set stream format */
682*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(buf, &dummy);
683*4882a593Smuzhiyun if (err < 0)
684*4882a593Smuzhiyun break;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
687*4882a593Smuzhiyun GFP_KERNEL);
688*4882a593Smuzhiyun if (!formats[eid]) {
689*4882a593Smuzhiyun err = -ENOMEM;
690*4882a593Smuzhiyun break;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun /* get next entry */
694*4882a593Smuzhiyun len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
695*4882a593Smuzhiyun err = avc_stream_get_format_list(oxfw->unit, dir, 0,
696*4882a593Smuzhiyun buf, &len, ++eid);
697*4882a593Smuzhiyun /* No entries remained. */
698*4882a593Smuzhiyun if (err == -EINVAL) {
699*4882a593Smuzhiyun err = 0;
700*4882a593Smuzhiyun break;
701*4882a593Smuzhiyun } else if (err < 0) {
702*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
703*4882a593Smuzhiyun "fail to get stream format %d for isoc %s plug %d:%d\n",
704*4882a593Smuzhiyun eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
705*4882a593Smuzhiyun "out",
706*4882a593Smuzhiyun pid, err);
707*4882a593Smuzhiyun break;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun end:
711*4882a593Smuzhiyun kfree(buf);
712*4882a593Smuzhiyun return err;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
snd_oxfw_stream_discover(struct snd_oxfw * oxfw)715*4882a593Smuzhiyun int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
718*4882a593Smuzhiyun struct snd_oxfw_stream_formation formation;
719*4882a593Smuzhiyun u8 *format;
720*4882a593Smuzhiyun unsigned int i;
721*4882a593Smuzhiyun int err;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun /* the number of plugs for isoc in/out, ext in/out */
724*4882a593Smuzhiyun err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
725*4882a593Smuzhiyun if (err < 0) {
726*4882a593Smuzhiyun dev_err(&oxfw->unit->device,
727*4882a593Smuzhiyun "fail to get info for isoc/external in/out plugs: %d\n",
728*4882a593Smuzhiyun err);
729*4882a593Smuzhiyun goto end;
730*4882a593Smuzhiyun } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
731*4882a593Smuzhiyun err = -ENXIO;
732*4882a593Smuzhiyun goto end;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun /* use oPCR[0] if exists */
736*4882a593Smuzhiyun if (plugs[1] > 0) {
737*4882a593Smuzhiyun err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
738*4882a593Smuzhiyun if (err < 0) {
739*4882a593Smuzhiyun if (err != -ENXIO)
740*4882a593Smuzhiyun return err;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun // The oPCR is not available for isoc communication.
743*4882a593Smuzhiyun err = 0;
744*4882a593Smuzhiyun } else {
745*4882a593Smuzhiyun for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
746*4882a593Smuzhiyun format = oxfw->tx_stream_formats[i];
747*4882a593Smuzhiyun if (format == NULL)
748*4882a593Smuzhiyun continue;
749*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(format,
750*4882a593Smuzhiyun &formation);
751*4882a593Smuzhiyun if (err < 0)
752*4882a593Smuzhiyun continue;
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /* Add one MIDI port. */
755*4882a593Smuzhiyun if (formation.midi > 0)
756*4882a593Smuzhiyun oxfw->midi_input_ports = 1;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun oxfw->has_output = true;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun /* use iPCR[0] if exists */
764*4882a593Smuzhiyun if (plugs[0] > 0) {
765*4882a593Smuzhiyun err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
766*4882a593Smuzhiyun if (err < 0) {
767*4882a593Smuzhiyun if (err != -ENXIO)
768*4882a593Smuzhiyun return err;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun // The iPCR is not available for isoc communication.
771*4882a593Smuzhiyun err = 0;
772*4882a593Smuzhiyun } else {
773*4882a593Smuzhiyun for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
774*4882a593Smuzhiyun format = oxfw->rx_stream_formats[i];
775*4882a593Smuzhiyun if (format == NULL)
776*4882a593Smuzhiyun continue;
777*4882a593Smuzhiyun err = snd_oxfw_stream_parse_format(format,
778*4882a593Smuzhiyun &formation);
779*4882a593Smuzhiyun if (err < 0)
780*4882a593Smuzhiyun continue;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun /* Add one MIDI port. */
783*4882a593Smuzhiyun if (formation.midi > 0)
784*4882a593Smuzhiyun oxfw->midi_output_ports = 1;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun oxfw->has_input = true;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun end:
791*4882a593Smuzhiyun return err;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
snd_oxfw_stream_lock_changed(struct snd_oxfw * oxfw)794*4882a593Smuzhiyun void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
795*4882a593Smuzhiyun {
796*4882a593Smuzhiyun oxfw->dev_lock_changed = true;
797*4882a593Smuzhiyun wake_up(&oxfw->hwdep_wait);
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
snd_oxfw_stream_lock_try(struct snd_oxfw * oxfw)800*4882a593Smuzhiyun int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
801*4882a593Smuzhiyun {
802*4882a593Smuzhiyun int err;
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun spin_lock_irq(&oxfw->lock);
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun /* user land lock this */
807*4882a593Smuzhiyun if (oxfw->dev_lock_count < 0) {
808*4882a593Smuzhiyun err = -EBUSY;
809*4882a593Smuzhiyun goto end;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun /* this is the first time */
813*4882a593Smuzhiyun if (oxfw->dev_lock_count++ == 0)
814*4882a593Smuzhiyun snd_oxfw_stream_lock_changed(oxfw);
815*4882a593Smuzhiyun err = 0;
816*4882a593Smuzhiyun end:
817*4882a593Smuzhiyun spin_unlock_irq(&oxfw->lock);
818*4882a593Smuzhiyun return err;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
snd_oxfw_stream_lock_release(struct snd_oxfw * oxfw)821*4882a593Smuzhiyun void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun spin_lock_irq(&oxfw->lock);
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun if (WARN_ON(oxfw->dev_lock_count <= 0))
826*4882a593Smuzhiyun goto end;
827*4882a593Smuzhiyun if (--oxfw->dev_lock_count == 0)
828*4882a593Smuzhiyun snd_oxfw_stream_lock_changed(oxfw);
829*4882a593Smuzhiyun end:
830*4882a593Smuzhiyun spin_unlock_irq(&oxfw->lock);
831*4882a593Smuzhiyun }
832