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