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 dependant 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, funcionalities should migrate to more apropriate 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 "usbusx2yaudio.c"
  55
  56#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) &&  USX2Y_NRPACKS == 1)
  57
  58#include <sound/hwdep.h>
  59
  60
  61static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
  62{
  63        struct urb      *urb = subs->completed_urb;
  64        struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
  65        int             i, lens = 0, hwptr_done = subs->hwptr_done;
  66        struct usX2Ydev *usX2Y = subs->usX2Y;
  67        if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
  68                int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
  69                if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
  70                        head = 0;
  71                usX2Y->hwdep_pcm_shm->capture_iso_start = head;
  72                snd_printdd("cap start %i\n", head);
  73        }
  74        for (i = 0; i < nr_of_packs(); i++) {
  75                if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
  76                        snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
  77                        return urb->iso_frame_desc[i].status;
  78                }
  79                lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
  80        }
  81        if ((hwptr_done += lens) >= runtime->buffer_size)
  82                hwptr_done -= runtime->buffer_size;
  83        subs->hwptr_done = hwptr_done;
  84        subs->transfer_done += lens;
  85        /* update the pointer, call callback if necessary */
  86        if (subs->transfer_done >= runtime->period_size) {
  87                subs->transfer_done -= runtime->period_size;
  88                snd_pcm_period_elapsed(subs->pcm_substream);
  89        }
  90        return 0;
  91}
  92
  93static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
  94                                              struct usX2Ydev * usX2Y)
  95{
  96        return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
  97}
  98
  99/*
 100 * prepare urb for playback data pipe
 101 *
 102 * we copy the data directly from the pcm buffer.
 103 * the current position to be copied is held in hwptr field.
 104 * since a urb can handle only a single linear buffer, if the total
 105 * transferred area overflows the buffer boundary, we cannot send
 106 * it directly from the buffer.  thus the data is once copied to
 107 * a temporary buffer and urb points to that.
 108 */
 109static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
 110                                        struct urb *urb)
 111{
 112        int count, counts, pack;
 113        struct usX2Ydev *usX2Y = subs->usX2Y;
 114        struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
 115        struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
 116
 117        if (0 > shm->playback_iso_start) {
 118                shm->playback_iso_start = shm->captured_iso_head -
 119                        usX2Y_iso_frames_per_buffer(runtime, usX2Y);
 120                if (0 > shm->playback_iso_start)
 121                        shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
 122                shm->playback_iso_head = shm->playback_iso_start;
 123        }
 124
 125        count = 0;
 126        for (pack = 0; pack < nr_of_packs(); pack++) {
 127                /* calculate the size of a packet */
 128                counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
 129                if (counts < 43 || counts > 50) {
 130                        snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
 131                        return -EPIPE;
 132                }
 133                /* set up descriptor */
 134                urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
 135                urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
 136                if (atomic_read(&subs->state) != state_RUNNING)
 137                        memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
 138                               urb->iso_frame_desc[pack].length);
 139                if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
 140                        shm->playback_iso_head = 0;
 141                count += counts;
 142        }
 143        urb->transfer_buffer_length = count * usX2Y->stride;
 144        return 0;
 145}
 146
 147
 148static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
 149                                                     struct urb *urb)
 150{
 151        int pack;
 152        for (pack = 0; pack < nr_of_packs(); ++pack) {
 153                struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
 154                if (NULL != subs) {
 155                        struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
 156                        int head = shm->captured_iso_head + 1;
 157                        if (head >= ARRAY_SIZE(shm->captured_iso))
 158                                head = 0;
 159                        shm->captured_iso[head].frame = urb->start_frame + pack;
 160                        shm->captured_iso[head].offset = desc->offset;
 161                        shm->captured_iso[head].length = desc->actual_length;
 162                        shm->captured_iso_head = head;
 163                        shm->captured_iso_frames++;
 164                }
 165                if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
 166                    desc->length >= SSS)
 167                        desc->offset -= (SSS - desc->length);
 168        }
 169}
 170
 171static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
 172                                                 struct snd_usX2Y_substream *capsubs2,
 173                                                 struct snd_usX2Y_substream *playbacksubs,
 174                                                 int frame)
 175{
 176        int err, state;
 177        struct urb *urb = playbacksubs->completed_urb;
 178
 179        state = atomic_read(&playbacksubs->state);
 180        if (NULL != urb) {
 181                if (state == state_RUNNING)
 182                        usX2Y_urb_play_retire(playbacksubs, urb);
 183                else if (state >= state_PRERUNNING)
 184                        atomic_inc(&playbacksubs->state);
 185        } else {
 186                switch (state) {
 187                case state_STARTING1:
 188                        urb = playbacksubs->urb[0];
 189                        atomic_inc(&playbacksubs->state);
 190                        break;
 191                case state_STARTING2:
 192                        urb = playbacksubs->urb[1];
 193                        atomic_inc(&playbacksubs->state);
 194                        break;
 195                }
 196        }
 197        if (urb) {
 198                if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
 199                    (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
 200                        return err;
 201                }
 202        }
 203        
 204        playbacksubs->completed_urb = NULL;
 205
 206        state = atomic_read(&capsubs->state);
 207        if (state >= state_PREPARED) {
 208                if (state == state_RUNNING) {
 209                        if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
 210                                return err;
 211                } else if (state >= state_PRERUNNING)
 212                        atomic_inc(&capsubs->state);
 213                usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
 214                if (NULL != capsubs2)
 215                        usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
 216                if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
 217                        return err;
 218                if (NULL != capsubs2)
 219                        if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
 220                                return err;
 221        }
 222        capsubs->completed_urb = NULL;
 223        if (NULL != capsubs2)
 224                capsubs2->completed_urb = NULL;
 225        return 0;
 226}
 227
 228
 229static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
 230{
 231        struct snd_usX2Y_substream *subs = urb->context;
 232        struct usX2Ydev *usX2Y = subs->usX2Y;
 233        struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
 234
 235        if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
 236                snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
 237                            usb_get_current_frame_number(usX2Y->chip.dev),
 238                            subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
 239                            urb->status, urb->start_frame);
 240                return;
 241        }
 242        if (unlikely(urb->status)) {
 243                usX2Y_error_urb_status(usX2Y, subs, urb);
 244                return;
 245        }
 246        if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
 247                subs->completed_urb = urb;
 248        else {
 249                usX2Y_error_sequence(usX2Y, subs, urb);
 250                return;
 251        }
 252
 253        capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
 254        capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 255        playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 256        if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
 257            (NULL == capsubs2 || capsubs2->completed_urb) &&
 258            (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
 259                if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
 260                        usX2Y->wait_iso_frame += nr_of_packs();
 261                else {
 262                        snd_printdd("\n");
 263                        usX2Y_clients_stop(usX2Y);
 264                }
 265        }
 266}
 267
 268
 269static void usX2Y_hwdep_urb_release(struct urb **urb)
 270{
 271        usb_kill_urb(*urb);
 272        usb_free_urb(*urb);
 273        *urb = NULL;
 274}
 275
 276/*
 277 * release a substream
 278 */
 279static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
 280{
 281        int i;
 282        snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
 283        for (i = 0; i < NRURBS; i++)
 284                usX2Y_hwdep_urb_release(subs->urb + i);
 285}
 286
 287static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
 288{
 289        usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
 290        usX2Y->prepare_subs = NULL;
 291}
 292
 293static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
 294{
 295        struct snd_usX2Y_substream *subs = urb->context;
 296        struct usX2Ydev *usX2Y = subs->usX2Y;
 297        struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
 298        if (NULL != prepare_subs &&
 299            urb->start_frame == prepare_subs->urb[0]->start_frame) {
 300                atomic_inc(&prepare_subs->state);
 301                if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
 302                        struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 303                        if (cap_subs2 != NULL)
 304                                atomic_inc(&cap_subs2->state);
 305                }
 306                usX2Y_usbpcm_subs_startup_finish(usX2Y);
 307                wake_up(&usX2Y->prepare_wait_queue);
 308        }
 309
 310        i_usX2Y_usbpcm_urb_complete(urb);
 311}
 312
 313/*
 314 * initialize a substream's urbs
 315 */
 316static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
 317{
 318        int i;
 319        unsigned int pipe;
 320        int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 321        struct usb_device *dev = subs->usX2Y->chip.dev;
 322
 323        pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
 324                        usb_rcvisocpipe(dev, subs->endpoint);
 325        subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
 326        if (!subs->maxpacksize)
 327                return -EINVAL;
 328
 329        /* allocate and initialize data urbs */
 330        for (i = 0; i < NRURBS; i++) {
 331                struct urb **purb = subs->urb + i;
 332                if (*purb) {
 333                        usb_kill_urb(*purb);
 334                        continue;
 335                }
 336                *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
 337                if (NULL == *purb) {
 338                        usX2Y_usbpcm_urbs_release(subs);
 339                        return -ENOMEM;
 340                }
 341                (*purb)->transfer_buffer = is_playback ?
 342                        subs->usX2Y->hwdep_pcm_shm->playback : (
 343                                subs->endpoint == 0x8 ?
 344                                subs->usX2Y->hwdep_pcm_shm->capture0x8 :
 345                                subs->usX2Y->hwdep_pcm_shm->capture0xA);
 346
 347                (*purb)->dev = dev;
 348                (*purb)->pipe = pipe;
 349                (*purb)->number_of_packets = nr_of_packs();
 350                (*purb)->context = subs;
 351                (*purb)->interval = 1;
 352                (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
 353        }
 354        return 0;
 355}
 356
 357/*
 358 * free the buffer
 359 */
 360static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
 361{
 362        struct snd_pcm_runtime *runtime = substream->runtime;
 363        struct snd_usX2Y_substream *subs = runtime->private_data,
 364                *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
 365        mutex_lock(&subs->usX2Y->prepare_mutex);
 366        snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
 367
 368        if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
 369                struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
 370                atomic_set(&subs->state, state_STOPPED);
 371                usX2Y_usbpcm_urbs_release(subs);
 372                if (!cap_subs->pcm_substream ||
 373                    !cap_subs->pcm_substream->runtime ||
 374                    !cap_subs->pcm_substream->runtime->status ||
 375                    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
 376                        atomic_set(&cap_subs->state, state_STOPPED);
 377                        if (NULL != cap_subs2)
 378                                atomic_set(&cap_subs2->state, state_STOPPED);
 379                        usX2Y_usbpcm_urbs_release(cap_subs);
 380                        if (NULL != cap_subs2)
 381                                usX2Y_usbpcm_urbs_release(cap_subs2);
 382                }
 383        } else {
 384                struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
 385                if (atomic_read(&playback_subs->state) < state_PREPARED) {
 386                        atomic_set(&subs->state, state_STOPPED);
 387                        if (NULL != cap_subs2)
 388                                atomic_set(&cap_subs2->state, state_STOPPED);
 389                        usX2Y_usbpcm_urbs_release(subs);
 390                        if (NULL != cap_subs2)
 391                                usX2Y_usbpcm_urbs_release(cap_subs2);
 392                }
 393        }
 394        mutex_unlock(&subs->usX2Y->prepare_mutex);
 395        return snd_pcm_lib_free_pages(substream);
 396}
 397
 398static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
 399{
 400        struct usX2Ydev * usX2Y = subs->usX2Y;
 401        usX2Y->prepare_subs = subs;
 402        subs->urb[0]->start_frame = -1;
 403        smp_wmb();      // Make sure above modifications are seen by i_usX2Y_subs_startup()
 404        usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
 405}
 406
 407static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
 408{
 409        int     p, u, err,
 410                stream = subs->pcm_substream->stream;
 411        struct usX2Ydev *usX2Y = subs->usX2Y;
 412
 413        if (SNDRV_PCM_STREAM_CAPTURE == stream) {
 414                usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
 415                usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
 416        }
 417
 418        for (p = 0; 3 >= (stream + p); p += 2) {
 419                struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
 420                if (subs != NULL) {
 421                        if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
 422                                return err;
 423                        subs->completed_urb = NULL;
 424                }
 425        }
 426
 427        for (p = 0; p < 4; p++) {
 428                struct snd_usX2Y_substream *subs = usX2Y->subs[p];
 429                if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
 430                        goto start;
 431        }
 432
 433 start:
 434        usX2Y_usbpcm_subs_startup(subs);
 435        for (u = 0; u < NRURBS; u++) {
 436                for (p = 0; 3 >= (stream + p); p += 2) {
 437                        struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
 438                        if (subs != NULL) {
 439                                struct urb *urb = subs->urb[u];
 440                                if (usb_pipein(urb->pipe)) {
 441                                        unsigned long pack;
 442                                        if (0 == u)
 443                                                atomic_set(&subs->state, state_STARTING3);
 444                                        urb->dev = usX2Y->chip.dev;
 445                                        urb->transfer_flags = URB_ISO_ASAP;
 446                                        for (pack = 0; pack < nr_of_packs(); pack++) {
 447                                                urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
 448                                                urb->iso_frame_desc[pack].length = subs->maxpacksize;
 449                                        }
 450                                        urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); 
 451                                        if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
 452                                                snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
 453                                                err = -EPIPE;
 454                                                goto cleanup;
 455                                        }  else {
 456                                                snd_printdd("%i\n", urb->start_frame);
 457                                                if (u == 0)
 458                                                        usX2Y->wait_iso_frame = urb->start_frame;
 459                                        }
 460                                        urb->transfer_flags = 0;
 461                                } else {
 462                                        atomic_set(&subs->state, state_STARTING1);
 463                                        break;
 464                                }                       
 465                        }
 466                }
 467        }
 468        err = 0;
 469        wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
 470        if (atomic_read(&subs->state) != state_PREPARED)
 471                err = -EPIPE;
 472                
 473 cleanup:
 474        if (err) {
 475                usX2Y_subs_startup_finish(usX2Y);       // Call it now
 476                usX2Y_clients_stop(usX2Y);              // something is completely wroong > stop evrything                      
 477        }
 478        return err;
 479}
 480
 481/*
 482 * prepare callback
 483 *
 484 * set format and initialize urbs
 485 */
 486static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
 487{
 488        struct snd_pcm_runtime *runtime = substream->runtime;
 489        struct snd_usX2Y_substream *subs = runtime->private_data;
 490        struct usX2Ydev *usX2Y = subs->usX2Y;
 491        struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
 492        int err = 0;
 493        snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
 494
 495        if (NULL == usX2Y->hwdep_pcm_shm) {
 496                if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
 497                        return -ENOMEM;
 498                memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 499        }
 500
 501        mutex_lock(&usX2Y->prepare_mutex);
 502        usX2Y_subs_prepare(subs);
 503// Start hardware streams
 504// SyncStream first....
 505        if (atomic_read(&capsubs->state) < state_PREPARED) {
 506                if (usX2Y->format != runtime->format)
 507                        if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
 508                                goto up_prepare_mutex;
 509                if (usX2Y->rate != runtime->rate)
 510                        if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
 511                                goto up_prepare_mutex;
 512                snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
 513                            "self" : "playpipe");
 514                if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
 515                        goto up_prepare_mutex;
 516        }
 517
 518        if (subs != capsubs) {
 519                usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
 520                if (atomic_read(&subs->state) < state_PREPARED) {
 521                        while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
 522                               usX2Y->hwdep_pcm_shm->captured_iso_frames) {
 523                                snd_printdd("Wait: iso_frames_per_buffer=%i,"
 524                                            "captured_iso_frames=%i\n",
 525                                            usX2Y_iso_frames_per_buffer(runtime, usX2Y),
 526                                            usX2Y->hwdep_pcm_shm->captured_iso_frames);
 527                                if (msleep_interruptible(10)) {
 528                                        err = -ERESTARTSYS;
 529                                        goto up_prepare_mutex;
 530                                }
 531                        } 
 532                        if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
 533                                goto up_prepare_mutex;
 534                }
 535                snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
 536                            usX2Y_iso_frames_per_buffer(runtime, usX2Y),
 537                            usX2Y->hwdep_pcm_shm->captured_iso_frames);
 538        } else
 539                usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
 540
 541 up_prepare_mutex:
 542        mutex_unlock(&usX2Y->prepare_mutex);
 543        return err;
 544}
 545
 546static struct snd_pcm_hardware snd_usX2Y_4c =
 547{
 548        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 549                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 550                                 SNDRV_PCM_INFO_MMAP_VALID),
 551        .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
 552        .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 553        .rate_min =                44100,
 554        .rate_max =                48000,
 555        .channels_min =            2,
 556        .channels_max =            4,
 557        .buffer_bytes_max =     (2*128*1024),
 558        .period_bytes_min =     64,
 559        .period_bytes_max =     (128*1024),
 560        .periods_min =          2,
 561        .periods_max =          1024,
 562        .fifo_size =              0
 563};
 564
 565
 566
 567static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
 568{
 569        struct snd_usX2Y_substream      *subs = ((struct snd_usX2Y_substream **)
 570                                         snd_pcm_substream_chip(substream))[substream->stream];
 571        struct snd_pcm_runtime  *runtime = substream->runtime;
 572
 573        if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
 574                return -EBUSY;
 575
 576        runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
 577                (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
 578        runtime->private_data = subs;
 579        subs->pcm_substream = substream;
 580        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
 581        return 0;
 582}
 583
 584
 585static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
 586{
 587        struct snd_pcm_runtime *runtime = substream->runtime;
 588        struct snd_usX2Y_substream *subs = runtime->private_data;
 589
 590        subs->pcm_substream = NULL;
 591        return 0;
 592}
 593
 594
 595static struct snd_pcm_ops snd_usX2Y_usbpcm_ops = 
 596{
 597        .open =         snd_usX2Y_usbpcm_open,
 598        .close =        snd_usX2Y_usbpcm_close,
 599        .ioctl =        snd_pcm_lib_ioctl,
 600        .hw_params =    snd_usX2Y_pcm_hw_params,
 601        .hw_free =      snd_usX2Y_usbpcm_hw_free,
 602        .prepare =      snd_usX2Y_usbpcm_prepare,
 603        .trigger =      snd_usX2Y_pcm_trigger,
 604        .pointer =      snd_usX2Y_pcm_pointer,
 605};
 606
 607
 608static int usX2Y_pcms_lock_check(struct snd_card *card)
 609{
 610        struct list_head *list;
 611        struct snd_device *dev;
 612        struct snd_pcm *pcm;
 613        int err = 0;
 614        list_for_each(list, &card->devices) {
 615                dev = snd_device(list);
 616                if (dev->type != SNDRV_DEV_PCM)
 617                        continue;
 618                pcm = dev->device_data;
 619                mutex_lock(&pcm->open_mutex);
 620        }
 621        list_for_each(list, &card->devices) {
 622                int s;
 623                dev = snd_device(list);
 624                if (dev->type != SNDRV_DEV_PCM)
 625                        continue;
 626                pcm = dev->device_data;
 627                for (s = 0; s < 2; ++s) {
 628                        struct snd_pcm_substream *substream;
 629                        substream = pcm->streams[s].substream;
 630                        if (substream && SUBSTREAM_BUSY(substream))
 631                                err = -EBUSY;
 632                }
 633        }
 634        return err;
 635}
 636
 637
 638static void usX2Y_pcms_unlock(struct snd_card *card)
 639{
 640        struct list_head *list;
 641        struct snd_device *dev;
 642        struct snd_pcm *pcm;
 643        list_for_each(list, &card->devices) {
 644                dev = snd_device(list);
 645                if (dev->type != SNDRV_DEV_PCM)
 646                        continue;
 647                pcm = dev->device_data;
 648                mutex_unlock(&pcm->open_mutex);
 649        }
 650}
 651
 652
 653static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
 654{
 655        // we need to be the first 
 656        struct snd_card *card = hw->card;
 657        int err = usX2Y_pcms_lock_check(card);
 658        if (0 == err)
 659                usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
 660        usX2Y_pcms_unlock(card);
 661        return err;
 662}
 663
 664
 665static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
 666{
 667        struct snd_card *card = hw->card;
 668        int err = usX2Y_pcms_lock_check(card);
 669        if (0 == err)
 670                usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
 671        usX2Y_pcms_unlock(card);
 672        return err;
 673}
 674
 675
 676static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
 677{
 678}
 679
 680
 681static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
 682{
 683}
 684
 685
 686static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
 687                                        struct vm_fault *vmf)
 688{
 689        unsigned long offset;
 690        void *vaddr;
 691
 692        offset = vmf->pgoff << PAGE_SHIFT;
 693        vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
 694        vmf->page = virt_to_page(vaddr);
 695        get_page(vmf->page);
 696        return 0;
 697}
 698
 699
 700static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
 701        .open = snd_usX2Y_hwdep_pcm_vm_open,
 702        .close = snd_usX2Y_hwdep_pcm_vm_close,
 703        .fault = snd_usX2Y_hwdep_pcm_vm_fault,
 704};
 705
 706
 707static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
 708{
 709        unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
 710        struct usX2Ydev *usX2Y = hw->private_data;
 711
 712        if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
 713                return -EBUSY;
 714
 715        /* if userspace tries to mmap beyond end of our buffer, fail */ 
 716        if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
 717                snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 
 718                return -EINVAL;
 719        }
 720
 721        if (!usX2Y->hwdep_pcm_shm) {
 722                return -ENODEV;
 723        }
 724        area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
 725        area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
 726        area->vm_private_data = hw->private_data;
 727        return 0;
 728}
 729
 730
 731static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
 732{
 733        struct usX2Ydev *usX2Y = hwdep->private_data;
 734        if (NULL != usX2Y->hwdep_pcm_shm)
 735                snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 736}
 737
 738
 739int usX2Y_hwdep_pcm_new(struct snd_card *card)
 740{
 741        int err;
 742        struct snd_hwdep *hw;
 743        struct snd_pcm *pcm;
 744        struct usb_device *dev = usX2Y(card)->chip.dev;
 745        if (1 != nr_of_packs())
 746                return 0;
 747
 748        if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
 749                return err;
 750
 751        hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
 752        hw->private_data = usX2Y(card);
 753        hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
 754        hw->ops.open = snd_usX2Y_hwdep_pcm_open;
 755        hw->ops.release = snd_usX2Y_hwdep_pcm_release;
 756        hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
 757        hw->exclusive = 1;
 758        sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
 759
 760        err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
 761        if (err < 0) {
 762                return err;
 763        }
 764        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
 765        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
 766
 767        pcm->private_data = usX2Y(card)->subs;
 768        pcm->info_flags = 0;
 769
 770        sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
 771        if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
 772                                                     SNDRV_DMA_TYPE_CONTINUOUS,
 773                                                     snd_dma_continuous_data(GFP_KERNEL),
 774                                                     64*1024, 128*1024)) ||
 775            0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
 776                                                     SNDRV_DMA_TYPE_CONTINUOUS,
 777                                                     snd_dma_continuous_data(GFP_KERNEL),
 778                                                     64*1024, 128*1024))) {
 779                return err;
 780        }
 781
 782
 783        return 0;
 784}
 785
 786#else
 787
 788int usX2Y_hwdep_pcm_new(struct snd_card *card)
 789{
 790        return 0;
 791}
 792
 793#endif
 794