root/sound/usb/usx2y/usx2yhwdeppcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usX2Y_usbpcm_urb_capt_retire
  2. usX2Y_iso_frames_per_buffer
  3. usX2Y_hwdep_urb_play_prepare
  4. usX2Y_usbpcm_urb_capt_iso_advance
  5. usX2Y_usbpcm_usbframe_complete
  6. i_usX2Y_usbpcm_urb_complete
  7. usX2Y_hwdep_urb_release
  8. usX2Y_usbpcm_urbs_release
  9. usX2Y_usbpcm_subs_startup_finish
  10. i_usX2Y_usbpcm_subs_startup
  11. usX2Y_usbpcm_urbs_allocate
  12. snd_usX2Y_usbpcm_hw_free
  13. usX2Y_usbpcm_subs_startup
  14. usX2Y_usbpcm_urbs_start
  15. snd_usX2Y_usbpcm_prepare
  16. snd_usX2Y_usbpcm_open
  17. snd_usX2Y_usbpcm_close
  18. usX2Y_pcms_busy_check
  19. snd_usX2Y_hwdep_pcm_open
  20. snd_usX2Y_hwdep_pcm_release
  21. snd_usX2Y_hwdep_pcm_vm_open
  22. snd_usX2Y_hwdep_pcm_vm_close
  23. snd_usX2Y_hwdep_pcm_vm_fault
  24. snd_usX2Y_hwdep_pcm_mmap
  25. snd_usX2Y_hwdep_pcm_private_free
  26. usX2Y_hwdep_pcm_new
  27. usX2Y_hwdep_pcm_new

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

/* [<][>][^][v][top][bottom][index][help] */