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