1e2786ca6STakashi Sakamoto /*
2e2786ca6STakashi Sakamoto  * oxfw_stream.c - a part of driver for OXFW970/971 based devices
3e2786ca6STakashi Sakamoto  *
4e2786ca6STakashi Sakamoto  * Copyright (c) 2014 Takashi Sakamoto
5e2786ca6STakashi Sakamoto  *
6e2786ca6STakashi Sakamoto  * Licensed under the terms of the GNU General Public License, version 2.
7e2786ca6STakashi Sakamoto  */
8e2786ca6STakashi Sakamoto 
9e2786ca6STakashi Sakamoto #include "oxfw.h"
10e2786ca6STakashi Sakamoto 
115cd1d3f4STakashi Sakamoto #define AVC_GENERIC_FRAME_MAXIMUM_BYTES	512
125cd1d3f4STakashi Sakamoto 
135cd1d3f4STakashi Sakamoto /*
145cd1d3f4STakashi Sakamoto  * According to datasheet of Oxford Semiconductor:
155cd1d3f4STakashi Sakamoto  *  OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
165cd1d3f4STakashi Sakamoto  *  OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
175cd1d3f4STakashi Sakamoto  */
185cd1d3f4STakashi Sakamoto static const unsigned int oxfw_rate_table[] = {
195cd1d3f4STakashi Sakamoto 	[0] = 32000,
205cd1d3f4STakashi Sakamoto 	[1] = 44100,
215cd1d3f4STakashi Sakamoto 	[2] = 48000,
225cd1d3f4STakashi Sakamoto 	[3] = 88200,
235cd1d3f4STakashi Sakamoto 	[4] = 96000,
245cd1d3f4STakashi Sakamoto 	[5] = 192000,
255cd1d3f4STakashi Sakamoto };
265cd1d3f4STakashi Sakamoto 
275cd1d3f4STakashi Sakamoto /*
285cd1d3f4STakashi Sakamoto  * See Table 5.7 – Sampling frequency for Multi-bit Audio
295cd1d3f4STakashi Sakamoto  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
305cd1d3f4STakashi Sakamoto  */
315cd1d3f4STakashi Sakamoto static const unsigned int avc_stream_rate_table[] = {
325cd1d3f4STakashi Sakamoto 	[0] = 0x02,
335cd1d3f4STakashi Sakamoto 	[1] = 0x03,
345cd1d3f4STakashi Sakamoto 	[2] = 0x04,
355cd1d3f4STakashi Sakamoto 	[3] = 0x0a,
365cd1d3f4STakashi Sakamoto 	[4] = 0x05,
375cd1d3f4STakashi Sakamoto 	[5] = 0x07,
385cd1d3f4STakashi Sakamoto };
395cd1d3f4STakashi Sakamoto 
40e2786ca6STakashi Sakamoto int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw)
41e2786ca6STakashi Sakamoto {
42e2786ca6STakashi Sakamoto 	int err;
43e2786ca6STakashi Sakamoto 
44e2786ca6STakashi Sakamoto 	err = cmp_connection_init(&oxfw->in_conn, oxfw->unit,
45e2786ca6STakashi Sakamoto 				  CMP_INPUT, 0);
46e2786ca6STakashi Sakamoto 	if (err < 0)
47e2786ca6STakashi Sakamoto 		goto end;
48e2786ca6STakashi Sakamoto 
49e2786ca6STakashi Sakamoto 	err = amdtp_stream_init(&oxfw->rx_stream, oxfw->unit,
50e2786ca6STakashi Sakamoto 				AMDTP_OUT_STREAM, CIP_NONBLOCKING);
51e2786ca6STakashi Sakamoto 	if (err < 0) {
52e2786ca6STakashi Sakamoto 		amdtp_stream_destroy(&oxfw->rx_stream);
53e2786ca6STakashi Sakamoto 		cmp_connection_destroy(&oxfw->in_conn);
54e2786ca6STakashi Sakamoto 	}
55e2786ca6STakashi Sakamoto end:
56e2786ca6STakashi Sakamoto 	return err;
57e2786ca6STakashi Sakamoto }
58e2786ca6STakashi Sakamoto 
59e2786ca6STakashi Sakamoto static void stop_stream(struct snd_oxfw *oxfw)
60e2786ca6STakashi Sakamoto {
61e2786ca6STakashi Sakamoto 	amdtp_stream_pcm_abort(&oxfw->rx_stream);
62e2786ca6STakashi Sakamoto 	amdtp_stream_stop(&oxfw->rx_stream);
63e2786ca6STakashi Sakamoto 	cmp_connection_break(&oxfw->in_conn);
64e2786ca6STakashi Sakamoto }
65e2786ca6STakashi Sakamoto 
66e2786ca6STakashi Sakamoto int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw)
67e2786ca6STakashi Sakamoto {
68e2786ca6STakashi Sakamoto 	int err = 0;
69e2786ca6STakashi Sakamoto 
70e2786ca6STakashi Sakamoto 	if (amdtp_streaming_error(&oxfw->rx_stream))
71e2786ca6STakashi Sakamoto 		stop_stream(oxfw);
72e2786ca6STakashi Sakamoto 
73e2786ca6STakashi Sakamoto 	if (amdtp_stream_running(&oxfw->rx_stream))
74e2786ca6STakashi Sakamoto 		goto end;
75e2786ca6STakashi Sakamoto 
76e2786ca6STakashi Sakamoto 	err = cmp_connection_establish(&oxfw->in_conn,
77e2786ca6STakashi Sakamoto 			amdtp_stream_get_max_payload(&oxfw->rx_stream));
78e2786ca6STakashi Sakamoto 	if (err < 0)
79e2786ca6STakashi Sakamoto 		goto end;
80e2786ca6STakashi Sakamoto 
81e2786ca6STakashi Sakamoto 	err = amdtp_stream_start(&oxfw->rx_stream,
82e2786ca6STakashi Sakamoto 				 oxfw->in_conn.resources.channel,
83e2786ca6STakashi Sakamoto 				 oxfw->in_conn.speed);
84e2786ca6STakashi Sakamoto 	if (err < 0)
85e2786ca6STakashi Sakamoto 		stop_stream(oxfw);
86e2786ca6STakashi Sakamoto end:
87e2786ca6STakashi Sakamoto 	return err;
88e2786ca6STakashi Sakamoto }
89e2786ca6STakashi Sakamoto 
90e2786ca6STakashi Sakamoto void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw)
91e2786ca6STakashi Sakamoto {
92e2786ca6STakashi Sakamoto 	stop_stream(oxfw);
93e2786ca6STakashi Sakamoto }
94e2786ca6STakashi Sakamoto 
95e2786ca6STakashi Sakamoto void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw)
96e2786ca6STakashi Sakamoto {
97e2786ca6STakashi Sakamoto 	stop_stream(oxfw);
98e2786ca6STakashi Sakamoto 
99e2786ca6STakashi Sakamoto 	amdtp_stream_destroy(&oxfw->rx_stream);
100e2786ca6STakashi Sakamoto 	cmp_connection_destroy(&oxfw->in_conn);
101e2786ca6STakashi Sakamoto }
102e2786ca6STakashi Sakamoto 
103e2786ca6STakashi Sakamoto void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw)
104e2786ca6STakashi Sakamoto {
105e2786ca6STakashi Sakamoto 	if (cmp_connection_update(&oxfw->in_conn) < 0)
106e2786ca6STakashi Sakamoto 		stop_stream(oxfw);
107e2786ca6STakashi Sakamoto 	else
108e2786ca6STakashi Sakamoto 		amdtp_stream_update(&oxfw->rx_stream);
109e2786ca6STakashi Sakamoto }
1105cd1d3f4STakashi Sakamoto 
1115cd1d3f4STakashi Sakamoto /*
1125cd1d3f4STakashi Sakamoto  * See Table 6.16 - AM824 Stream Format
1135cd1d3f4STakashi Sakamoto  *     Figure 6.19 - format_information field for AM824 Compound
1145cd1d3f4STakashi Sakamoto  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
1155cd1d3f4STakashi Sakamoto  * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
1165cd1d3f4STakashi Sakamoto  */
1175cd1d3f4STakashi Sakamoto int snd_oxfw_stream_parse_format(u8 *format,
1185cd1d3f4STakashi Sakamoto 				 struct snd_oxfw_stream_formation *formation)
1195cd1d3f4STakashi Sakamoto {
1205cd1d3f4STakashi Sakamoto 	unsigned int i, e, channels, type;
1215cd1d3f4STakashi Sakamoto 
1225cd1d3f4STakashi Sakamoto 	memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
1235cd1d3f4STakashi Sakamoto 
1245cd1d3f4STakashi Sakamoto 	/*
1255cd1d3f4STakashi Sakamoto 	 * this module can support a hierarchy combination that:
1265cd1d3f4STakashi Sakamoto 	 *  Root:	Audio and Music (0x90)
1275cd1d3f4STakashi Sakamoto 	 *  Level 1:	AM824 Compound  (0x40)
1285cd1d3f4STakashi Sakamoto 	 */
1295cd1d3f4STakashi Sakamoto 	if ((format[0] != 0x90) || (format[1] != 0x40))
1305cd1d3f4STakashi Sakamoto 		return -ENOSYS;
1315cd1d3f4STakashi Sakamoto 
1325cd1d3f4STakashi Sakamoto 	/* check the sampling rate */
1335cd1d3f4STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
1345cd1d3f4STakashi Sakamoto 		if (format[2] == avc_stream_rate_table[i])
1355cd1d3f4STakashi Sakamoto 			break;
1365cd1d3f4STakashi Sakamoto 	}
1375cd1d3f4STakashi Sakamoto 	if (i == ARRAY_SIZE(avc_stream_rate_table))
1385cd1d3f4STakashi Sakamoto 		return -ENOSYS;
1395cd1d3f4STakashi Sakamoto 
1405cd1d3f4STakashi Sakamoto 	formation->rate = oxfw_rate_table[i];
1415cd1d3f4STakashi Sakamoto 
1425cd1d3f4STakashi Sakamoto 	for (e = 0; e < format[4]; e++) {
1435cd1d3f4STakashi Sakamoto 		channels = format[5 + e * 2];
1445cd1d3f4STakashi Sakamoto 		type = format[6 + e * 2];
1455cd1d3f4STakashi Sakamoto 
1465cd1d3f4STakashi Sakamoto 		switch (type) {
1475cd1d3f4STakashi Sakamoto 		/* IEC 60958 Conformant, currently handled as MBLA */
1485cd1d3f4STakashi Sakamoto 		case 0x00:
1495cd1d3f4STakashi Sakamoto 		/* Multi Bit Linear Audio (Raw) */
1505cd1d3f4STakashi Sakamoto 		case 0x06:
1515cd1d3f4STakashi Sakamoto 			formation->pcm += channels;
1525cd1d3f4STakashi Sakamoto 			break;
1535cd1d3f4STakashi Sakamoto 		/* MIDI Conformant */
1545cd1d3f4STakashi Sakamoto 		case 0x0d:
1555cd1d3f4STakashi Sakamoto 			formation->midi = channels;
1565cd1d3f4STakashi Sakamoto 			break;
1575cd1d3f4STakashi Sakamoto 		/* IEC 61937-3 to 7 */
1585cd1d3f4STakashi Sakamoto 		case 0x01:
1595cd1d3f4STakashi Sakamoto 		case 0x02:
1605cd1d3f4STakashi Sakamoto 		case 0x03:
1615cd1d3f4STakashi Sakamoto 		case 0x04:
1625cd1d3f4STakashi Sakamoto 		case 0x05:
1635cd1d3f4STakashi Sakamoto 		/* Multi Bit Linear Audio */
1645cd1d3f4STakashi Sakamoto 		case 0x07:	/* DVD-Audio */
1655cd1d3f4STakashi Sakamoto 		case 0x0c:	/* High Precision */
1665cd1d3f4STakashi Sakamoto 		/* One Bit Audio */
1675cd1d3f4STakashi Sakamoto 		case 0x08:	/* (Plain) Raw */
1685cd1d3f4STakashi Sakamoto 		case 0x09:	/* (Plain) SACD */
1695cd1d3f4STakashi Sakamoto 		case 0x0a:	/* (Encoded) Raw */
1705cd1d3f4STakashi Sakamoto 		case 0x0b:	/* (Encoded) SACD */
1715cd1d3f4STakashi Sakamoto 		/* SMPTE Time-Code conformant */
1725cd1d3f4STakashi Sakamoto 		case 0x0e:
1735cd1d3f4STakashi Sakamoto 		/* Sample Count */
1745cd1d3f4STakashi Sakamoto 		case 0x0f:
1755cd1d3f4STakashi Sakamoto 		/* Anciliary Data */
1765cd1d3f4STakashi Sakamoto 		case 0x10:
1775cd1d3f4STakashi Sakamoto 		/* Synchronization Stream (Stereo Raw audio) */
1785cd1d3f4STakashi Sakamoto 		case 0x40:
1795cd1d3f4STakashi Sakamoto 		/* Don't care */
1805cd1d3f4STakashi Sakamoto 		case 0xff:
1815cd1d3f4STakashi Sakamoto 		default:
1825cd1d3f4STakashi Sakamoto 			return -ENOSYS;	/* not supported */
1835cd1d3f4STakashi Sakamoto 		}
1845cd1d3f4STakashi Sakamoto 	}
1855cd1d3f4STakashi Sakamoto 
1865cd1d3f4STakashi Sakamoto 	if (formation->pcm  > AMDTP_MAX_CHANNELS_FOR_PCM ||
1875cd1d3f4STakashi Sakamoto 	    formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
1885cd1d3f4STakashi Sakamoto 		return -ENOSYS;
1895cd1d3f4STakashi Sakamoto 
1905cd1d3f4STakashi Sakamoto 	return 0;
1915cd1d3f4STakashi Sakamoto }
1925cd1d3f4STakashi Sakamoto 
1935cd1d3f4STakashi Sakamoto static int
1945cd1d3f4STakashi Sakamoto assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
1955cd1d3f4STakashi Sakamoto 		      unsigned int pid, u8 *buf, unsigned int *len,
1965cd1d3f4STakashi Sakamoto 		      u8 **formats)
1975cd1d3f4STakashi Sakamoto {
1985cd1d3f4STakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
1995cd1d3f4STakashi Sakamoto 	unsigned int i, eid;
2005cd1d3f4STakashi Sakamoto 	int err;
2015cd1d3f4STakashi Sakamoto 
2025cd1d3f4STakashi Sakamoto 	/* get format at current sampling rate */
2035cd1d3f4STakashi Sakamoto 	err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
2045cd1d3f4STakashi Sakamoto 	if (err < 0) {
2055cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
2065cd1d3f4STakashi Sakamoto 		"fail to get current stream format for isoc %s plug %d:%d\n",
2075cd1d3f4STakashi Sakamoto 			(dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
2085cd1d3f4STakashi Sakamoto 			pid, err);
2095cd1d3f4STakashi Sakamoto 		goto end;
2105cd1d3f4STakashi Sakamoto 	}
2115cd1d3f4STakashi Sakamoto 
2125cd1d3f4STakashi Sakamoto 	/* parse and set stream format */
2135cd1d3f4STakashi Sakamoto 	eid = 0;
2145cd1d3f4STakashi Sakamoto 	err = snd_oxfw_stream_parse_format(buf, &formation);
2155cd1d3f4STakashi Sakamoto 	if (err < 0)
2165cd1d3f4STakashi Sakamoto 		goto end;
2175cd1d3f4STakashi Sakamoto 
2185cd1d3f4STakashi Sakamoto 	formats[eid] = kmalloc(*len, GFP_KERNEL);
2195cd1d3f4STakashi Sakamoto 	if (formats[eid] == NULL) {
2205cd1d3f4STakashi Sakamoto 		err = -ENOMEM;
2215cd1d3f4STakashi Sakamoto 		goto end;
2225cd1d3f4STakashi Sakamoto 	}
2235cd1d3f4STakashi Sakamoto 	memcpy(formats[eid], buf, *len);
2245cd1d3f4STakashi Sakamoto 
2255cd1d3f4STakashi Sakamoto 	/* apply the format for each available sampling rate */
2265cd1d3f4STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
2275cd1d3f4STakashi Sakamoto 		if (formation.rate == oxfw_rate_table[i])
2285cd1d3f4STakashi Sakamoto 			continue;
2295cd1d3f4STakashi Sakamoto 
2305cd1d3f4STakashi Sakamoto 		err = avc_general_inquiry_sig_fmt(oxfw->unit,
2315cd1d3f4STakashi Sakamoto 						  oxfw_rate_table[i],
2325cd1d3f4STakashi Sakamoto 						  dir, pid);
2335cd1d3f4STakashi Sakamoto 		if (err < 0)
2345cd1d3f4STakashi Sakamoto 			continue;
2355cd1d3f4STakashi Sakamoto 
2365cd1d3f4STakashi Sakamoto 		eid++;
2375cd1d3f4STakashi Sakamoto 		formats[eid] = kmalloc(*len, GFP_KERNEL);
2385cd1d3f4STakashi Sakamoto 		if (formats[eid] == NULL) {
2395cd1d3f4STakashi Sakamoto 			err = -ENOMEM;
2405cd1d3f4STakashi Sakamoto 			goto end;
2415cd1d3f4STakashi Sakamoto 		}
2425cd1d3f4STakashi Sakamoto 		memcpy(formats[eid], buf, *len);
2435cd1d3f4STakashi Sakamoto 		formats[eid][2] = avc_stream_rate_table[i];
2445cd1d3f4STakashi Sakamoto 	}
2455cd1d3f4STakashi Sakamoto 
2465cd1d3f4STakashi Sakamoto 	err = 0;
2475cd1d3f4STakashi Sakamoto 	oxfw->assumed = true;
2485cd1d3f4STakashi Sakamoto end:
2495cd1d3f4STakashi Sakamoto 	return err;
2505cd1d3f4STakashi Sakamoto }
2515cd1d3f4STakashi Sakamoto 
2525cd1d3f4STakashi Sakamoto static int fill_stream_formats(struct snd_oxfw *oxfw,
2535cd1d3f4STakashi Sakamoto 			       enum avc_general_plug_dir dir,
2545cd1d3f4STakashi Sakamoto 			       unsigned short pid)
2555cd1d3f4STakashi Sakamoto {
2565cd1d3f4STakashi Sakamoto 	u8 *buf, **formats;
2575cd1d3f4STakashi Sakamoto 	unsigned int len, eid = 0;
2585cd1d3f4STakashi Sakamoto 	struct snd_oxfw_stream_formation dummy;
2595cd1d3f4STakashi Sakamoto 	int err;
2605cd1d3f4STakashi Sakamoto 
2615cd1d3f4STakashi Sakamoto 	buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
2625cd1d3f4STakashi Sakamoto 	if (buf == NULL)
2635cd1d3f4STakashi Sakamoto 		return -ENOMEM;
2645cd1d3f4STakashi Sakamoto 
2655cd1d3f4STakashi Sakamoto 	formats = oxfw->rx_stream_formats;
2665cd1d3f4STakashi Sakamoto 
2675cd1d3f4STakashi Sakamoto 	/* get first entry */
2685cd1d3f4STakashi Sakamoto 	len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
2695cd1d3f4STakashi Sakamoto 	err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
2705cd1d3f4STakashi Sakamoto 	if (err == -ENOSYS) {
2715cd1d3f4STakashi Sakamoto 		/* LIST subfunction is not implemented */
2725cd1d3f4STakashi Sakamoto 		len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
2735cd1d3f4STakashi Sakamoto 		err = assume_stream_formats(oxfw, dir, pid, buf, &len,
2745cd1d3f4STakashi Sakamoto 					    formats);
2755cd1d3f4STakashi Sakamoto 		goto end;
2765cd1d3f4STakashi Sakamoto 	} else if (err < 0) {
2775cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
2785cd1d3f4STakashi Sakamoto 			"fail to get stream format %d for isoc %s plug %d:%d\n",
2795cd1d3f4STakashi Sakamoto 			eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
2805cd1d3f4STakashi Sakamoto 			pid, err);
2815cd1d3f4STakashi Sakamoto 		goto end;
2825cd1d3f4STakashi Sakamoto 	}
2835cd1d3f4STakashi Sakamoto 
2845cd1d3f4STakashi Sakamoto 	/* LIST subfunction is implemented */
2855cd1d3f4STakashi Sakamoto 	while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
2865cd1d3f4STakashi Sakamoto 		/* The format is too short. */
2875cd1d3f4STakashi Sakamoto 		if (len < 3) {
2885cd1d3f4STakashi Sakamoto 			err = -EIO;
2895cd1d3f4STakashi Sakamoto 			break;
2905cd1d3f4STakashi Sakamoto 		}
2915cd1d3f4STakashi Sakamoto 
2925cd1d3f4STakashi Sakamoto 		/* parse and set stream format */
2935cd1d3f4STakashi Sakamoto 		err = snd_oxfw_stream_parse_format(buf, &dummy);
2945cd1d3f4STakashi Sakamoto 		if (err < 0)
2955cd1d3f4STakashi Sakamoto 			break;
2965cd1d3f4STakashi Sakamoto 
2975cd1d3f4STakashi Sakamoto 		formats[eid] = kmalloc(len, GFP_KERNEL);
2985cd1d3f4STakashi Sakamoto 		if (formats[eid] == NULL) {
2995cd1d3f4STakashi Sakamoto 			err = -ENOMEM;
3005cd1d3f4STakashi Sakamoto 			break;
3015cd1d3f4STakashi Sakamoto 		}
3025cd1d3f4STakashi Sakamoto 		memcpy(formats[eid], buf, len);
3035cd1d3f4STakashi Sakamoto 
3045cd1d3f4STakashi Sakamoto 		/* get next entry */
3055cd1d3f4STakashi Sakamoto 		len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
3065cd1d3f4STakashi Sakamoto 		err = avc_stream_get_format_list(oxfw->unit, dir, 0,
3075cd1d3f4STakashi Sakamoto 						 buf, &len, ++eid);
3085cd1d3f4STakashi Sakamoto 		/* No entries remained. */
3095cd1d3f4STakashi Sakamoto 		if (err == -EINVAL) {
3105cd1d3f4STakashi Sakamoto 			err = 0;
3115cd1d3f4STakashi Sakamoto 			break;
3125cd1d3f4STakashi Sakamoto 		} else if (err < 0) {
3135cd1d3f4STakashi Sakamoto 			dev_err(&oxfw->unit->device,
3145cd1d3f4STakashi Sakamoto 			"fail to get stream format %d for isoc %s plug %d:%d\n",
3155cd1d3f4STakashi Sakamoto 				eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
3165cd1d3f4STakashi Sakamoto 									"out",
3175cd1d3f4STakashi Sakamoto 				pid, err);
3185cd1d3f4STakashi Sakamoto 			break;
3195cd1d3f4STakashi Sakamoto 		}
3205cd1d3f4STakashi Sakamoto 	}
3215cd1d3f4STakashi Sakamoto end:
3225cd1d3f4STakashi Sakamoto 	kfree(buf);
3235cd1d3f4STakashi Sakamoto 	return err;
3245cd1d3f4STakashi Sakamoto }
3255cd1d3f4STakashi Sakamoto 
3265cd1d3f4STakashi Sakamoto int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
3275cd1d3f4STakashi Sakamoto {
3285cd1d3f4STakashi Sakamoto 	u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
3295cd1d3f4STakashi Sakamoto 	int err;
3305cd1d3f4STakashi Sakamoto 
3315cd1d3f4STakashi Sakamoto 	/* the number of plugs for isoc in/out, ext in/out  */
3325cd1d3f4STakashi Sakamoto 	err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
3335cd1d3f4STakashi Sakamoto 	if (err < 0) {
3345cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
3355cd1d3f4STakashi Sakamoto 		"fail to get info for isoc/external in/out plugs: %d\n",
3365cd1d3f4STakashi Sakamoto 			err);
3375cd1d3f4STakashi Sakamoto 		goto end;
3385cd1d3f4STakashi Sakamoto 	} else if (plugs[0] == 0) {
3395cd1d3f4STakashi Sakamoto 		err = -ENOSYS;
3405cd1d3f4STakashi Sakamoto 		goto end;
3415cd1d3f4STakashi Sakamoto 	}
3425cd1d3f4STakashi Sakamoto 
3435cd1d3f4STakashi Sakamoto 	/* use iPCR[0] if exists */
3445cd1d3f4STakashi Sakamoto 	if (plugs[0] > 0)
3455cd1d3f4STakashi Sakamoto 		err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
3465cd1d3f4STakashi Sakamoto end:
3475cd1d3f4STakashi Sakamoto 	return err;
3485cd1d3f4STakashi Sakamoto }
349