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