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