brintos

brintos / linux-shallow public Read only

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