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 = 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        err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports,
 159                                         false);
 160        if (err < 0)
 161                goto end;
 162
 163        err = cmp_connection_establish(conn,
 164                                       amdtp_stream_get_max_payload(stream));
 165        if (err < 0)
 166                goto end;
 167
 168        err = amdtp_stream_start(stream,
 169                                 conn->resources.channel,
 170                                 conn->speed);
 171        if (err < 0) {
 172                cmp_connection_break(conn);
 173                goto end;
 174        }
 175
 176        /* Wait first packet */
 177        if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
 178                stop_stream(oxfw, stream);
 179                err = -ETIMEDOUT;
 180        }
 181end:
 182        return err;
 183}
 184
 185static int check_connection_used_by_others(struct snd_oxfw *oxfw,
 186                                           struct amdtp_stream *stream)
 187{
 188        struct cmp_connection *conn;
 189        bool used;
 190        int err;
 191
 192        if (stream == &oxfw->tx_stream)
 193                conn = &oxfw->out_conn;
 194        else
 195                conn = &oxfw->in_conn;
 196
 197        err = cmp_connection_check_used(conn, &used);
 198        if ((err >= 0) && used && !amdtp_stream_running(stream)) {
 199                dev_err(&oxfw->unit->device,
 200                        "Connection established by others: %cPCR[%d]\n",
 201                        (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
 202                        conn->pcr_index);
 203                err = -EBUSY;
 204        }
 205
 206        return err;
 207}
 208
 209int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
 210                                 struct amdtp_stream *stream)
 211{
 212        struct cmp_connection *conn;
 213        enum cmp_direction c_dir;
 214        enum amdtp_stream_direction s_dir;
 215        int err;
 216
 217        if (stream == &oxfw->tx_stream) {
 218                conn = &oxfw->out_conn;
 219                c_dir = CMP_OUTPUT;
 220                s_dir = AMDTP_IN_STREAM;
 221        } else {
 222                conn = &oxfw->in_conn;
 223                c_dir = CMP_INPUT;
 224                s_dir = AMDTP_OUT_STREAM;
 225        }
 226
 227        err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
 228        if (err < 0)
 229                goto end;
 230
 231        err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
 232        if (err < 0) {
 233                amdtp_stream_destroy(stream);
 234                cmp_connection_destroy(conn);
 235                goto end;
 236        }
 237
 238        /*
 239         * OXFW starts to transmit packets with non-zero dbc.
 240         * OXFW postpone transferring packets till handling any asynchronous
 241         * packets. As a result, next isochronous packet includes more data
 242         * blocks than IEC 61883-6 defines.
 243         */
 244        if (stream == &oxfw->tx_stream) {
 245                oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK |
 246                                         CIP_JUMBO_PAYLOAD;
 247                if (oxfw->wrong_dbs)
 248                        oxfw->tx_stream.flags |= CIP_WRONG_DBS;
 249        }
 250end:
 251        return err;
 252}
 253
 254int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
 255                                  struct amdtp_stream *stream,
 256                                  unsigned int rate, unsigned int pcm_channels)
 257{
 258        struct amdtp_stream *opposite;
 259        struct snd_oxfw_stream_formation formation;
 260        enum avc_general_plug_dir dir;
 261        unsigned int substreams, opposite_substreams;
 262        int err = 0;
 263
 264        if (stream == &oxfw->tx_stream) {
 265                substreams = oxfw->capture_substreams;
 266                opposite = &oxfw->rx_stream;
 267                opposite_substreams = oxfw->playback_substreams;
 268                dir = AVC_GENERAL_PLUG_DIR_OUT;
 269        } else {
 270                substreams = oxfw->playback_substreams;
 271                opposite_substreams = oxfw->capture_substreams;
 272
 273                if (oxfw->has_output)
 274                        opposite = &oxfw->rx_stream;
 275                else
 276                        opposite = NULL;
 277
 278                dir = AVC_GENERAL_PLUG_DIR_IN;
 279        }
 280
 281        if (substreams == 0)
 282                goto end;
 283
 284        /*
 285         * Considering JACK/FFADO streaming:
 286         * TODO: This can be removed hwdep functionality becomes popular.
 287         */
 288        err = check_connection_used_by_others(oxfw, stream);
 289        if (err < 0)
 290                goto end;
 291
 292        /* packet queueing error */
 293        if (amdtp_streaming_error(stream))
 294                stop_stream(oxfw, stream);
 295
 296        err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
 297        if (err < 0)
 298                goto end;
 299        if (rate == 0)
 300                rate = formation.rate;
 301        if (pcm_channels == 0)
 302                pcm_channels = formation.pcm;
 303
 304        if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
 305                if (opposite != NULL) {
 306                        err = check_connection_used_by_others(oxfw, opposite);
 307                        if (err < 0)
 308                                goto end;
 309                        stop_stream(oxfw, opposite);
 310                }
 311                stop_stream(oxfw, stream);
 312
 313                err = set_stream_format(oxfw, stream, rate, pcm_channels);
 314                if (err < 0) {
 315                        dev_err(&oxfw->unit->device,
 316                                "fail to set stream format: %d\n", err);
 317                        goto end;
 318                }
 319
 320                /* Start opposite stream if needed. */
 321                if (opposite && !amdtp_stream_running(opposite) &&
 322                    (opposite_substreams > 0)) {
 323                        err = start_stream(oxfw, opposite, rate, 0);
 324                        if (err < 0) {
 325                                dev_err(&oxfw->unit->device,
 326                                        "fail to restart stream: %d\n", err);
 327                                goto end;
 328                        }
 329                }
 330        }
 331
 332        /* Start requested stream. */
 333        if (!amdtp_stream_running(stream)) {
 334                err = start_stream(oxfw, stream, rate, pcm_channels);
 335                if (err < 0)
 336                        dev_err(&oxfw->unit->device,
 337                                "fail to start stream: %d\n", err);
 338        }
 339end:
 340        return err;
 341}
 342
 343void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
 344                                  struct amdtp_stream *stream)
 345{
 346        if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
 347            ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
 348                return;
 349
 350        stop_stream(oxfw, stream);
 351}
 352
 353/*
 354 * This function should be called before starting the stream or after stopping
 355 * the streams.
 356 */
 357void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
 358                                     struct amdtp_stream *stream)
 359{
 360        struct cmp_connection *conn;
 361
 362        if (stream == &oxfw->tx_stream)
 363                conn = &oxfw->out_conn;
 364        else
 365                conn = &oxfw->in_conn;
 366
 367        amdtp_stream_destroy(stream);
 368        cmp_connection_destroy(conn);
 369}
 370
 371void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
 372                                    struct amdtp_stream *stream)
 373{
 374        struct cmp_connection *conn;
 375
 376        if (stream == &oxfw->tx_stream)
 377                conn = &oxfw->out_conn;
 378        else
 379                conn = &oxfw->in_conn;
 380
 381        if (cmp_connection_update(conn) < 0)
 382                stop_stream(oxfw, stream);
 383        else
 384                amdtp_stream_update(stream);
 385}
 386
 387int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
 388                                enum avc_general_plug_dir dir,
 389                                struct snd_oxfw_stream_formation *formation)
 390{
 391        u8 *format;
 392        unsigned int len;
 393        int err;
 394
 395        len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
 396        format = kmalloc(len, GFP_KERNEL);
 397        if (format == NULL)
 398                return -ENOMEM;
 399
 400        err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
 401        if (err < 0)
 402                goto end;
 403        if (len < 3) {
 404                err = -EIO;
 405                goto end;
 406        }
 407
 408        err = snd_oxfw_stream_parse_format(format, formation);
 409end:
 410        kfree(format);
 411        return err;
 412}
 413
 414/*
 415 * See Table 6.16 - AM824 Stream Format
 416 *     Figure 6.19 - format_information field for AM824 Compound
 417 * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
 418 * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
 419 */
 420int snd_oxfw_stream_parse_format(u8 *format,
 421                                 struct snd_oxfw_stream_formation *formation)
 422{
 423        unsigned int i, e, channels, type;
 424
 425        memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
 426
 427        /*
 428         * this module can support a hierarchy combination that:
 429         *  Root:       Audio and Music (0x90)
 430         *  Level 1:    AM824 Compound  (0x40)
 431         */
 432        if ((format[0] != 0x90) || (format[1] != 0x40))
 433                return -ENOSYS;
 434
 435        /* check the sampling rate */
 436        for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
 437                if (format[2] == avc_stream_rate_table[i])
 438                        break;
 439        }
 440        if (i == ARRAY_SIZE(avc_stream_rate_table))
 441                return -ENOSYS;
 442
 443        formation->rate = oxfw_rate_table[i];
 444
 445        for (e = 0; e < format[4]; e++) {
 446                channels = format[5 + e * 2];
 447                type = format[6 + e * 2];
 448
 449                switch (type) {
 450                /* IEC 60958 Conformant, currently handled as MBLA */
 451                case 0x00:
 452                /* Multi Bit Linear Audio (Raw) */
 453                case 0x06:
 454                        formation->pcm += channels;
 455                        break;
 456                /* MIDI Conformant */
 457                case 0x0d:
 458                        formation->midi = channels;
 459                        break;
 460                /* IEC 61937-3 to 7 */
 461                case 0x01:
 462                case 0x02:
 463                case 0x03:
 464                case 0x04:
 465                case 0x05:
 466                /* Multi Bit Linear Audio */
 467                case 0x07:      /* DVD-Audio */
 468                case 0x0c:      /* High Precision */
 469                /* One Bit Audio */
 470                case 0x08:      /* (Plain) Raw */
 471                case 0x09:      /* (Plain) SACD */
 472                case 0x0a:      /* (Encoded) Raw */
 473                case 0x0b:      /* (Encoded) SACD */
 474                /* SMPTE Time-Code conformant */
 475                case 0x0e:
 476                /* Sample Count */
 477                case 0x0f:
 478                /* Anciliary Data */
 479                case 0x10:
 480                /* Synchronization Stream (Stereo Raw audio) */
 481                case 0x40:
 482                /* Don't care */
 483                case 0xff:
 484                default:
 485                        return -ENOSYS; /* not supported */
 486                }
 487        }
 488
 489        if (formation->pcm  > AM824_MAX_CHANNELS_FOR_PCM ||
 490            formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
 491                return -ENOSYS;
 492
 493        return 0;
 494}
 495
 496static int
 497assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
 498                      unsigned int pid, u8 *buf, unsigned int *len,
 499                      u8 **formats)
 500{
 501        struct snd_oxfw_stream_formation formation;
 502        unsigned int i, eid;
 503        int err;
 504
 505        /* get format at current sampling rate */
 506        err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
 507        if (err < 0) {
 508                dev_err(&oxfw->unit->device,
 509                "fail to get current stream format for isoc %s plug %d:%d\n",
 510                        (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
 511                        pid, err);
 512                goto end;
 513        }
 514
 515        /* parse and set stream format */
 516        eid = 0;
 517        err = snd_oxfw_stream_parse_format(buf, &formation);
 518        if (err < 0)
 519                goto end;
 520
 521        formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
 522        if (formats[eid] == NULL) {
 523                err = -ENOMEM;
 524                goto end;
 525        }
 526
 527        /* apply the format for each available sampling rate */
 528        for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
 529                if (formation.rate == oxfw_rate_table[i])
 530                        continue;
 531
 532                err = avc_general_inquiry_sig_fmt(oxfw->unit,
 533                                                  oxfw_rate_table[i],
 534                                                  dir, pid);
 535                if (err < 0)
 536                        continue;
 537
 538                eid++;
 539                formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
 540                if (formats[eid] == NULL) {
 541                        err = -ENOMEM;
 542                        goto end;
 543                }
 544                formats[eid][2] = avc_stream_rate_table[i];
 545        }
 546
 547        err = 0;
 548        oxfw->assumed = true;
 549end:
 550        return err;
 551}
 552
 553static int fill_stream_formats(struct snd_oxfw *oxfw,
 554                               enum avc_general_plug_dir dir,
 555                               unsigned short pid)
 556{
 557        u8 *buf, **formats;
 558        unsigned int len, eid = 0;
 559        struct snd_oxfw_stream_formation dummy;
 560        int err;
 561
 562        buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
 563        if (buf == NULL)
 564                return -ENOMEM;
 565
 566        if (dir == AVC_GENERAL_PLUG_DIR_OUT)
 567                formats = oxfw->tx_stream_formats;
 568        else
 569                formats = oxfw->rx_stream_formats;
 570
 571        /* get first entry */
 572        len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
 573        err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
 574        if (err == -ENOSYS) {
 575                /* LIST subfunction is not implemented */
 576                len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
 577                err = assume_stream_formats(oxfw, dir, pid, buf, &len,
 578                                            formats);
 579                goto end;
 580        } else if (err < 0) {
 581                dev_err(&oxfw->unit->device,
 582                        "fail to get stream format %d for isoc %s plug %d:%d\n",
 583                        eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
 584                        pid, err);
 585                goto end;
 586        }
 587
 588        /* LIST subfunction is implemented */
 589        while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
 590                /* The format is too short. */
 591                if (len < 3) {
 592                        err = -EIO;
 593                        break;
 594                }
 595
 596                /* parse and set stream format */
 597                err = snd_oxfw_stream_parse_format(buf, &dummy);
 598                if (err < 0)
 599                        break;
 600
 601                formats[eid] = kmemdup(buf, len, GFP_KERNEL);
 602                if (formats[eid] == NULL) {
 603                        err = -ENOMEM;
 604                        break;
 605                }
 606
 607                /* get next entry */
 608                len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
 609                err = avc_stream_get_format_list(oxfw->unit, dir, 0,
 610                                                 buf, &len, ++eid);
 611                /* No entries remained. */
 612                if (err == -EINVAL) {
 613                        err = 0;
 614                        break;
 615                } else if (err < 0) {
 616                        dev_err(&oxfw->unit->device,
 617                        "fail to get stream format %d for isoc %s plug %d:%d\n",
 618                                eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
 619                                                                        "out",
 620                                pid, err);
 621                        break;
 622                }
 623        }
 624end:
 625        kfree(buf);
 626        return err;
 627}
 628
 629int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
 630{
 631        u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
 632        struct snd_oxfw_stream_formation formation;
 633        u8 *format;
 634        unsigned int i;
 635        int err;
 636
 637        /* the number of plugs for isoc in/out, ext in/out  */
 638        err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
 639        if (err < 0) {
 640                dev_err(&oxfw->unit->device,
 641                "fail to get info for isoc/external in/out plugs: %d\n",
 642                        err);
 643                goto end;
 644        } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
 645                err = -ENOSYS;
 646                goto end;
 647        }
 648
 649        /* use oPCR[0] if exists */
 650        if (plugs[1] > 0) {
 651                err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
 652                if (err < 0)
 653                        goto end;
 654
 655                for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
 656                        format = oxfw->tx_stream_formats[i];
 657                        if (format == NULL)
 658                                continue;
 659                        err = snd_oxfw_stream_parse_format(format, &formation);
 660                        if (err < 0)
 661                                continue;
 662
 663                        /* Add one MIDI port. */
 664                        if (formation.midi > 0)
 665                                oxfw->midi_input_ports = 1;
 666                }
 667
 668                oxfw->has_output = true;
 669        }
 670
 671        /* use iPCR[0] if exists */
 672        if (plugs[0] > 0) {
 673                err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
 674                if (err < 0)
 675                        goto end;
 676
 677                for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
 678                        format = oxfw->rx_stream_formats[i];
 679                        if (format == NULL)
 680                                continue;
 681                        err = snd_oxfw_stream_parse_format(format, &formation);
 682                        if (err < 0)
 683                                continue;
 684
 685                        /* Add one MIDI port. */
 686                        if (formation.midi > 0)
 687                                oxfw->midi_output_ports = 1;
 688                }
 689        }
 690end:
 691        return err;
 692}
 693
 694void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
 695{
 696        oxfw->dev_lock_changed = true;
 697        wake_up(&oxfw->hwdep_wait);
 698}
 699
 700int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
 701{
 702        int err;
 703
 704        spin_lock_irq(&oxfw->lock);
 705
 706        /* user land lock this */
 707        if (oxfw->dev_lock_count < 0) {
 708                err = -EBUSY;
 709                goto end;
 710        }
 711
 712        /* this is the first time */
 713        if (oxfw->dev_lock_count++ == 0)
 714                snd_oxfw_stream_lock_changed(oxfw);
 715        err = 0;
 716end:
 717        spin_unlock_irq(&oxfw->lock);
 718        return err;
 719}
 720
 721void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
 722{
 723        spin_lock_irq(&oxfw->lock);
 724
 725        if (WARN_ON(oxfw->dev_lock_count <= 0))
 726                goto end;
 727        if (--oxfw->dev_lock_count == 0)
 728                snd_oxfw_stream_lock_changed(oxfw);
 729end:
 730        spin_unlock_irq(&oxfw->lock);
 731}
 732