Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  */
0004 
0005 /* USX2Y "rawusb" aka hwdep_pcm implementation
0006 
0007  Its usb's unableness to atomically handle power of 2 period sized data chuncs
0008  at standard samplerates,
0009  what led to this part of the usx2y module:
0010  It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
0011  The pair uses a hardware dependent alsa-device for mmaped pcm transport.
0012  Advantage achieved:
0013          The usb_hc moves pcm data from/into memory via DMA.
0014          That memory is mmaped by jack's usx2y driver.
0015          Jack's usx2y driver is the first/last to read/write pcm data.
0016          Read/write is a combination of power of 2 period shaping and
0017          float/int conversation.
0018          Compared to mainline alsa/jack we leave out power of 2 period shaping inside
0019          snd-usb-usx2y which needs memcpy() and additional buffers.
0020          As a side effect possible unwanted pcm-data coruption resulting of
0021          standard alsa's snd-usb-usx2y period shaping scheme falls away.
0022          Result is sane jack operation at buffering schemes down to 128frames,
0023          2 periods.
0024          plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
0025          cost of easier triggered i.e. aeolus xruns (128 or 256frames,
0026          2periods works but is useless cause of crackling).
0027 
0028  This is a first "proof of concept" implementation.
0029  Later, functionalities should migrate to more appropriate places:
0030  Userland:
0031  - The jackd could mmap its float-pcm buffers directly from alsa-lib.
0032  - alsa-lib could provide power of 2 period sized shaping combined with int/float
0033    conversation.
0034    Currently the usx2y jack driver provides above 2 services.
0035  Kernel:
0036  - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
0037    devices can use it.
0038    Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
0039 */
0040 
0041 #include <linux/delay.h>
0042 #include <linux/gfp.h>
0043 #include "usbusx2yaudio.c"
0044 
0045 #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
0046 
0047 #include <sound/hwdep.h>
0048 
0049 static int usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream *subs)
0050 {
0051     struct urb  *urb = subs->completed_urb;
0052     struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
0053     int     i, lens = 0, hwptr_done = subs->hwptr_done;
0054     struct usx2ydev *usx2y = subs->usx2y;
0055     int head;
0056 
0057     if (usx2y->hwdep_pcm_shm->capture_iso_start < 0) { //FIXME
0058         head = usx2y->hwdep_pcm_shm->captured_iso_head + 1;
0059         if (head >= ARRAY_SIZE(usx2y->hwdep_pcm_shm->captured_iso))
0060             head = 0;
0061         usx2y->hwdep_pcm_shm->capture_iso_start = head;
0062         snd_printdd("cap start %i\n", head);
0063     }
0064     for (i = 0; i < nr_of_packs(); i++) {
0065         if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
0066             snd_printk(KERN_ERR
0067                    "active frame status %i. Most probably some hardware problem.\n",
0068                    urb->iso_frame_desc[i].status);
0069             return urb->iso_frame_desc[i].status;
0070         }
0071         lens += urb->iso_frame_desc[i].actual_length / usx2y->stride;
0072     }
0073     hwptr_done += lens;
0074     if (hwptr_done >= runtime->buffer_size)
0075         hwptr_done -= runtime->buffer_size;
0076     subs->hwptr_done = hwptr_done;
0077     subs->transfer_done += lens;
0078     /* update the pointer, call callback if necessary */
0079     if (subs->transfer_done >= runtime->period_size) {
0080         subs->transfer_done -= runtime->period_size;
0081         snd_pcm_period_elapsed(subs->pcm_substream);
0082     }
0083     return 0;
0084 }
0085 
0086 static int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
0087                           struct usx2ydev *usx2y)
0088 {
0089     return (runtime->buffer_size * 1000) / usx2y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
0090 }
0091 
0092 /*
0093  * prepare urb for playback data pipe
0094  *
0095  * we copy the data directly from the pcm buffer.
0096  * the current position to be copied is held in hwptr field.
0097  * since a urb can handle only a single linear buffer, if the total
0098  * transferred area overflows the buffer boundary, we cannot send
0099  * it directly from the buffer.  thus the data is once copied to
0100  * a temporary buffer and urb points to that.
0101  */
0102 static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs,
0103                     struct urb *urb)
0104 {
0105     int count, counts, pack;
0106     struct usx2ydev *usx2y = subs->usx2y;
0107     struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm;
0108     struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
0109 
0110     if (shm->playback_iso_start < 0) {
0111         shm->playback_iso_start = shm->captured_iso_head -
0112             usx2y_iso_frames_per_buffer(runtime, usx2y);
0113         if (shm->playback_iso_start < 0)
0114             shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
0115         shm->playback_iso_head = shm->playback_iso_start;
0116     }
0117 
0118     count = 0;
0119     for (pack = 0; pack < nr_of_packs(); pack++) {
0120         /* calculate the size of a packet */
0121         counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride;
0122         if (counts < 43 || counts > 50) {
0123             snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
0124             return -EPIPE;
0125         }
0126         /* set up descriptor */
0127         urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
0128         urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
0129         if (atomic_read(&subs->state) != STATE_RUNNING)
0130             memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
0131                    urb->iso_frame_desc[pack].length);
0132         if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
0133             shm->playback_iso_head = 0;
0134         count += counts;
0135     }
0136     urb->transfer_buffer_length = count * usx2y->stride;
0137     return 0;
0138 }
0139 
0140 static void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs,
0141                           struct urb *urb)
0142 {
0143     struct usb_iso_packet_descriptor *desc;
0144     struct snd_usx2y_hwdep_pcm_shm *shm;
0145     int pack, head;
0146 
0147     for (pack = 0; pack < nr_of_packs(); ++pack) {
0148         desc = urb->iso_frame_desc + pack;
0149         if (subs) {
0150             shm = subs->usx2y->hwdep_pcm_shm;
0151             head = shm->captured_iso_head + 1;
0152             if (head >= ARRAY_SIZE(shm->captured_iso))
0153                 head = 0;
0154             shm->captured_iso[head].frame = urb->start_frame + pack;
0155             shm->captured_iso[head].offset = desc->offset;
0156             shm->captured_iso[head].length = desc->actual_length;
0157             shm->captured_iso_head = head;
0158             shm->captured_iso_frames++;
0159         }
0160         desc->offset += desc->length * NRURBS * nr_of_packs();
0161         if (desc->offset + desc->length >= SSS)
0162             desc->offset -= (SSS - desc->length);
0163     }
0164 }
0165 
0166 static int usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream *capsubs,
0167                       struct snd_usx2y_substream *capsubs2,
0168                       struct snd_usx2y_substream *playbacksubs,
0169                       int frame)
0170 {
0171     int err, state;
0172     struct urb *urb = playbacksubs->completed_urb;
0173 
0174     state = atomic_read(&playbacksubs->state);
0175     if (urb) {
0176         if (state == STATE_RUNNING)
0177             usx2y_urb_play_retire(playbacksubs, urb);
0178         else if (state >= STATE_PRERUNNING)
0179             atomic_inc(&playbacksubs->state);
0180     } else {
0181         switch (state) {
0182         case STATE_STARTING1:
0183             urb = playbacksubs->urb[0];
0184             atomic_inc(&playbacksubs->state);
0185             break;
0186         case STATE_STARTING2:
0187             urb = playbacksubs->urb[1];
0188             atomic_inc(&playbacksubs->state);
0189             break;
0190         }
0191     }
0192     if (urb) {
0193         err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
0194         if (err)
0195             return err;
0196         err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
0197         if (err)
0198             return err;
0199     }
0200 
0201     playbacksubs->completed_urb = NULL;
0202 
0203     state = atomic_read(&capsubs->state);
0204     if (state >= STATE_PREPARED) {
0205         if (state == STATE_RUNNING) {
0206             err = usx2y_usbpcm_urb_capt_retire(capsubs);
0207             if (err)
0208                 return err;
0209         } else if (state >= STATE_PRERUNNING) {
0210             atomic_inc(&capsubs->state);
0211         }
0212         usx2y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
0213         if (capsubs2)
0214             usx2y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
0215         err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame);
0216         if (err)
0217             return err;
0218         if (capsubs2) {
0219             err = usx2y_urb_submit(capsubs2, capsubs2->completed_urb, frame);
0220             if (err)
0221                 return err;
0222         }
0223     }
0224     capsubs->completed_urb = NULL;
0225     if (capsubs2)
0226         capsubs2->completed_urb = NULL;
0227     return 0;
0228 }
0229 
0230 static void i_usx2y_usbpcm_urb_complete(struct urb *urb)
0231 {
0232     struct snd_usx2y_substream *subs = urb->context;
0233     struct usx2ydev *usx2y = subs->usx2y;
0234     struct snd_usx2y_substream *capsubs, *capsubs2, *playbacksubs;
0235 
0236     if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
0237         snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
0238                 usb_get_current_frame_number(usx2y->dev),
0239                 subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
0240                 urb->status, urb->start_frame);
0241         return;
0242     }
0243     if (unlikely(urb->status)) {
0244         usx2y_error_urb_status(usx2y, subs, urb);
0245         return;
0246     }
0247 
0248     subs->completed_urb = urb;
0249     capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
0250     capsubs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
0251     playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
0252     if (capsubs->completed_urb && atomic_read(&capsubs->state) >= STATE_PREPARED &&
0253         (!capsubs2 || capsubs2->completed_urb) &&
0254         (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
0255         if (!usx2y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
0256             usx2y->wait_iso_frame += nr_of_packs();
0257         } else {
0258             snd_printdd("\n");
0259             usx2y_clients_stop(usx2y);
0260         }
0261     }
0262 }
0263 
0264 static void usx2y_hwdep_urb_release(struct urb **urb)
0265 {
0266     usb_kill_urb(*urb);
0267     usb_free_urb(*urb);
0268     *urb = NULL;
0269 }
0270 
0271 /*
0272  * release a substream
0273  */
0274 static void usx2y_usbpcm_urbs_release(struct snd_usx2y_substream *subs)
0275 {
0276     int i;
0277 
0278     snd_printdd("snd_usx2y_urbs_release() %i\n", subs->endpoint);
0279     for (i = 0; i < NRURBS; i++)
0280         usx2y_hwdep_urb_release(subs->urb + i);
0281 }
0282 
0283 static void usx2y_usbpcm_subs_startup_finish(struct usx2ydev *usx2y)
0284 {
0285     usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_urb_complete);
0286     usx2y->prepare_subs = NULL;
0287 }
0288 
0289 static void i_usx2y_usbpcm_subs_startup(struct urb *urb)
0290 {
0291     struct snd_usx2y_substream *subs = urb->context;
0292     struct usx2ydev *usx2y = subs->usx2y;
0293     struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
0294     struct snd_usx2y_substream *cap_subs2;
0295 
0296     if (prepare_subs &&
0297         urb->start_frame == prepare_subs->urb[0]->start_frame) {
0298         atomic_inc(&prepare_subs->state);
0299         if (prepare_subs == usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
0300             cap_subs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
0301             if (cap_subs2)
0302                 atomic_inc(&cap_subs2->state);
0303         }
0304         usx2y_usbpcm_subs_startup_finish(usx2y);
0305         wake_up(&usx2y->prepare_wait_queue);
0306     }
0307 
0308     i_usx2y_usbpcm_urb_complete(urb);
0309 }
0310 
0311 /*
0312  * initialize a substream's urbs
0313  */
0314 static int usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream *subs)
0315 {
0316     int i;
0317     unsigned int pipe;
0318     int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
0319     struct usb_device *dev = subs->usx2y->dev;
0320     struct urb **purb;
0321 
0322     pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
0323             usb_rcvisocpipe(dev, subs->endpoint);
0324     subs->maxpacksize = usb_maxpacket(dev, pipe);
0325     if (!subs->maxpacksize)
0326         return -EINVAL;
0327 
0328     /* allocate and initialize data urbs */
0329     for (i = 0; i < NRURBS; i++) {
0330         purb = subs->urb + i;
0331         if (*purb) {
0332             usb_kill_urb(*purb);
0333             continue;
0334         }
0335         *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
0336         if (!*purb) {
0337             usx2y_usbpcm_urbs_release(subs);
0338             return -ENOMEM;
0339         }
0340         (*purb)->transfer_buffer = is_playback ?
0341             subs->usx2y->hwdep_pcm_shm->playback : (
0342                 subs->endpoint == 0x8 ?
0343                 subs->usx2y->hwdep_pcm_shm->capture0x8 :
0344                 subs->usx2y->hwdep_pcm_shm->capture0xA);
0345 
0346         (*purb)->dev = dev;
0347         (*purb)->pipe = pipe;
0348         (*purb)->number_of_packets = nr_of_packs();
0349         (*purb)->context = subs;
0350         (*purb)->interval = 1;
0351         (*purb)->complete = i_usx2y_usbpcm_subs_startup;
0352     }
0353     return 0;
0354 }
0355 
0356 /*
0357  * free the buffer
0358  */
0359 static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream)
0360 {
0361     struct snd_pcm_runtime *runtime = substream->runtime;
0362     struct snd_usx2y_substream *subs = runtime->private_data;
0363     struct snd_usx2y_substream *cap_subs;
0364     struct snd_usx2y_substream *playback_subs;
0365     struct snd_usx2y_substream *cap_subs2;
0366 
0367     mutex_lock(&subs->usx2y->pcm_mutex);
0368     snd_printdd("%s(%p)\n", __func__, substream);
0369 
0370     cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
0371     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0372         cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
0373         atomic_set(&subs->state, STATE_STOPPED);
0374         usx2y_usbpcm_urbs_release(subs);
0375         if (!cap_subs->pcm_substream ||
0376             !cap_subs->pcm_substream->runtime ||
0377             !cap_subs->pcm_substream->runtime->status ||
0378             cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
0379             atomic_set(&cap_subs->state, STATE_STOPPED);
0380             if (cap_subs2)
0381                 atomic_set(&cap_subs2->state, STATE_STOPPED);
0382             usx2y_usbpcm_urbs_release(cap_subs);
0383             if (cap_subs2)
0384                 usx2y_usbpcm_urbs_release(cap_subs2);
0385         }
0386     } else {
0387         playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
0388         if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
0389             atomic_set(&subs->state, STATE_STOPPED);
0390             if (cap_subs2)
0391                 atomic_set(&cap_subs2->state, STATE_STOPPED);
0392             usx2y_usbpcm_urbs_release(subs);
0393             if (cap_subs2)
0394                 usx2y_usbpcm_urbs_release(cap_subs2);
0395         }
0396     }
0397     mutex_unlock(&subs->usx2y->pcm_mutex);
0398     return 0;
0399 }
0400 
0401 static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs)
0402 {
0403     struct usx2ydev *usx2y = subs->usx2y;
0404 
0405     usx2y->prepare_subs = subs;
0406     subs->urb[0]->start_frame = -1;
0407     smp_wmb();  // Make sure above modifications are seen by i_usx2y_subs_startup()
0408     usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup);
0409 }
0410 
0411 static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs)
0412 {
0413     int p, u, err, stream = subs->pcm_substream->stream;
0414     struct usx2ydev *usx2y = subs->usx2y;
0415     struct urb *urb;
0416     unsigned long pack;
0417 
0418     if (stream == SNDRV_PCM_STREAM_CAPTURE) {
0419         usx2y->hwdep_pcm_shm->captured_iso_head = -1;
0420         usx2y->hwdep_pcm_shm->captured_iso_frames = 0;
0421     }
0422 
0423     for (p = 0; 3 >= (stream + p); p += 2) {
0424         struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
0425         if (subs) {
0426             err = usx2y_usbpcm_urbs_allocate(subs);
0427             if (err < 0)
0428                 return err;
0429             subs->completed_urb = NULL;
0430         }
0431     }
0432 
0433     for (p = 0; p < 4; p++) {
0434         struct snd_usx2y_substream *subs = usx2y->subs[p];
0435 
0436         if (subs && atomic_read(&subs->state) >= STATE_PREPARED)
0437             goto start;
0438     }
0439 
0440  start:
0441     usx2y_usbpcm_subs_startup(subs);
0442     for (u = 0; u < NRURBS; u++) {
0443         for (p = 0; 3 >= (stream + p); p += 2) {
0444             struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
0445 
0446             if (!subs)
0447                 continue;
0448             urb = subs->urb[u];
0449             if (usb_pipein(urb->pipe)) {
0450                 if (!u)
0451                     atomic_set(&subs->state, STATE_STARTING3);
0452                 urb->dev = usx2y->dev;
0453                 for (pack = 0; pack < nr_of_packs(); pack++) {
0454                     urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
0455                     urb->iso_frame_desc[pack].length = subs->maxpacksize;
0456                 }
0457                 urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
0458                 err = usb_submit_urb(urb, GFP_KERNEL);
0459                 if (err < 0) {
0460                     snd_printk(KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
0461                     err = -EPIPE;
0462                     goto cleanup;
0463                 }  else {
0464                     snd_printdd("%i\n", urb->start_frame);
0465                     if (!u)
0466                         usx2y->wait_iso_frame = urb->start_frame;
0467                 }
0468                 urb->transfer_flags = 0;
0469             } else {
0470                 atomic_set(&subs->state, STATE_STARTING1);
0471                 break;
0472             }
0473         }
0474     }
0475     err = 0;
0476     wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs);
0477     if (atomic_read(&subs->state) != STATE_PREPARED)
0478         err = -EPIPE;
0479 
0480  cleanup:
0481     if (err) {
0482         usx2y_subs_startup_finish(usx2y);   // Call it now
0483         usx2y_clients_stop(usx2y);  // something is completely wrong > stop everything
0484     }
0485     return err;
0486 }
0487 
0488 #define USX2Y_HWDEP_PCM_PAGES   \
0489     PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm))
0490 
0491 /*
0492  * prepare callback
0493  *
0494  * set format and initialize urbs
0495  */
0496 static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream)
0497 {
0498     struct snd_pcm_runtime *runtime = substream->runtime;
0499     struct snd_usx2y_substream *subs = runtime->private_data;
0500     struct usx2ydev *usx2y = subs->usx2y;
0501     struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
0502     int err = 0;
0503 
0504     snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
0505 
0506     mutex_lock(&usx2y->pcm_mutex);
0507 
0508     if (!usx2y->hwdep_pcm_shm) {
0509         usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES,
0510                              GFP_KERNEL);
0511         if (!usx2y->hwdep_pcm_shm) {
0512             err = -ENOMEM;
0513             goto up_prepare_mutex;
0514         }
0515         memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES);
0516     }
0517 
0518     usx2y_subs_prepare(subs);
0519     // Start hardware streams
0520     // SyncStream first....
0521     if (atomic_read(&capsubs->state) < STATE_PREPARED) {
0522         if (usx2y->format != runtime->format) {
0523             err = usx2y_format_set(usx2y, runtime->format);
0524             if (err < 0)
0525                 goto up_prepare_mutex;
0526         }
0527         if (usx2y->rate != runtime->rate) {
0528             err = usx2y_rate_set(usx2y, runtime->rate);
0529             if (err < 0)
0530                 goto up_prepare_mutex;
0531         }
0532         snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
0533                 "self" : "playpipe");
0534         err = usx2y_usbpcm_urbs_start(capsubs);
0535         if (err < 0)
0536             goto up_prepare_mutex;
0537     }
0538 
0539     if (subs != capsubs) {
0540         usx2y->hwdep_pcm_shm->playback_iso_start = -1;
0541         if (atomic_read(&subs->state) < STATE_PREPARED) {
0542             while (usx2y_iso_frames_per_buffer(runtime, usx2y) >
0543                    usx2y->hwdep_pcm_shm->captured_iso_frames) {
0544                 snd_printdd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
0545                         usx2y_iso_frames_per_buffer(runtime, usx2y),
0546                         usx2y->hwdep_pcm_shm->captured_iso_frames);
0547                 if (msleep_interruptible(10)) {
0548                     err = -ERESTARTSYS;
0549                     goto up_prepare_mutex;
0550                 }
0551             }
0552             err = usx2y_usbpcm_urbs_start(subs);
0553             if (err < 0)
0554                 goto up_prepare_mutex;
0555         }
0556         snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
0557                 usx2y_iso_frames_per_buffer(runtime, usx2y),
0558                 usx2y->hwdep_pcm_shm->captured_iso_frames);
0559     } else {
0560         usx2y->hwdep_pcm_shm->capture_iso_start = -1;
0561     }
0562 
0563  up_prepare_mutex:
0564     mutex_unlock(&usx2y->pcm_mutex);
0565     return err;
0566 }
0567 
0568 static const struct snd_pcm_hardware snd_usx2y_4c = {
0569     .info =         (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
0570                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
0571                  SNDRV_PCM_INFO_MMAP_VALID),
0572     .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
0573     .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
0574     .rate_min =                44100,
0575     .rate_max =                48000,
0576     .channels_min =            2,
0577     .channels_max =            4,
0578     .buffer_bytes_max = (2*128*1024),
0579     .period_bytes_min = 64,
0580     .period_bytes_max = (128*1024),
0581     .periods_min =      2,
0582     .periods_max =      1024,
0583     .fifo_size =              0
0584 };
0585 
0586 static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream)
0587 {
0588     struct snd_usx2y_substream  *subs =
0589         ((struct snd_usx2y_substream **)
0590          snd_pcm_substream_chip(substream))[substream->stream];
0591     struct snd_pcm_runtime  *runtime = substream->runtime;
0592 
0593     if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
0594         return -EBUSY;
0595 
0596     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0597         runtime->hw = snd_usx2y_2c;
0598     else
0599         runtime->hw = (subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c);
0600     runtime->private_data = subs;
0601     subs->pcm_substream = substream;
0602     snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
0603     return 0;
0604 }
0605 
0606 static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream)
0607 {
0608     struct snd_pcm_runtime *runtime = substream->runtime;
0609     struct snd_usx2y_substream *subs = runtime->private_data;
0610 
0611     subs->pcm_substream = NULL;
0612     return 0;
0613 }
0614 
0615 static const struct snd_pcm_ops snd_usx2y_usbpcm_ops = {
0616     .open =     snd_usx2y_usbpcm_open,
0617     .close =    snd_usx2y_usbpcm_close,
0618     .hw_params =    snd_usx2y_pcm_hw_params,
0619     .hw_free =  snd_usx2y_usbpcm_hw_free,
0620     .prepare =  snd_usx2y_usbpcm_prepare,
0621     .trigger =  snd_usx2y_pcm_trigger,
0622     .pointer =  snd_usx2y_pcm_pointer,
0623 };
0624 
0625 static int usx2y_pcms_busy_check(struct snd_card *card)
0626 {
0627     struct usx2ydev *dev = usx2y(card);
0628     struct snd_usx2y_substream *subs;
0629     int i;
0630 
0631     for (i = 0; i < dev->pcm_devs * 2; i++) {
0632         subs = dev->subs[i];
0633         if (subs && subs->pcm_substream &&
0634             SUBSTREAM_BUSY(subs->pcm_substream))
0635             return -EBUSY;
0636     }
0637     return 0;
0638 }
0639 
0640 static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
0641 {
0642     struct snd_card *card = hw->card;
0643     int err;
0644 
0645     mutex_lock(&usx2y(card)->pcm_mutex);
0646     err = usx2y_pcms_busy_check(card);
0647     if (!err)
0648         usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
0649     mutex_unlock(&usx2y(card)->pcm_mutex);
0650     return err;
0651 }
0652 
0653 static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
0654 {
0655     struct snd_card *card = hw->card;
0656     int err;
0657 
0658     mutex_lock(&usx2y(card)->pcm_mutex);
0659     err = usx2y_pcms_busy_check(card);
0660     if (!err)
0661         usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
0662     mutex_unlock(&usx2y(card)->pcm_mutex);
0663     return err;
0664 }
0665 
0666 static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area)
0667 {
0668 }
0669 
0670 static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area)
0671 {
0672 }
0673 
0674 static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
0675 {
0676     unsigned long offset;
0677     void *vaddr;
0678 
0679     offset = vmf->pgoff << PAGE_SHIFT;
0680     vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
0681     vmf->page = virt_to_page(vaddr);
0682     get_page(vmf->page);
0683     return 0;
0684 }
0685 
0686 static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = {
0687     .open = snd_usx2y_hwdep_pcm_vm_open,
0688     .close = snd_usx2y_hwdep_pcm_vm_close,
0689     .fault = snd_usx2y_hwdep_pcm_vm_fault,
0690 };
0691 
0692 static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area)
0693 {
0694     unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
0695     struct usx2ydev *usx2y = hw->private_data;
0696 
0697     if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT))
0698         return -EBUSY;
0699 
0700     /* if userspace tries to mmap beyond end of our buffer, fail */
0701     if (size > USX2Y_HWDEP_PCM_PAGES) {
0702         snd_printd("%lu > %lu\n", size, (unsigned long)USX2Y_HWDEP_PCM_PAGES);
0703         return -EINVAL;
0704     }
0705 
0706     if (!usx2y->hwdep_pcm_shm)
0707         return -ENODEV;
0708 
0709     area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops;
0710     area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
0711     area->vm_private_data = hw->private_data;
0712     return 0;
0713 }
0714 
0715 static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
0716 {
0717     struct usx2ydev *usx2y = hwdep->private_data;
0718 
0719     if (usx2y->hwdep_pcm_shm)
0720         free_pages_exact(usx2y->hwdep_pcm_shm, USX2Y_HWDEP_PCM_PAGES);
0721 }
0722 
0723 int usx2y_hwdep_pcm_new(struct snd_card *card)
0724 {
0725     int err;
0726     struct snd_hwdep *hw;
0727     struct snd_pcm *pcm;
0728     struct usb_device *dev = usx2y(card)->dev;
0729 
0730     if (nr_of_packs() != 1)
0731         return 0;
0732 
0733     err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw);
0734     if (err < 0)
0735         return err;
0736 
0737     hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
0738     hw->private_data = usx2y(card);
0739     hw->private_free = snd_usx2y_hwdep_pcm_private_free;
0740     hw->ops.open = snd_usx2y_hwdep_pcm_open;
0741     hw->ops.release = snd_usx2y_hwdep_pcm_release;
0742     hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap;
0743     hw->exclusive = 1;
0744     sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
0745 
0746     err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
0747     if (err < 0)
0748         return err;
0749 
0750     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops);
0751     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops);
0752 
0753     pcm->private_data = usx2y(card)->subs;
0754     pcm->info_flags = 0;
0755 
0756     sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
0757     snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
0758                    SNDRV_DMA_TYPE_CONTINUOUS,
0759                    NULL,
0760                    64*1024, 128*1024);
0761     snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
0762                    SNDRV_DMA_TYPE_CONTINUOUS,
0763                    NULL,
0764                    64*1024, 128*1024);
0765 
0766     return 0;
0767 }
0768 
0769 #else
0770 
0771 int usx2y_hwdep_pcm_new(struct snd_card *card)
0772 {
0773     return 0;
0774 }
0775 
0776 #endif