oxfw-stream.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. * oxfw_stream.c - a part of driver for OXFW970/971 based devices
  3. *
  4. * Copyright (c) 2014 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "oxfw.h"
  9. #include <linux/delay.h>
  10. #define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
  11. #define CALLBACK_TIMEOUT 200
  12. /*
  13. * According to datasheet of Oxford Semiconductor:
  14. * OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
  15. * OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
  16. */
  17. static const unsigned int oxfw_rate_table[] = {
  18. [0] = 32000,
  19. [1] = 44100,
  20. [2] = 48000,
  21. [3] = 88200,
  22. [4] = 96000,
  23. [5] = 192000,
  24. };
  25. /*
  26. * See Table 5.7 – Sampling frequency for Multi-bit Audio
  27. * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
  28. */
  29. static const unsigned int avc_stream_rate_table[] = {
  30. [0] = 0x02,
  31. [1] = 0x03,
  32. [2] = 0x04,
  33. [3] = 0x0a,
  34. [4] = 0x05,
  35. [5] = 0x07,
  36. };
  37. static int set_rate(struct snd_oxfw *oxfw, unsigned int rate)
  38. {
  39. int err;
  40. err = avc_general_set_sig_fmt(oxfw->unit, rate,
  41. AVC_GENERAL_PLUG_DIR_IN, 0);
  42. if (err < 0)
  43. goto end;
  44. if (oxfw->has_output)
  45. err = avc_general_set_sig_fmt(oxfw->unit, rate,
  46. AVC_GENERAL_PLUG_DIR_OUT, 0);
  47. end:
  48. return err;
  49. }
  50. static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
  51. unsigned int rate, unsigned int pcm_channels)
  52. {
  53. u8 **formats;
  54. struct snd_oxfw_stream_formation formation;
  55. enum avc_general_plug_dir dir;
  56. unsigned int len;
  57. int i, err;
  58. if (s == &oxfw->tx_stream) {
  59. formats = oxfw->tx_stream_formats;
  60. dir = AVC_GENERAL_PLUG_DIR_OUT;
  61. } else {
  62. formats = oxfw->rx_stream_formats;
  63. dir = AVC_GENERAL_PLUG_DIR_IN;
  64. }
  65. /* Seek stream format for requirements. */
  66. for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
  67. err = snd_oxfw_stream_parse_format(formats[i], &formation);
  68. if (err < 0)
  69. return err;
  70. if ((formation.rate == rate) && (formation.pcm == pcm_channels))
  71. break;
  72. }
  73. if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
  74. return -EINVAL;
  75. /* If assumed, just change rate. */
  76. if (oxfw->assumed)
  77. return set_rate(oxfw, rate);
  78. /* Calculate format length. */
  79. len = 5 + formats[i][4] * 2;
  80. err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
  81. if (err < 0)
  82. return err;
  83. /* Some requests just after changing format causes freezing. */
  84. msleep(100);
  85. return 0;
  86. }
  87. static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
  88. {
  89. amdtp_stream_pcm_abort(stream);
  90. amdtp_stream_stop(stream);
  91. if (stream == &oxfw->tx_stream)
  92. cmp_connection_break(&oxfw->out_conn);
  93. else
  94. cmp_connection_break(&oxfw->in_conn);
  95. }
  96. static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
  97. unsigned int rate, unsigned int pcm_channels)
  98. {
  99. u8 **formats;
  100. struct cmp_connection *conn;
  101. struct snd_oxfw_stream_formation formation;
  102. unsigned int i, midi_ports;
  103. int err;
  104. if (stream == &oxfw->rx_stream) {
  105. formats = oxfw->rx_stream_formats;
  106. conn = &oxfw->in_conn;
  107. } else {
  108. formats = oxfw->tx_stream_formats;
  109. conn = &oxfw->out_conn;
  110. }
  111. /* Get stream format */
  112. for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
  113. if (formats[i] == NULL)
  114. break;
  115. err = snd_oxfw_stream_parse_format(formats[i], &formation);
  116. if (err < 0)
  117. goto end;
  118. if (rate != formation.rate)
  119. continue;
  120. if (pcm_channels == 0 || pcm_channels == formation.pcm)
  121. break;
  122. }
  123. if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
  124. err = -EINVAL;
  125. goto end;
  126. }
  127. pcm_channels = formation.pcm;
  128. midi_ports = DIV_ROUND_UP(formation.midi, 8);
  129. /* The stream should have one pcm channels at least */
  130. if (pcm_channels == 0) {
  131. err = -EINVAL;
  132. goto end;
  133. }
  134. amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports);
  135. err = cmp_connection_establish(conn,
  136. amdtp_stream_get_max_payload(stream));
  137. if (err < 0)
  138. goto end;
  139. err = amdtp_stream_start(stream,
  140. conn->resources.channel,
  141. conn->speed);
  142. if (err < 0) {
  143. cmp_connection_break(conn);
  144. goto end;
  145. }
  146. /* Wait first packet */
  147. if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
  148. stop_stream(oxfw, stream);
  149. err = -ETIMEDOUT;
  150. }
  151. end:
  152. return err;
  153. }
  154. static int check_connection_used_by_others(struct snd_oxfw *oxfw,
  155. struct amdtp_stream *stream)
  156. {
  157. struct cmp_connection *conn;
  158. bool used;
  159. int err;
  160. if (stream == &oxfw->tx_stream)
  161. conn = &oxfw->out_conn;
  162. else
  163. conn = &oxfw->in_conn;
  164. err = cmp_connection_check_used(conn, &used);
  165. if ((err >= 0) && used && !amdtp_stream_running(stream)) {
  166. dev_err(&oxfw->unit->device,
  167. "Connection established by others: %cPCR[%d]\n",
  168. (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
  169. conn->pcr_index);
  170. err = -EBUSY;
  171. }
  172. return err;
  173. }
  174. int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
  175. struct amdtp_stream *stream)
  176. {
  177. struct cmp_connection *conn;
  178. enum cmp_direction c_dir;
  179. enum amdtp_stream_direction s_dir;
  180. int err;
  181. if (stream == &oxfw->tx_stream) {
  182. conn = &oxfw->out_conn;
  183. c_dir = CMP_OUTPUT;
  184. s_dir = AMDTP_IN_STREAM;
  185. } else {
  186. conn = &oxfw->in_conn;
  187. c_dir = CMP_INPUT;
  188. s_dir = AMDTP_OUT_STREAM;
  189. }
  190. err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
  191. if (err < 0)
  192. goto end;
  193. err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
  194. if (err < 0) {
  195. amdtp_stream_destroy(stream);
  196. cmp_connection_destroy(conn);
  197. goto end;
  198. }
  199. /*
  200. * OXFW starts to transmit packets with non-zero dbc.
  201. * OXFW postpone transferring packets till handling any asynchronous
  202. * packets. As a result, next isochronous packet includes more data
  203. * blocks than IEC 61883-6 defines.
  204. */
  205. if (stream == &oxfw->tx_stream)
  206. oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK |
  207. CIP_JUMBO_PAYLOAD;
  208. end:
  209. return err;
  210. }
  211. int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
  212. struct amdtp_stream *stream,
  213. unsigned int rate, unsigned int pcm_channels)
  214. {
  215. struct amdtp_stream *opposite;
  216. struct snd_oxfw_stream_formation formation;
  217. enum avc_general_plug_dir dir;
  218. unsigned int substreams, opposite_substreams;
  219. int err = 0;
  220. if (stream == &oxfw->tx_stream) {
  221. substreams = oxfw->capture_substreams;
  222. opposite = &oxfw->rx_stream;
  223. opposite_substreams = oxfw->playback_substreams;
  224. dir = AVC_GENERAL_PLUG_DIR_OUT;
  225. } else {
  226. substreams = oxfw->playback_substreams;
  227. opposite_substreams = oxfw->capture_substreams;
  228. if (oxfw->has_output)
  229. opposite = &oxfw->rx_stream;
  230. else
  231. opposite = NULL;
  232. dir = AVC_GENERAL_PLUG_DIR_IN;
  233. }
  234. if (substreams == 0)
  235. goto end;
  236. /*
  237. * Considering JACK/FFADO streaming:
  238. * TODO: This can be removed hwdep functionality becomes popular.
  239. */
  240. err = check_connection_used_by_others(oxfw, stream);
  241. if (err < 0)
  242. goto end;
  243. /* packet queueing error */
  244. if (amdtp_streaming_error(stream))
  245. stop_stream(oxfw, stream);
  246. err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
  247. if (err < 0)
  248. goto end;
  249. if (rate == 0)
  250. rate = formation.rate;
  251. if (pcm_channels == 0)
  252. pcm_channels = formation.pcm;
  253. if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
  254. if (opposite != NULL) {
  255. err = check_connection_used_by_others(oxfw, opposite);
  256. if (err < 0)
  257. goto end;
  258. stop_stream(oxfw, opposite);
  259. }
  260. stop_stream(oxfw, stream);
  261. err = set_stream_format(oxfw, stream, rate, pcm_channels);
  262. if (err < 0) {
  263. dev_err(&oxfw->unit->device,
  264. "fail to set stream format: %d\n", err);
  265. goto end;
  266. }
  267. /* Start opposite stream if needed. */
  268. if (opposite && !amdtp_stream_running(opposite) &&
  269. (opposite_substreams > 0)) {
  270. err = start_stream(oxfw, opposite, rate, 0);
  271. if (err < 0) {
  272. dev_err(&oxfw->unit->device,
  273. "fail to restart stream: %d\n", err);
  274. goto end;
  275. }
  276. }
  277. }
  278. /* Start requested stream. */
  279. if (!amdtp_stream_running(stream)) {
  280. err = start_stream(oxfw, stream, rate, pcm_channels);
  281. if (err < 0)
  282. dev_err(&oxfw->unit->device,
  283. "fail to start stream: %d\n", err);
  284. }
  285. end:
  286. return err;
  287. }
  288. void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
  289. struct amdtp_stream *stream)
  290. {
  291. if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
  292. ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
  293. return;
  294. stop_stream(oxfw, stream);
  295. }
  296. /*
  297. * This function should be called before starting the stream or after stopping
  298. * the streams.
  299. */
  300. void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
  301. struct amdtp_stream *stream)
  302. {
  303. struct cmp_connection *conn;
  304. if (stream == &oxfw->tx_stream)
  305. conn = &oxfw->out_conn;
  306. else
  307. conn = &oxfw->in_conn;
  308. amdtp_stream_destroy(stream);
  309. cmp_connection_destroy(conn);
  310. }
  311. void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
  312. struct amdtp_stream *stream)
  313. {
  314. struct cmp_connection *conn;
  315. if (stream == &oxfw->tx_stream)
  316. conn = &oxfw->out_conn;
  317. else
  318. conn = &oxfw->in_conn;
  319. if (cmp_connection_update(conn) < 0)
  320. stop_stream(oxfw, stream);
  321. else
  322. amdtp_stream_update(stream);
  323. }
  324. int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
  325. enum avc_general_plug_dir dir,
  326. struct snd_oxfw_stream_formation *formation)
  327. {
  328. u8 *format;
  329. unsigned int len;
  330. int err;
  331. len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
  332. format = kmalloc(len, GFP_KERNEL);
  333. if (format == NULL)
  334. return -ENOMEM;
  335. err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
  336. if (err < 0)
  337. goto end;
  338. if (len < 3) {
  339. err = -EIO;
  340. goto end;
  341. }
  342. err = snd_oxfw_stream_parse_format(format, formation);
  343. end:
  344. kfree(format);
  345. return err;
  346. }
  347. /*
  348. * See Table 6.16 - AM824 Stream Format
  349. * Figure 6.19 - format_information field for AM824 Compound
  350. * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
  351. * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
  352. */
  353. int snd_oxfw_stream_parse_format(u8 *format,
  354. struct snd_oxfw_stream_formation *formation)
  355. {
  356. unsigned int i, e, channels, type;
  357. memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
  358. /*
  359. * this module can support a hierarchy combination that:
  360. * Root: Audio and Music (0x90)
  361. * Level 1: AM824 Compound (0x40)
  362. */
  363. if ((format[0] != 0x90) || (format[1] != 0x40))
  364. return -ENOSYS;
  365. /* check the sampling rate */
  366. for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
  367. if (format[2] == avc_stream_rate_table[i])
  368. break;
  369. }
  370. if (i == ARRAY_SIZE(avc_stream_rate_table))
  371. return -ENOSYS;
  372. formation->rate = oxfw_rate_table[i];
  373. for (e = 0; e < format[4]; e++) {
  374. channels = format[5 + e * 2];
  375. type = format[6 + e * 2];
  376. switch (type) {
  377. /* IEC 60958 Conformant, currently handled as MBLA */
  378. case 0x00:
  379. /* Multi Bit Linear Audio (Raw) */
  380. case 0x06:
  381. formation->pcm += channels;
  382. break;
  383. /* MIDI Conformant */
  384. case 0x0d:
  385. formation->midi = channels;
  386. break;
  387. /* IEC 61937-3 to 7 */
  388. case 0x01:
  389. case 0x02:
  390. case 0x03:
  391. case 0x04:
  392. case 0x05:
  393. /* Multi Bit Linear Audio */
  394. case 0x07: /* DVD-Audio */
  395. case 0x0c: /* High Precision */
  396. /* One Bit Audio */
  397. case 0x08: /* (Plain) Raw */
  398. case 0x09: /* (Plain) SACD */
  399. case 0x0a: /* (Encoded) Raw */
  400. case 0x0b: /* (Encoded) SACD */
  401. /* SMPTE Time-Code conformant */
  402. case 0x0e:
  403. /* Sample Count */
  404. case 0x0f:
  405. /* Anciliary Data */
  406. case 0x10:
  407. /* Synchronization Stream (Stereo Raw audio) */
  408. case 0x40:
  409. /* Don't care */
  410. case 0xff:
  411. default:
  412. return -ENOSYS; /* not supported */
  413. }
  414. }
  415. if (formation->pcm > AMDTP_MAX_CHANNELS_FOR_PCM ||
  416. formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
  417. return -ENOSYS;
  418. return 0;
  419. }
  420. static int
  421. assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
  422. unsigned int pid, u8 *buf, unsigned int *len,
  423. u8 **formats)
  424. {
  425. struct snd_oxfw_stream_formation formation;
  426. unsigned int i, eid;
  427. int err;
  428. /* get format at current sampling rate */
  429. err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
  430. if (err < 0) {
  431. dev_err(&oxfw->unit->device,
  432. "fail to get current stream format for isoc %s plug %d:%d\n",
  433. (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
  434. pid, err);
  435. goto end;
  436. }
  437. /* parse and set stream format */
  438. eid = 0;
  439. err = snd_oxfw_stream_parse_format(buf, &formation);
  440. if (err < 0)
  441. goto end;
  442. formats[eid] = kmalloc(*len, GFP_KERNEL);
  443. if (formats[eid] == NULL) {
  444. err = -ENOMEM;
  445. goto end;
  446. }
  447. memcpy(formats[eid], buf, *len);
  448. /* apply the format for each available sampling rate */
  449. for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
  450. if (formation.rate == oxfw_rate_table[i])
  451. continue;
  452. err = avc_general_inquiry_sig_fmt(oxfw->unit,
  453. oxfw_rate_table[i],
  454. dir, pid);
  455. if (err < 0)
  456. continue;
  457. eid++;
  458. formats[eid] = kmalloc(*len, GFP_KERNEL);
  459. if (formats[eid] == NULL) {
  460. err = -ENOMEM;
  461. goto end;
  462. }
  463. memcpy(formats[eid], buf, *len);
  464. formats[eid][2] = avc_stream_rate_table[i];
  465. }
  466. err = 0;
  467. oxfw->assumed = true;
  468. end:
  469. return err;
  470. }
  471. static int fill_stream_formats(struct snd_oxfw *oxfw,
  472. enum avc_general_plug_dir dir,
  473. unsigned short pid)
  474. {
  475. u8 *buf, **formats;
  476. unsigned int len, eid = 0;
  477. struct snd_oxfw_stream_formation dummy;
  478. int err;
  479. buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
  480. if (buf == NULL)
  481. return -ENOMEM;
  482. if (dir == AVC_GENERAL_PLUG_DIR_OUT)
  483. formats = oxfw->tx_stream_formats;
  484. else
  485. formats = oxfw->rx_stream_formats;
  486. /* get first entry */
  487. len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
  488. err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
  489. if (err == -ENOSYS) {
  490. /* LIST subfunction is not implemented */
  491. len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
  492. err = assume_stream_formats(oxfw, dir, pid, buf, &len,
  493. formats);
  494. goto end;
  495. } else if (err < 0) {
  496. dev_err(&oxfw->unit->device,
  497. "fail to get stream format %d for isoc %s plug %d:%d\n",
  498. eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
  499. pid, err);
  500. goto end;
  501. }
  502. /* LIST subfunction is implemented */
  503. while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
  504. /* The format is too short. */
  505. if (len < 3) {
  506. err = -EIO;
  507. break;
  508. }
  509. /* parse and set stream format */
  510. err = snd_oxfw_stream_parse_format(buf, &dummy);
  511. if (err < 0)
  512. break;
  513. formats[eid] = kmalloc(len, GFP_KERNEL);
  514. if (formats[eid] == NULL) {
  515. err = -ENOMEM;
  516. break;
  517. }
  518. memcpy(formats[eid], buf, len);
  519. /* get next entry */
  520. len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
  521. err = avc_stream_get_format_list(oxfw->unit, dir, 0,
  522. buf, &len, ++eid);
  523. /* No entries remained. */
  524. if (err == -EINVAL) {
  525. err = 0;
  526. break;
  527. } else if (err < 0) {
  528. dev_err(&oxfw->unit->device,
  529. "fail to get stream format %d for isoc %s plug %d:%d\n",
  530. eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
  531. "out",
  532. pid, err);
  533. break;
  534. }
  535. }
  536. end:
  537. kfree(buf);
  538. return err;
  539. }
  540. int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
  541. {
  542. u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
  543. int err;
  544. /* the number of plugs for isoc in/out, ext in/out */
  545. err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
  546. if (err < 0) {
  547. dev_err(&oxfw->unit->device,
  548. "fail to get info for isoc/external in/out plugs: %d\n",
  549. err);
  550. goto end;
  551. } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
  552. err = -ENOSYS;
  553. goto end;
  554. }
  555. /* use oPCR[0] if exists */
  556. if (plugs[1] > 0) {
  557. err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
  558. if (err < 0)
  559. goto end;
  560. oxfw->has_output = true;
  561. }
  562. /* use iPCR[0] if exists */
  563. if (plugs[0] > 0)
  564. err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
  565. end:
  566. return err;
  567. }
  568. void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
  569. {
  570. oxfw->dev_lock_changed = true;
  571. wake_up(&oxfw->hwdep_wait);
  572. }
  573. int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
  574. {
  575. int err;
  576. spin_lock_irq(&oxfw->lock);
  577. /* user land lock this */
  578. if (oxfw->dev_lock_count < 0) {
  579. err = -EBUSY;
  580. goto end;
  581. }
  582. /* this is the first time */
  583. if (oxfw->dev_lock_count++ == 0)
  584. snd_oxfw_stream_lock_changed(oxfw);
  585. err = 0;
  586. end:
  587. spin_unlock_irq(&oxfw->lock);
  588. return err;
  589. }
  590. void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
  591. {
  592. spin_lock_irq(&oxfw->lock);
  593. if (WARN_ON(oxfw->dev_lock_count <= 0))
  594. goto end;
  595. if (--oxfw->dev_lock_count == 0)
  596. snd_oxfw_stream_lock_changed(oxfw);
  597. end:
  598. spin_unlock_irq(&oxfw->lock);
  599. }