0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
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) {
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) {
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
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;
0090 }
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
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
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
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
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
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
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
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();
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);
0483 usx2y_clients_stop(usx2y);
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
0493
0494
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
0520
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
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