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 "activ frame status %i. Most propably 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        if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
 248                subs->completed_urb = urb;
 249        else {
 250                usX2Y_error_sequence(usX2Y, subs, urb);
 251                return;
 252        }
 253
 254        capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
 255        capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 256        playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 257        if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
 258            (NULL == capsubs2 || capsubs2->completed_urb) &&
 259            (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
 260                if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
 261                        usX2Y->wait_iso_frame += nr_of_packs();
 262                else {
 263                        snd_printdd("\n");
 264                        usX2Y_clients_stop(usX2Y);
 265                }
 266        }
 267}
 268
 269
 270static void usX2Y_hwdep_urb_release(struct urb **urb)
 271{
 272        usb_kill_urb(*urb);
 273        usb_free_urb(*urb);
 274        *urb = NULL;
 275}
 276
 277/*
 278 * release a substream
 279 */
 280static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
 281{
 282        int i;
 283        snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
 284        for (i = 0; i < NRURBS; i++)
 285                usX2Y_hwdep_urb_release(subs->urb + i);
 286}
 287
 288static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
 289{
 290        usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
 291        usX2Y->prepare_subs = NULL;
 292}
 293
 294static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
 295{
 296        struct snd_usX2Y_substream *subs = urb->context;
 297        struct usX2Ydev *usX2Y = subs->usX2Y;
 298        struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
 299        if (NULL != prepare_subs &&
 300            urb->start_frame == prepare_subs->urb[0]->start_frame) {
 301                atomic_inc(&prepare_subs->state);
 302                if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
 303                        struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 304                        if (cap_subs2 != NULL)
 305                                atomic_inc(&cap_subs2->state);
 306                }
 307                usX2Y_usbpcm_subs_startup_finish(usX2Y);
 308                wake_up(&usX2Y->prepare_wait_queue);
 309        }
 310
 311        i_usX2Y_usbpcm_urb_complete(urb);
 312}
 313
 314/*
 315 * initialize a substream's urbs
 316 */
 317static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
 318{
 319        int i;
 320        unsigned int pipe;
 321        int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 322        struct usb_device *dev = subs->usX2Y->dev;
 323
 324        pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
 325                        usb_rcvisocpipe(dev, subs->endpoint);
 326        subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
 327        if (!subs->maxpacksize)
 328                return -EINVAL;
 329
 330        /* allocate and initialize data urbs */
 331        for (i = 0; i < NRURBS; i++) {
 332                struct urb **purb = subs->urb + i;
 333                if (*purb) {
 334                        usb_kill_urb(*purb);
 335                        continue;
 336                }
 337                *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
 338                if (NULL == *purb) {
 339                        usX2Y_usbpcm_urbs_release(subs);
 340                        return -ENOMEM;
 341                }
 342                (*purb)->transfer_buffer = is_playback ?
 343                        subs->usX2Y->hwdep_pcm_shm->playback : (
 344                                subs->endpoint == 0x8 ?
 345                                subs->usX2Y->hwdep_pcm_shm->capture0x8 :
 346                                subs->usX2Y->hwdep_pcm_shm->capture0xA);
 347
 348                (*purb)->dev = dev;
 349                (*purb)->pipe = pipe;
 350                (*purb)->number_of_packets = nr_of_packs();
 351                (*purb)->context = subs;
 352                (*purb)->interval = 1;
 353                (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
 354        }
 355        return 0;
 356}
 357
 358/*
 359 * free the buffer
 360 */
 361static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
 362{
 363        struct snd_pcm_runtime *runtime = substream->runtime;
 364        struct snd_usX2Y_substream *subs = runtime->private_data,
 365                *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 366        mutex_lock(&subs->usX2Y->prepare_mutex);
 367        snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
 368
 369        if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
 370                struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
 371                atomic_set(&subs->state, state_STOPPED);
 372                usX2Y_usbpcm_urbs_release(subs);
 373                if (!cap_subs->pcm_substream ||
 374                    !cap_subs->pcm_substream->runtime ||
 375                    !cap_subs->pcm_substream->runtime->status ||
 376                    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
 377                        atomic_set(&cap_subs->state, state_STOPPED);
 378                        if (NULL != cap_subs2)
 379                                atomic_set(&cap_subs2->state, state_STOPPED);
 380                        usX2Y_usbpcm_urbs_release(cap_subs);
 381                        if (NULL != cap_subs2)
 382                                usX2Y_usbpcm_urbs_release(cap_subs2);
 383                }
 384        } else {
 385                struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 386                if (atomic_read(&playback_subs->state) < state_PREPARED) {
 387                        atomic_set(&subs->state, state_STOPPED);
 388                        if (NULL != cap_subs2)
 389                                atomic_set(&cap_subs2->state, state_STOPPED);
 390                        usX2Y_usbpcm_urbs_release(subs);
 391                        if (NULL != cap_subs2)
 392                                usX2Y_usbpcm_urbs_release(cap_subs2);
 393                }
 394        }
 395        mutex_unlock(&subs->usX2Y->prepare_mutex);
 396        return snd_pcm_lib_free_pages(substream);
 397}
 398
 399static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
 400{
 401        struct usX2Ydev * usX2Y = subs->usX2Y;
 402        usX2Y->prepare_subs = subs;
 403        subs->urb[0]->start_frame = -1;
 404        smp_wmb();      // Make sure above modifications are seen by i_usX2Y_subs_startup()
 405        usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
 406}
 407
 408static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
 409{
 410        int     p, u, err,
 411                stream = subs->pcm_substream->stream;
 412        struct usX2Ydev *usX2Y = subs->usX2Y;
 413
 414        if (SNDRV_PCM_STREAM_CAPTURE == stream) {
 415                usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
 416                usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
 417        }
 418
 419        for (p = 0; 3 >= (stream + p); p += 2) {
 420                struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
 421                if (subs != NULL) {
 422                        if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
 423                                return err;
 424                        subs->completed_urb = NULL;
 425                }
 426        }
 427
 428        for (p = 0; p < 4; p++) {
 429                struct snd_usX2Y_substream *subs = usX2Y->subs[p];
 430                if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
 431                        goto start;
 432        }
 433
 434 start:
 435        usX2Y_usbpcm_subs_startup(subs);
 436        for (u = 0; u < NRURBS; u++) {
 437                for (p = 0; 3 >= (stream + p); p += 2) {
 438                        struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
 439                        if (subs != NULL) {
 440                                struct urb *urb = subs->urb[u];
 441                                if (usb_pipein(urb->pipe)) {
 442                                        unsigned long pack;
 443                                        if (0 == u)
 444                                                atomic_set(&subs->state, state_STARTING3);
 445                                        urb->dev = usX2Y->dev;
 446                                        urb->transfer_flags = URB_ISO_ASAP;
 447                                        for (pack = 0; pack < nr_of_packs(); pack++) {
 448                                                urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
 449                                                urb->iso_frame_desc[pack].length = subs->maxpacksize;
 450                                        }
 451                                        urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); 
 452                                        if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
 453                                                snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
 454                                                err = -EPIPE;
 455                                                goto cleanup;
 456                                        }  else {
 457                                                snd_printdd("%i\n", urb->start_frame);
 458                                                if (u == 0)
 459                                                        usX2Y->wait_iso_frame = urb->start_frame;
 460                                        }
 461                                        urb->transfer_flags = 0;
 462                                } else {
 463                                        atomic_set(&subs->state, state_STARTING1);
 464                                        break;
 465                                }                       
 466                        }
 467                }
 468        }
 469        err = 0;
 470        wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
 471        if (atomic_read(&subs->state) != state_PREPARED)
 472                err = -EPIPE;
 473                
 474 cleanup:
 475        if (err) {
 476                usX2Y_subs_startup_finish(usX2Y);       // Call it now
 477                usX2Y_clients_stop(usX2Y);              // something is completely wroong > stop evrything                      
 478        }
 479        return err;
 480}
 481
 482/*
 483 * prepare callback
 484 *
 485 * set format and initialize urbs
 486 */
 487static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
 488{
 489        struct snd_pcm_runtime *runtime = substream->runtime;
 490        struct snd_usX2Y_substream *subs = runtime->private_data;
 491        struct usX2Ydev *usX2Y = subs->usX2Y;
 492        struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
 493        int err = 0;
 494        snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
 495
 496        if (NULL == usX2Y->hwdep_pcm_shm) {
 497                if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
 498                        return -ENOMEM;
 499                memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 500        }
 501
 502        mutex_lock(&usX2Y->prepare_mutex);
 503        usX2Y_subs_prepare(subs);
 504// Start hardware streams
 505// SyncStream first....
 506        if (atomic_read(&capsubs->state) < state_PREPARED) {
 507                if (usX2Y->format != runtime->format)
 508                        if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
 509                                goto up_prepare_mutex;
 510                if (usX2Y->rate != runtime->rate)
 511                        if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
 512                                goto up_prepare_mutex;
 513                snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
 514                            "self" : "playpipe");
 515                if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
 516                        goto up_prepare_mutex;
 517        }
 518
 519        if (subs != capsubs) {
 520                usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
 521                if (atomic_read(&subs->state) < state_PREPARED) {
 522                        while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
 523                               usX2Y->hwdep_pcm_shm->captured_iso_frames) {
 524                                snd_printdd("Wait: iso_frames_per_buffer=%i,"
 525                                            "captured_iso_frames=%i\n",
 526                                            usX2Y_iso_frames_per_buffer(runtime, usX2Y),
 527                                            usX2Y->hwdep_pcm_shm->captured_iso_frames);
 528                                if (msleep_interruptible(10)) {
 529                                        err = -ERESTARTSYS;
 530                                        goto up_prepare_mutex;
 531                                }
 532                        } 
 533                        if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
 534                                goto up_prepare_mutex;
 535                }
 536                snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
 537                            usX2Y_iso_frames_per_buffer(runtime, usX2Y),
 538                            usX2Y->hwdep_pcm_shm->captured_iso_frames);
 539        } else
 540                usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
 541
 542 up_prepare_mutex:
 543        mutex_unlock(&usX2Y->prepare_mutex);
 544        return err;
 545}
 546
 547static struct snd_pcm_hardware snd_usX2Y_4c =
 548{
 549        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 550                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 551                                 SNDRV_PCM_INFO_MMAP_VALID),
 552        .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
 553        .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 554        .rate_min =                44100,
 555        .rate_max =                48000,
 556        .channels_min =            2,
 557        .channels_max =            4,
 558        .buffer_bytes_max =     (2*128*1024),
 559        .period_bytes_min =     64,
 560        .period_bytes_max =     (128*1024),
 561        .periods_min =          2,
 562        .periods_max =          1024,
 563        .fifo_size =              0
 564};
 565
 566
 567
 568static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
 569{
 570        struct snd_usX2Y_substream      *subs = ((struct snd_usX2Y_substream **)
 571                                         snd_pcm_substream_chip(substream))[substream->stream];
 572        struct snd_pcm_runtime  *runtime = substream->runtime;
 573
 574        if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
 575                return -EBUSY;
 576
 577        runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
 578                (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
 579        runtime->private_data = subs;
 580        subs->pcm_substream = substream;
 581        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
 582        return 0;
 583}
 584
 585
 586static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
 587{
 588        struct snd_pcm_runtime *runtime = substream->runtime;
 589        struct snd_usX2Y_substream *subs = runtime->private_data;
 590
 591        subs->pcm_substream = NULL;
 592        return 0;
 593}
 594
 595
 596static struct snd_pcm_ops snd_usX2Y_usbpcm_ops = 
 597{
 598        .open =         snd_usX2Y_usbpcm_open,
 599        .close =        snd_usX2Y_usbpcm_close,
 600        .ioctl =        snd_pcm_lib_ioctl,
 601        .hw_params =    snd_usX2Y_pcm_hw_params,
 602        .hw_free =      snd_usX2Y_usbpcm_hw_free,
 603        .prepare =      snd_usX2Y_usbpcm_prepare,
 604        .trigger =      snd_usX2Y_pcm_trigger,
 605        .pointer =      snd_usX2Y_pcm_pointer,
 606};
 607
 608
 609static int usX2Y_pcms_lock_check(struct snd_card *card)
 610{
 611        struct list_head *list;
 612        struct snd_device *dev;
 613        struct snd_pcm *pcm;
 614        int err = 0;
 615        list_for_each(list, &card->devices) {
 616                dev = snd_device(list);
 617                if (dev->type != SNDRV_DEV_PCM)
 618                        continue;
 619                pcm = dev->device_data;
 620                mutex_lock(&pcm->open_mutex);
 621        }
 622        list_for_each(list, &card->devices) {
 623                int s;
 624                dev = snd_device(list);
 625                if (dev->type != SNDRV_DEV_PCM)
 626                        continue;
 627                pcm = dev->device_data;
 628                for (s = 0; s < 2; ++s) {
 629                        struct snd_pcm_substream *substream;
 630                        substream = pcm->streams[s].substream;
 631                        if (substream && SUBSTREAM_BUSY(substream))
 632                                err = -EBUSY;
 633                }
 634        }
 635        return err;
 636}
 637
 638
 639static void usX2Y_pcms_unlock(struct snd_card *card)
 640{
 641        struct list_head *list;
 642        struct snd_device *dev;
 643        struct snd_pcm *pcm;
 644        list_for_each(list, &card->devices) {
 645                dev = snd_device(list);
 646                if (dev->type != SNDRV_DEV_PCM)
 647                        continue;
 648                pcm = dev->device_data;
 649                mutex_unlock(&pcm->open_mutex);
 650        }
 651}
 652
 653
 654static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
 655{
 656        // we need to be the first 
 657        struct snd_card *card = hw->card;
 658        int err = usX2Y_pcms_lock_check(card);
 659        if (0 == err)
 660                usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
 661        usX2Y_pcms_unlock(card);
 662        return err;
 663}
 664
 665
 666static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
 667{
 668        struct snd_card *card = hw->card;
 669        int err = usX2Y_pcms_lock_check(card);
 670        if (0 == err)
 671                usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
 672        usX2Y_pcms_unlock(card);
 673        return err;
 674}
 675
 676
 677static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
 678{
 679}
 680
 681
 682static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
 683{
 684}
 685
 686
 687static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
 688                                        struct vm_fault *vmf)
 689{
 690        unsigned long offset;
 691        void *vaddr;
 692
 693        offset = vmf->pgoff << PAGE_SHIFT;
 694        vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
 695        vmf->page = virt_to_page(vaddr);
 696        get_page(vmf->page);
 697        return 0;
 698}
 699
 700
 701static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
 702        .open = snd_usX2Y_hwdep_pcm_vm_open,
 703        .close = snd_usX2Y_hwdep_pcm_vm_close,
 704        .fault = snd_usX2Y_hwdep_pcm_vm_fault,
 705};
 706
 707
 708static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
 709{
 710        unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
 711        struct usX2Ydev *usX2Y = hw->private_data;
 712
 713        if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
 714                return -EBUSY;
 715
 716        /* if userspace tries to mmap beyond end of our buffer, fail */ 
 717        if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
 718                snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 
 719                return -EINVAL;
 720        }
 721
 722        if (!usX2Y->hwdep_pcm_shm) {
 723                return -ENODEV;
 724        }
 725        area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
 726        area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
 727        area->vm_private_data = hw->private_data;
 728        return 0;
 729}
 730
 731
 732static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
 733{
 734        struct usX2Ydev *usX2Y = hwdep->private_data;
 735        if (NULL != usX2Y->hwdep_pcm_shm)
 736                snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 737}
 738
 739
 740int usX2Y_hwdep_pcm_new(struct snd_card *card)
 741{
 742        int err;
 743        struct snd_hwdep *hw;
 744        struct snd_pcm *pcm;
 745        struct usb_device *dev = usX2Y(card)->dev;
 746        if (1 != nr_of_packs())
 747                return 0;
 748
 749        if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
 750                return err;
 751
 752        hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
 753        hw->private_data = usX2Y(card);
 754        hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
 755        hw->ops.open = snd_usX2Y_hwdep_pcm_open;
 756        hw->ops.release = snd_usX2Y_hwdep_pcm_release;
 757        hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
 758        hw->exclusive = 1;
 759        sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
 760
 761        err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
 762        if (err < 0) {
 763                return err;
 764        }
 765        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
 766        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
 767
 768        pcm->private_data = usX2Y(card)->subs;
 769        pcm->info_flags = 0;
 770
 771        sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
 772        if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
 773                                                     SNDRV_DMA_TYPE_CONTINUOUS,
 774                                                     snd_dma_continuous_data(GFP_KERNEL),
 775                                                     64*1024, 128*1024)) ||
 776            0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
 777                                                     SNDRV_DMA_TYPE_CONTINUOUS,
 778                                                     snd_dma_continuous_data(GFP_KERNEL),
 779                                                     64*1024, 128*1024))) {
 780                return err;
 781        }
 782
 783
 784        return 0;
 785}
 786
 787#else
 788
 789int usX2Y_hwdep_pcm_new(struct snd_card *card)
 790{
 791        return 0;
 792}
 793
 794#endif
 795