linux/sound/usb/usx2y/usx2yhwdeppcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 */
   4
   5/* USX2Y "rawusb" aka hwdep_pcm implementation
   6
   7 Its usb's unableness to atomically handle power of 2 period sized data chuncs
   8 at standard samplerates,
   9 what led to this part of the usx2y module:
  10 It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
  11 The pair uses a hardware dependent alsa-device for mmaped pcm transport.
  12 Advantage achieved:
  13         The usb_hc moves pcm data from/into memory via DMA.
  14         That memory is mmaped by jack's usx2y driver.
  15         Jack's usx2y driver is the first/last to read/write pcm data.
  16         Read/write is a combination of power of 2 period shaping and
  17         float/int conversation.
  18         Compared to mainline alsa/jack we leave out power of 2 period shaping inside
  19         snd-usb-usx2y which needs memcpy() and additional buffers.
  20         As a side effect possible unwanted pcm-data coruption resulting of
  21         standard alsa's snd-usb-usx2y period shaping scheme falls away.
  22         Result is sane jack operation at buffering schemes down to 128frames,
  23         2 periods.
  24         plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
  25         cost of easier triggered i.e. aeolus xruns (128 or 256frames,
  26         2periods works but is useless cause of crackling).
  27
  28 This is a first "proof of concept" implementation.
  29 Later, functionalities should migrate to more appropriate places:
  30 Userland:
  31 - The jackd could mmap its float-pcm buffers directly from alsa-lib.
  32 - alsa-lib could provide power of 2 period sized shaping combined with int/float
  33   conversation.
  34   Currently the usx2y jack driver provides above 2 services.
  35 Kernel:
  36 - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
  37   devices can use it.
  38   Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
  39*/
  40
  41#include <linux/delay.h>
  42#include <linux/gfp.h>
  43#include "usbusx2yaudio.c"
  44
  45#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
  46
  47#include <sound/hwdep.h>
  48
  49static int usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream *subs)
  50{
  51        struct urb      *urb = subs->completed_urb;
  52        struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
  53        int             i, lens = 0, hwptr_done = subs->hwptr_done;
  54        struct usx2ydev *usx2y = subs->usx2y;
  55        int head;
  56
  57        if (usx2y->hwdep_pcm_shm->capture_iso_start < 0) { //FIXME
  58                head = usx2y->hwdep_pcm_shm->captured_iso_head + 1;
  59                if (head >= ARRAY_SIZE(usx2y->hwdep_pcm_shm->captured_iso))
  60                        head = 0;
  61                usx2y->hwdep_pcm_shm->capture_iso_start = head;
  62                snd_printdd("cap start %i\n", head);
  63        }
  64        for (i = 0; i < nr_of_packs(); i++) {
  65                if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
  66                        snd_printk(KERN_ERR
  67                                   "active frame status %i. Most probably some hardware problem.\n",
  68                                   urb->iso_frame_desc[i].status);
  69                        return urb->iso_frame_desc[i].status;
  70                }
  71                lens += urb->iso_frame_desc[i].actual_length / usx2y->stride;
  72        }
  73        hwptr_done += lens;
  74        if (hwptr_done >= runtime->buffer_size)
  75                hwptr_done -= runtime->buffer_size;
  76        subs->hwptr_done = hwptr_done;
  77        subs->transfer_done += lens;
  78        /* update the pointer, call callback if necessary */
  79        if (subs->transfer_done >= runtime->period_size) {
  80                subs->transfer_done -= runtime->period_size;
  81                snd_pcm_period_elapsed(subs->pcm_substream);
  82        }
  83        return 0;
  84}
  85
  86static int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
  87                                              struct usx2ydev *usx2y)
  88{
  89        return (runtime->buffer_size * 1000) / usx2y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
  90}
  91
  92/*
  93 * prepare urb for playback data pipe
  94 *
  95 * we copy the data directly from the pcm buffer.
  96 * the current position to be copied is held in hwptr field.
  97 * since a urb can handle only a single linear buffer, if the total
  98 * transferred area overflows the buffer boundary, we cannot send
  99 * it directly from the buffer.  thus the data is once copied to
 100 * a temporary buffer and urb points to that.
 101 */
 102static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs,
 103                                        struct urb *urb)
 104{
 105        int count, counts, pack;
 106        struct usx2ydev *usx2y = subs->usx2y;
 107        struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm;
 108        struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
 109
 110        if (shm->playback_iso_start < 0) {
 111                shm->playback_iso_start = shm->captured_iso_head -
 112                        usx2y_iso_frames_per_buffer(runtime, usx2y);
 113                if (shm->playback_iso_start < 0)
 114                        shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
 115                shm->playback_iso_head = shm->playback_iso_start;
 116        }
 117
 118        count = 0;
 119        for (pack = 0; pack < nr_of_packs(); pack++) {
 120                /* calculate the size of a packet */
 121                counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride;
 122                if (counts < 43 || counts > 50) {
 123                        snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
 124                        return -EPIPE;
 125                }
 126                /* set up descriptor */
 127                urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
 128                urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
 129                if (atomic_read(&subs->state) != STATE_RUNNING)
 130                        memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
 131                               urb->iso_frame_desc[pack].length);
 132                if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
 133                        shm->playback_iso_head = 0;
 134                count += counts;
 135        }
 136        urb->transfer_buffer_length = count * usx2y->stride;
 137        return 0;
 138}
 139
 140static void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs,
 141                                              struct urb *urb)
 142{
 143        struct usb_iso_packet_descriptor *desc;
 144        struct snd_usx2y_hwdep_pcm_shm *shm;
 145        int pack, head;
 146
 147        for (pack = 0; pack < nr_of_packs(); ++pack) {
 148                desc = urb->iso_frame_desc + pack;
 149                if (subs) {
 150                        shm = subs->usx2y->hwdep_pcm_shm;
 151                        head = shm->captured_iso_head + 1;
 152                        if (head >= ARRAY_SIZE(shm->captured_iso))
 153                                head = 0;
 154                        shm->captured_iso[head].frame = urb->start_frame + pack;
 155                        shm->captured_iso[head].offset = desc->offset;
 156                        shm->captured_iso[head].length = desc->actual_length;
 157                        shm->captured_iso_head = head;
 158                        shm->captured_iso_frames++;
 159                }
 160                desc->offset += desc->length * NRURBS * nr_of_packs();
 161                if (desc->offset + desc->length >= SSS)
 162                        desc->offset -= (SSS - desc->length);
 163        }
 164}
 165
 166static int usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream *capsubs,
 167                                          struct snd_usx2y_substream *capsubs2,
 168                                          struct snd_usx2y_substream *playbacksubs,
 169                                          int frame)
 170{
 171        int err, state;
 172        struct urb *urb = playbacksubs->completed_urb;
 173
 174        state = atomic_read(&playbacksubs->state);
 175        if (urb) {
 176                if (state == STATE_RUNNING)
 177                        usx2y_urb_play_retire(playbacksubs, urb);
 178                else if (state >= STATE_PRERUNNING)
 179                        atomic_inc(&playbacksubs->state);
 180        } else {
 181                switch (state) {
 182                case STATE_STARTING1:
 183                        urb = playbacksubs->urb[0];
 184                        atomic_inc(&playbacksubs->state);
 185                        break;
 186                case STATE_STARTING2:
 187                        urb = playbacksubs->urb[1];
 188                        atomic_inc(&playbacksubs->state);
 189                        break;
 190                }
 191        }
 192        if (urb) {
 193                err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
 194                if (err)
 195                        return err;
 196                err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
 197                if (err)
 198                        return err;
 199        }
 200
 201        playbacksubs->completed_urb = NULL;
 202
 203        state = atomic_read(&capsubs->state);
 204        if (state >= STATE_PREPARED) {
 205                if (state == STATE_RUNNING) {
 206                        err = usx2y_usbpcm_urb_capt_retire(capsubs);
 207                        if (err)
 208                                return err;
 209                } else if (state >= STATE_PRERUNNING) {
 210                        atomic_inc(&capsubs->state);
 211                }
 212                usx2y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
 213                if (capsubs2)
 214                        usx2y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
 215                err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame);
 216                if (err)
 217                        return err;
 218                if (capsubs2) {
 219                        err = usx2y_urb_submit(capsubs2, capsubs2->completed_urb, frame);
 220                        if (err)
 221                                return err;
 222                }
 223        }
 224        capsubs->completed_urb = NULL;
 225        if (capsubs2)
 226                capsubs2->completed_urb = NULL;
 227        return 0;
 228}
 229
 230static void i_usx2y_usbpcm_urb_complete(struct urb *urb)
 231{
 232        struct snd_usx2y_substream *subs = urb->context;
 233        struct usx2ydev *usx2y = subs->usx2y;
 234        struct snd_usx2y_substream *capsubs, *capsubs2, *playbacksubs;
 235
 236        if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
 237                snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
 238                            usb_get_current_frame_number(usx2y->dev),
 239                            subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
 240                            urb->status, urb->start_frame);
 241                return;
 242        }
 243        if (unlikely(urb->status)) {
 244                usx2y_error_urb_status(usx2y, subs, urb);
 245                return;
 246        }
 247
 248        subs->completed_urb = urb;
 249        capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
 250        capsubs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 251        playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 252        if (capsubs->completed_urb && atomic_read(&capsubs->state) >= STATE_PREPARED &&
 253            (!capsubs2 || capsubs2->completed_urb) &&
 254            (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
 255                if (!usx2y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
 256                        usx2y->wait_iso_frame += nr_of_packs();
 257                } else {
 258                        snd_printdd("\n");
 259                        usx2y_clients_stop(usx2y);
 260                }
 261        }
 262}
 263
 264static void usx2y_hwdep_urb_release(struct urb **urb)
 265{
 266        usb_kill_urb(*urb);
 267        usb_free_urb(*urb);
 268        *urb = NULL;
 269}
 270
 271/*
 272 * release a substream
 273 */
 274static void usx2y_usbpcm_urbs_release(struct snd_usx2y_substream *subs)
 275{
 276        int i;
 277
 278        snd_printdd("snd_usx2y_urbs_release() %i\n", subs->endpoint);
 279        for (i = 0; i < NRURBS; i++)
 280                usx2y_hwdep_urb_release(subs->urb + i);
 281}
 282
 283static void usx2y_usbpcm_subs_startup_finish(struct usx2ydev *usx2y)
 284{
 285        usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_urb_complete);
 286        usx2y->prepare_subs = NULL;
 287}
 288
 289static void i_usx2y_usbpcm_subs_startup(struct urb *urb)
 290{
 291        struct snd_usx2y_substream *subs = urb->context;
 292        struct usx2ydev *usx2y = subs->usx2y;
 293        struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
 294        struct snd_usx2y_substream *cap_subs2;
 295
 296        if (prepare_subs &&
 297            urb->start_frame == prepare_subs->urb[0]->start_frame) {
 298                atomic_inc(&prepare_subs->state);
 299                if (prepare_subs == usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
 300                        cap_subs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 301                        if (cap_subs2)
 302                                atomic_inc(&cap_subs2->state);
 303                }
 304                usx2y_usbpcm_subs_startup_finish(usx2y);
 305                wake_up(&usx2y->prepare_wait_queue);
 306        }
 307
 308        i_usx2y_usbpcm_urb_complete(urb);
 309}
 310
 311/*
 312 * initialize a substream's urbs
 313 */
 314static int usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream *subs)
 315{
 316        int i;
 317        unsigned int pipe;
 318        int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 319        struct usb_device *dev = subs->usx2y->dev;
 320        struct urb **purb;
 321
 322        pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
 323                        usb_rcvisocpipe(dev, subs->endpoint);
 324        subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
 325        if (!subs->maxpacksize)
 326                return -EINVAL;
 327
 328        /* allocate and initialize data urbs */
 329        for (i = 0; i < NRURBS; i++) {
 330                purb = subs->urb + i;
 331                if (*purb) {
 332                        usb_kill_urb(*purb);
 333                        continue;
 334                }
 335                *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
 336                if (!*purb) {
 337                        usx2y_usbpcm_urbs_release(subs);
 338                        return -ENOMEM;
 339                }
 340                (*purb)->transfer_buffer = is_playback ?
 341                        subs->usx2y->hwdep_pcm_shm->playback : (
 342                                subs->endpoint == 0x8 ?
 343                                subs->usx2y->hwdep_pcm_shm->capture0x8 :
 344                                subs->usx2y->hwdep_pcm_shm->capture0xA);
 345
 346                (*purb)->dev = dev;
 347                (*purb)->pipe = pipe;
 348                (*purb)->number_of_packets = nr_of_packs();
 349                (*purb)->context = subs;
 350                (*purb)->interval = 1;
 351                (*purb)->complete = i_usx2y_usbpcm_subs_startup;
 352        }
 353        return 0;
 354}
 355
 356/*
 357 * free the buffer
 358 */
 359static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream)
 360{
 361        struct snd_pcm_runtime *runtime = substream->runtime;
 362        struct snd_usx2y_substream *subs = runtime->private_data;
 363        struct snd_usx2y_substream *cap_subs;
 364        struct snd_usx2y_substream *playback_subs;
 365        struct snd_usx2y_substream *cap_subs2;
 366
 367        mutex_lock(&subs->usx2y->pcm_mutex);
 368        snd_printdd("%s(%p)\n", __func__, substream);
 369
 370        cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 371        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 372                cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
 373                atomic_set(&subs->state, STATE_STOPPED);
 374                usx2y_usbpcm_urbs_release(subs);
 375                if (!cap_subs->pcm_substream ||
 376                    !cap_subs->pcm_substream->runtime ||
 377                    !cap_subs->pcm_substream->runtime->status ||
 378                    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
 379                        atomic_set(&cap_subs->state, STATE_STOPPED);
 380                        if (cap_subs2)
 381                                atomic_set(&cap_subs2->state, STATE_STOPPED);
 382                        usx2y_usbpcm_urbs_release(cap_subs);
 383                        if (cap_subs2)
 384                                usx2y_usbpcm_urbs_release(cap_subs2);
 385                }
 386        } else {
 387                playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 388                if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
 389                        atomic_set(&subs->state, STATE_STOPPED);
 390                        if (cap_subs2)
 391                                atomic_set(&cap_subs2->state, STATE_STOPPED);
 392                        usx2y_usbpcm_urbs_release(subs);
 393                        if (cap_subs2)
 394                                usx2y_usbpcm_urbs_release(cap_subs2);
 395                }
 396        }
 397        mutex_unlock(&subs->usx2y->pcm_mutex);
 398        return 0;
 399}
 400
 401static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs)
 402{
 403        struct usx2ydev *usx2y = subs->usx2y;
 404
 405        usx2y->prepare_subs = subs;
 406        subs->urb[0]->start_frame = -1;
 407        smp_wmb();      // Make sure above modifications are seen by i_usx2y_subs_startup()
 408        usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup);
 409}
 410
 411static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs)
 412{
 413        int     p, u, err, stream = subs->pcm_substream->stream;
 414        struct usx2ydev *usx2y = subs->usx2y;
 415        struct urb *urb;
 416        unsigned long pack;
 417
 418        if (stream == SNDRV_PCM_STREAM_CAPTURE) {
 419                usx2y->hwdep_pcm_shm->captured_iso_head = -1;
 420                usx2y->hwdep_pcm_shm->captured_iso_frames = 0;
 421        }
 422
 423        for (p = 0; 3 >= (stream + p); p += 2) {
 424                struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
 425                if (subs) {
 426                        err = usx2y_usbpcm_urbs_allocate(subs);
 427                        if (err < 0)
 428                                return err;
 429                        subs->completed_urb = NULL;
 430                }
 431        }
 432
 433        for (p = 0; p < 4; p++) {
 434                struct snd_usx2y_substream *subs = usx2y->subs[p];
 435
 436                if (subs && atomic_read(&subs->state) >= STATE_PREPARED)
 437                        goto start;
 438        }
 439
 440 start:
 441        usx2y_usbpcm_subs_startup(subs);
 442        for (u = 0; u < NRURBS; u++) {
 443                for (p = 0; 3 >= (stream + p); p += 2) {
 444                        struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
 445
 446                        if (!subs)
 447                                continue;
 448                        urb = subs->urb[u];
 449                        if (usb_pipein(urb->pipe)) {
 450                                if (!u)
 451                                        atomic_set(&subs->state, STATE_STARTING3);
 452                                urb->dev = usx2y->dev;
 453                                for (pack = 0; pack < nr_of_packs(); pack++) {
 454                                        urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
 455                                        urb->iso_frame_desc[pack].length = subs->maxpacksize;
 456                                }
 457                                urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
 458                                err = usb_submit_urb(urb, GFP_KERNEL);
 459                                if (err < 0) {
 460                                        snd_printk(KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
 461                                        err = -EPIPE;
 462                                        goto cleanup;
 463                                }  else {
 464                                        snd_printdd("%i\n", urb->start_frame);
 465                                        if (!u)
 466                                                usx2y->wait_iso_frame = urb->start_frame;
 467                                }
 468                                urb->transfer_flags = 0;
 469                        } else {
 470                                atomic_set(&subs->state, STATE_STARTING1);
 471                                break;
 472                        }
 473                }
 474        }
 475        err = 0;
 476        wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs);
 477        if (atomic_read(&subs->state) != STATE_PREPARED)
 478                err = -EPIPE;
 479
 480 cleanup:
 481        if (err) {
 482                usx2y_subs_startup_finish(usx2y);       // Call it now
 483                usx2y_clients_stop(usx2y);      // something is completely wrong > stop everything
 484        }
 485        return err;
 486}
 487
 488#define USX2Y_HWDEP_PCM_PAGES   \
 489        PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm))
 490
 491/*
 492 * prepare callback
 493 *
 494 * set format and initialize urbs
 495 */
 496static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream)
 497{
 498        struct snd_pcm_runtime *runtime = substream->runtime;
 499        struct snd_usx2y_substream *subs = runtime->private_data;
 500        struct usx2ydev *usx2y = subs->usx2y;
 501        struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
 502        int err = 0;
 503
 504        snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
 505
 506        mutex_lock(&usx2y->pcm_mutex);
 507
 508        if (!usx2y->hwdep_pcm_shm) {
 509                usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES,
 510                                                         GFP_KERNEL);
 511                if (!usx2y->hwdep_pcm_shm) {
 512                        err = -ENOMEM;
 513                        goto up_prepare_mutex;
 514                }
 515                memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES);
 516        }
 517
 518        usx2y_subs_prepare(subs);
 519        // Start hardware streams
 520        // SyncStream first....
 521        if (atomic_read(&capsubs->state) < STATE_PREPARED) {
 522                if (usx2y->format != runtime->format) {
 523                        err = usx2y_format_set(usx2y, runtime->format);
 524                        if (err < 0)
 525                                goto up_prepare_mutex;
 526                }
 527                if (usx2y->rate != runtime->rate) {
 528                        err = usx2y_rate_set(usx2y, runtime->rate);
 529                        if (err < 0)
 530                                goto up_prepare_mutex;
 531                }
 532                snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
 533                            "self" : "playpipe");
 534                err = usx2y_usbpcm_urbs_start(capsubs);
 535                if (err < 0)
 536                        goto up_prepare_mutex;
 537        }
 538
 539        if (subs != capsubs) {
 540                usx2y->hwdep_pcm_shm->playback_iso_start = -1;
 541                if (atomic_read(&subs->state) < STATE_PREPARED) {
 542                        while (usx2y_iso_frames_per_buffer(runtime, usx2y) >
 543                               usx2y->hwdep_pcm_shm->captured_iso_frames) {
 544                                snd_printdd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
 545                                            usx2y_iso_frames_per_buffer(runtime, usx2y),
 546                                            usx2y->hwdep_pcm_shm->captured_iso_frames);
 547                                if (msleep_interruptible(10)) {
 548                                        err = -ERESTARTSYS;
 549                                        goto up_prepare_mutex;
 550                                }
 551                        }
 552                        err = usx2y_usbpcm_urbs_start(subs);
 553                        if (err < 0)
 554                                goto up_prepare_mutex;
 555                }
 556                snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
 557                            usx2y_iso_frames_per_buffer(runtime, usx2y),
 558                            usx2y->hwdep_pcm_shm->captured_iso_frames);
 559        } else {
 560                usx2y->hwdep_pcm_shm->capture_iso_start = -1;
 561        }
 562
 563 up_prepare_mutex:
 564        mutex_unlock(&usx2y->pcm_mutex);
 565        return err;
 566}
 567
 568static const struct snd_pcm_hardware snd_usx2y_4c = {
 569        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 570                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 571                                 SNDRV_PCM_INFO_MMAP_VALID),
 572        .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
 573        .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 574        .rate_min =                44100,
 575        .rate_max =                48000,
 576        .channels_min =            2,
 577        .channels_max =            4,
 578        .buffer_bytes_max =     (2*128*1024),
 579        .period_bytes_min =     64,
 580        .period_bytes_max =     (128*1024),
 581        .periods_min =          2,
 582        .periods_max =          1024,
 583        .fifo_size =              0
 584};
 585
 586static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream)
 587{
 588        struct snd_usx2y_substream      *subs =
 589                ((struct snd_usx2y_substream **)
 590                 snd_pcm_substream_chip(substream))[substream->stream];
 591        struct snd_pcm_runtime  *runtime = substream->runtime;
 592
 593        if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
 594                return -EBUSY;
 595
 596        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 597                runtime->hw = snd_usx2y_2c;
 598        else
 599                runtime->hw = (subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c);
 600        runtime->private_data = subs;
 601        subs->pcm_substream = substream;
 602        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
 603        return 0;
 604}
 605
 606static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream)
 607{
 608        struct snd_pcm_runtime *runtime = substream->runtime;
 609        struct snd_usx2y_substream *subs = runtime->private_data;
 610
 611        subs->pcm_substream = NULL;
 612        return 0;
 613}
 614
 615static const struct snd_pcm_ops snd_usx2y_usbpcm_ops = {
 616        .open =         snd_usx2y_usbpcm_open,
 617        .close =        snd_usx2y_usbpcm_close,
 618        .hw_params =    snd_usx2y_pcm_hw_params,
 619        .hw_free =      snd_usx2y_usbpcm_hw_free,
 620        .prepare =      snd_usx2y_usbpcm_prepare,
 621        .trigger =      snd_usx2y_pcm_trigger,
 622        .pointer =      snd_usx2y_pcm_pointer,
 623};
 624
 625static int usx2y_pcms_busy_check(struct snd_card *card)
 626{
 627        struct usx2ydev *dev = usx2y(card);
 628        struct snd_usx2y_substream *subs;
 629        int i;
 630
 631        for (i = 0; i < dev->pcm_devs * 2; i++) {
 632                subs = dev->subs[i];
 633                if (subs && subs->pcm_substream &&
 634                    SUBSTREAM_BUSY(subs->pcm_substream))
 635                        return -EBUSY;
 636        }
 637        return 0;
 638}
 639
 640static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
 641{
 642        struct snd_card *card = hw->card;
 643        int err;
 644
 645        mutex_lock(&usx2y(card)->pcm_mutex);
 646        err = usx2y_pcms_busy_check(card);
 647        if (!err)
 648                usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
 649        mutex_unlock(&usx2y(card)->pcm_mutex);
 650        return err;
 651}
 652
 653static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
 654{
 655        struct snd_card *card = hw->card;
 656        int err;
 657
 658        mutex_lock(&usx2y(card)->pcm_mutex);
 659        err = usx2y_pcms_busy_check(card);
 660        if (!err)
 661                usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
 662        mutex_unlock(&usx2y(card)->pcm_mutex);
 663        return err;
 664}
 665
 666static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area)
 667{
 668}
 669
 670static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area)
 671{
 672}
 673
 674static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
 675{
 676        unsigned long offset;
 677        void *vaddr;
 678
 679        offset = vmf->pgoff << PAGE_SHIFT;
 680        vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
 681        vmf->page = virt_to_page(vaddr);
 682        get_page(vmf->page);
 683        return 0;
 684}
 685
 686static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = {
 687        .open = snd_usx2y_hwdep_pcm_vm_open,
 688        .close = snd_usx2y_hwdep_pcm_vm_close,
 689        .fault = snd_usx2y_hwdep_pcm_vm_fault,
 690};
 691
 692static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area)
 693{
 694        unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
 695        struct usx2ydev *usx2y = hw->private_data;
 696
 697        if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT))
 698                return -EBUSY;
 699
 700        /* if userspace tries to mmap beyond end of our buffer, fail */
 701        if (size > USX2Y_HWDEP_PCM_PAGES) {
 702                snd_printd("%lu > %lu\n", size, (unsigned long)USX2Y_HWDEP_PCM_PAGES);
 703                return -EINVAL;
 704        }
 705
 706        if (!usx2y->hwdep_pcm_shm)
 707                return -ENODEV;
 708
 709        area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops;
 710        area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 711        area->vm_private_data = hw->private_data;
 712        return 0;
 713}
 714
 715static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
 716{
 717        struct usx2ydev *usx2y = hwdep->private_data;
 718
 719        if (usx2y->hwdep_pcm_shm)
 720                free_pages_exact(usx2y->hwdep_pcm_shm, USX2Y_HWDEP_PCM_PAGES);
 721}
 722
 723int usx2y_hwdep_pcm_new(struct snd_card *card)
 724{
 725        int err;
 726        struct snd_hwdep *hw;
 727        struct snd_pcm *pcm;
 728        struct usb_device *dev = usx2y(card)->dev;
 729
 730        if (nr_of_packs() != 1)
 731                return 0;
 732
 733        err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw);
 734        if (err < 0)
 735                return err;
 736
 737        hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
 738        hw->private_data = usx2y(card);
 739        hw->private_free = snd_usx2y_hwdep_pcm_private_free;
 740        hw->ops.open = snd_usx2y_hwdep_pcm_open;
 741        hw->ops.release = snd_usx2y_hwdep_pcm_release;
 742        hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap;
 743        hw->exclusive = 1;
 744        sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
 745
 746        err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
 747        if (err < 0)
 748                return err;
 749
 750        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops);
 751        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops);
 752
 753        pcm->private_data = usx2y(card)->subs;
 754        pcm->info_flags = 0;
 755
 756        sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
 757        snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
 758                                   SNDRV_DMA_TYPE_CONTINUOUS,
 759                                   NULL,
 760                                   64*1024, 128*1024);
 761        snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
 762                                   SNDRV_DMA_TYPE_CONTINUOUS,
 763                                   NULL,
 764                                   64*1024, 128*1024);
 765
 766        return 0;
 767}
 768
 769#else
 770
 771int usx2y_hwdep_pcm_new(struct snd_card *card)
 772{
 773        return 0;
 774}
 775
 776#endif
 777