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        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                                        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_DONTEXPAND | VM_DONTDUMP;
 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)->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