xref: /openbmc/linux/sound/usb/usx2y/usx2yhwdeppcm.c (revision 603c09f2)
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 static int usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream *subs)
50 {
51 	struct urb	*urb = subs->completed_urb;
52 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
53 	int		i, lens = 0, hwptr_done = subs->hwptr_done;
54 	struct usx2ydev	*usx2y = subs->usx2y;
55 	int head;
56 
57 	if (usx2y->hwdep_pcm_shm->capture_iso_start < 0) { //FIXME
58 		head = usx2y->hwdep_pcm_shm->captured_iso_head + 1;
59 		if (head >= ARRAY_SIZE(usx2y->hwdep_pcm_shm->captured_iso))
60 			head = 0;
61 		usx2y->hwdep_pcm_shm->capture_iso_start = head;
62 		snd_printdd("cap start %i\n", head);
63 	}
64 	for (i = 0; i < nr_of_packs(); i++) {
65 		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
66 			snd_printk(KERN_ERR
67 				   "active frame status %i. Most probably some hardware problem.\n",
68 				   urb->iso_frame_desc[i].status);
69 			return urb->iso_frame_desc[i].status;
70 		}
71 		lens += urb->iso_frame_desc[i].actual_length / usx2y->stride;
72 	}
73 	hwptr_done += lens;
74 	if (hwptr_done >= runtime->buffer_size)
75 		hwptr_done -= runtime->buffer_size;
76 	subs->hwptr_done = hwptr_done;
77 	subs->transfer_done += lens;
78 	/* update the pointer, call callback if necessary */
79 	if (subs->transfer_done >= runtime->period_size) {
80 		subs->transfer_done -= runtime->period_size;
81 		snd_pcm_period_elapsed(subs->pcm_substream);
82 	}
83 	return 0;
84 }
85 
86 static int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
87 					      struct usx2ydev *usx2y)
88 {
89 	return (runtime->buffer_size * 1000) / usx2y->rate + 1;	//FIXME: so far only correct period_size == 2^x ?
90 }
91 
92 /*
93  * prepare urb for playback data pipe
94  *
95  * we copy the data directly from the pcm buffer.
96  * the current position to be copied is held in hwptr field.
97  * since a urb can handle only a single linear buffer, if the total
98  * transferred area overflows the buffer boundary, we cannot send
99  * it directly from the buffer.  thus the data is once copied to
100  * a temporary buffer and urb points to that.
101  */
102 static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs,
103 					struct urb *urb)
104 {
105 	int count, counts, pack;
106 	struct usx2ydev *usx2y = subs->usx2y;
107 	struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm;
108 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
109 
110 	if (shm->playback_iso_start < 0) {
111 		shm->playback_iso_start = shm->captured_iso_head -
112 			usx2y_iso_frames_per_buffer(runtime, usx2y);
113 		if (shm->playback_iso_start < 0)
114 			shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
115 		shm->playback_iso_head = shm->playback_iso_start;
116 	}
117 
118 	count = 0;
119 	for (pack = 0; pack < nr_of_packs(); pack++) {
120 		/* calculate the size of a packet */
121 		counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride;
122 		if (counts < 43 || counts > 50) {
123 			snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
124 			return -EPIPE;
125 		}
126 		/* set up descriptor */
127 		urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
128 		urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
129 		if (atomic_read(&subs->state) != STATE_RUNNING)
130 			memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
131 			       urb->iso_frame_desc[pack].length);
132 		if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
133 			shm->playback_iso_head = 0;
134 		count += counts;
135 	}
136 	urb->transfer_buffer_length = count * usx2y->stride;
137 	return 0;
138 }
139 
140 static void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs,
141 					      struct urb *urb)
142 {
143 	struct usb_iso_packet_descriptor *desc;
144 	struct snd_usx2y_hwdep_pcm_shm *shm;
145 	int pack, head;
146 
147 	for (pack = 0; pack < nr_of_packs(); ++pack) {
148 		desc = urb->iso_frame_desc + pack;
149 		if (subs) {
150 			shm = subs->usx2y->hwdep_pcm_shm;
151 			head = shm->captured_iso_head + 1;
152 			if (head >= ARRAY_SIZE(shm->captured_iso))
153 				head = 0;
154 			shm->captured_iso[head].frame = urb->start_frame + pack;
155 			shm->captured_iso[head].offset = desc->offset;
156 			shm->captured_iso[head].length = desc->actual_length;
157 			shm->captured_iso_head = head;
158 			shm->captured_iso_frames++;
159 		}
160 		desc->offset += desc->length * NRURBS * nr_of_packs();
161 		if (desc->offset + desc->length >= SSS)
162 			desc->offset -= (SSS - desc->length);
163 	}
164 }
165 
166 static int usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream *capsubs,
167 					  struct snd_usx2y_substream *capsubs2,
168 					  struct snd_usx2y_substream *playbacksubs,
169 					  int frame)
170 {
171 	int err, state;
172 	struct urb *urb = playbacksubs->completed_urb;
173 
174 	state = atomic_read(&playbacksubs->state);
175 	if (urb) {
176 		if (state == STATE_RUNNING)
177 			usx2y_urb_play_retire(playbacksubs, urb);
178 		else if (state >= STATE_PRERUNNING)
179 			atomic_inc(&playbacksubs->state);
180 	} else {
181 		switch (state) {
182 		case STATE_STARTING1:
183 			urb = playbacksubs->urb[0];
184 			atomic_inc(&playbacksubs->state);
185 			break;
186 		case STATE_STARTING2:
187 			urb = playbacksubs->urb[1];
188 			atomic_inc(&playbacksubs->state);
189 			break;
190 		}
191 	}
192 	if (urb) {
193 		err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
194 		if (err)
195 			return err;
196 		err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb);
197 		if (err)
198 			return err;
199 	}
200 
201 	playbacksubs->completed_urb = NULL;
202 
203 	state = atomic_read(&capsubs->state);
204 	if (state >= STATE_PREPARED) {
205 		if (state == STATE_RUNNING) {
206 			err = usx2y_usbpcm_urb_capt_retire(capsubs);
207 			if (err)
208 				return err;
209 		} else if (state >= STATE_PRERUNNING) {
210 			atomic_inc(&capsubs->state);
211 		}
212 		usx2y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
213 		if (capsubs2)
214 			usx2y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
215 		err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame);
216 		if (err)
217 			return err;
218 		if (capsubs2) {
219 			err = usx2y_urb_submit(capsubs2, capsubs2->completed_urb, frame);
220 			if (err)
221 				return err;
222 		}
223 	}
224 	capsubs->completed_urb = NULL;
225 	if (capsubs2)
226 		capsubs2->completed_urb = NULL;
227 	return 0;
228 }
229 
230 static void i_usx2y_usbpcm_urb_complete(struct urb *urb)
231 {
232 	struct snd_usx2y_substream *subs = urb->context;
233 	struct usx2ydev *usx2y = subs->usx2y;
234 	struct snd_usx2y_substream *capsubs, *capsubs2, *playbacksubs;
235 
236 	if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
237 		snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
238 			    usb_get_current_frame_number(usx2y->dev),
239 			    subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
240 			    urb->status, urb->start_frame);
241 		return;
242 	}
243 	if (unlikely(urb->status)) {
244 		usx2y_error_urb_status(usx2y, subs, urb);
245 		return;
246 	}
247 
248 	subs->completed_urb = urb;
249 	capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
250 	capsubs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
251 	playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
252 	if (capsubs->completed_urb && atomic_read(&capsubs->state) >= STATE_PREPARED &&
253 	    (!capsubs2 || capsubs2->completed_urb) &&
254 	    (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
255 		if (!usx2y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
256 			usx2y->wait_iso_frame += nr_of_packs();
257 		} else {
258 			snd_printdd("\n");
259 			usx2y_clients_stop(usx2y);
260 		}
261 	}
262 }
263 
264 static void usx2y_hwdep_urb_release(struct urb **urb)
265 {
266 	usb_kill_urb(*urb);
267 	usb_free_urb(*urb);
268 	*urb = NULL;
269 }
270 
271 /*
272  * release a substream
273  */
274 static void usx2y_usbpcm_urbs_release(struct snd_usx2y_substream *subs)
275 {
276 	int i;
277 
278 	snd_printdd("snd_usx2y_urbs_release() %i\n", subs->endpoint);
279 	for (i = 0; i < NRURBS; i++)
280 		usx2y_hwdep_urb_release(subs->urb + i);
281 }
282 
283 static void usx2y_usbpcm_subs_startup_finish(struct usx2ydev *usx2y)
284 {
285 	usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_urb_complete);
286 	usx2y->prepare_subs = NULL;
287 }
288 
289 static void i_usx2y_usbpcm_subs_startup(struct urb *urb)
290 {
291 	struct snd_usx2y_substream *subs = urb->context;
292 	struct usx2ydev *usx2y = subs->usx2y;
293 	struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
294 	struct snd_usx2y_substream *cap_subs2;
295 
296 	if (prepare_subs &&
297 	    urb->start_frame == prepare_subs->urb[0]->start_frame) {
298 		atomic_inc(&prepare_subs->state);
299 		if (prepare_subs == usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
300 			cap_subs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
301 			if (cap_subs2)
302 				atomic_inc(&cap_subs2->state);
303 		}
304 		usx2y_usbpcm_subs_startup_finish(usx2y);
305 		wake_up(&usx2y->prepare_wait_queue);
306 	}
307 
308 	i_usx2y_usbpcm_urb_complete(urb);
309 }
310 
311 /*
312  * initialize a substream's urbs
313  */
314 static int usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream *subs)
315 {
316 	int i;
317 	unsigned int pipe;
318 	int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
319 	struct usb_device *dev = subs->usx2y->dev;
320 	struct urb **purb;
321 
322 	pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
323 			usb_rcvisocpipe(dev, subs->endpoint);
324 	subs->maxpacksize = usb_maxpacket(dev, pipe);
325 	if (!subs->maxpacksize)
326 		return -EINVAL;
327 
328 	/* allocate and initialize data urbs */
329 	for (i = 0; i < NRURBS; i++) {
330 		purb = subs->urb + i;
331 		if (*purb) {
332 			usb_kill_urb(*purb);
333 			continue;
334 		}
335 		*purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
336 		if (!*purb) {
337 			usx2y_usbpcm_urbs_release(subs);
338 			return -ENOMEM;
339 		}
340 		(*purb)->transfer_buffer = is_playback ?
341 			subs->usx2y->hwdep_pcm_shm->playback : (
342 				subs->endpoint == 0x8 ?
343 				subs->usx2y->hwdep_pcm_shm->capture0x8 :
344 				subs->usx2y->hwdep_pcm_shm->capture0xA);
345 
346 		(*purb)->dev = dev;
347 		(*purb)->pipe = pipe;
348 		(*purb)->number_of_packets = nr_of_packs();
349 		(*purb)->context = subs;
350 		(*purb)->interval = 1;
351 		(*purb)->complete = i_usx2y_usbpcm_subs_startup;
352 	}
353 	return 0;
354 }
355 
356 /*
357  * free the buffer
358  */
359 static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream)
360 {
361 	struct snd_pcm_runtime *runtime = substream->runtime;
362 	struct snd_usx2y_substream *subs = runtime->private_data;
363 	struct snd_usx2y_substream *cap_subs;
364 	struct snd_usx2y_substream *playback_subs;
365 	struct snd_usx2y_substream *cap_subs2;
366 
367 	mutex_lock(&subs->usx2y->pcm_mutex);
368 	snd_printdd("%s(%p)\n", __func__, substream);
369 
370 	cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
371 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
372 		cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
373 		atomic_set(&subs->state, STATE_STOPPED);
374 		usx2y_usbpcm_urbs_release(subs);
375 		if (!cap_subs->pcm_substream ||
376 		    !cap_subs->pcm_substream->runtime ||
377 		    !cap_subs->pcm_substream->runtime->status ||
378 		    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
379 			atomic_set(&cap_subs->state, STATE_STOPPED);
380 			if (cap_subs2)
381 				atomic_set(&cap_subs2->state, STATE_STOPPED);
382 			usx2y_usbpcm_urbs_release(cap_subs);
383 			if (cap_subs2)
384 				usx2y_usbpcm_urbs_release(cap_subs2);
385 		}
386 	} else {
387 		playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
388 		if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
389 			atomic_set(&subs->state, STATE_STOPPED);
390 			if (cap_subs2)
391 				atomic_set(&cap_subs2->state, STATE_STOPPED);
392 			usx2y_usbpcm_urbs_release(subs);
393 			if (cap_subs2)
394 				usx2y_usbpcm_urbs_release(cap_subs2);
395 		}
396 	}
397 	mutex_unlock(&subs->usx2y->pcm_mutex);
398 	return 0;
399 }
400 
401 static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs)
402 {
403 	struct usx2ydev *usx2y = subs->usx2y;
404 
405 	usx2y->prepare_subs = subs;
406 	subs->urb[0]->start_frame = -1;
407 	smp_wmb();	// Make sure above modifications are seen by i_usx2y_subs_startup()
408 	usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup);
409 }
410 
411 static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs)
412 {
413 	int	p, u, err, stream = subs->pcm_substream->stream;
414 	struct usx2ydev *usx2y = subs->usx2y;
415 	struct urb *urb;
416 	unsigned long pack;
417 
418 	if (stream == SNDRV_PCM_STREAM_CAPTURE) {
419 		usx2y->hwdep_pcm_shm->captured_iso_head = -1;
420 		usx2y->hwdep_pcm_shm->captured_iso_frames = 0;
421 	}
422 
423 	for (p = 0; 3 >= (stream + p); p += 2) {
424 		struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
425 		if (subs) {
426 			err = usx2y_usbpcm_urbs_allocate(subs);
427 			if (err < 0)
428 				return err;
429 			subs->completed_urb = NULL;
430 		}
431 	}
432 
433 	for (p = 0; p < 4; p++) {
434 		struct snd_usx2y_substream *subs = usx2y->subs[p];
435 
436 		if (subs && atomic_read(&subs->state) >= STATE_PREPARED)
437 			goto start;
438 	}
439 
440  start:
441 	usx2y_usbpcm_subs_startup(subs);
442 	for (u = 0; u < NRURBS; u++) {
443 		for (p = 0; 3 >= (stream + p); p += 2) {
444 			struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
445 
446 			if (!subs)
447 				continue;
448 			urb = subs->urb[u];
449 			if (usb_pipein(urb->pipe)) {
450 				if (!u)
451 					atomic_set(&subs->state, STATE_STARTING3);
452 				urb->dev = usx2y->dev;
453 				for (pack = 0; pack < nr_of_packs(); pack++) {
454 					urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
455 					urb->iso_frame_desc[pack].length = subs->maxpacksize;
456 				}
457 				urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
458 				err = usb_submit_urb(urb, GFP_KERNEL);
459 				if (err < 0) {
460 					snd_printk(KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
461 					err = -EPIPE;
462 					goto cleanup;
463 				}  else {
464 					snd_printdd("%i\n", urb->start_frame);
465 					if (!u)
466 						usx2y->wait_iso_frame = urb->start_frame;
467 				}
468 				urb->transfer_flags = 0;
469 			} else {
470 				atomic_set(&subs->state, STATE_STARTING1);
471 				break;
472 			}
473 		}
474 	}
475 	err = 0;
476 	wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs);
477 	if (atomic_read(&subs->state) != STATE_PREPARED)
478 		err = -EPIPE;
479 
480  cleanup:
481 	if (err) {
482 		usx2y_subs_startup_finish(usx2y);	// Call it now
483 		usx2y_clients_stop(usx2y);	// something is completely wrong > stop everything
484 	}
485 	return err;
486 }
487 
488 #define USX2Y_HWDEP_PCM_PAGES	\
489 	PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm))
490 
491 /*
492  * prepare callback
493  *
494  * set format and initialize urbs
495  */
496 static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream)
497 {
498 	struct snd_pcm_runtime *runtime = substream->runtime;
499 	struct snd_usx2y_substream *subs = runtime->private_data;
500 	struct usx2ydev *usx2y = subs->usx2y;
501 	struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
502 	int err = 0;
503 
504 	snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
505 
506 	mutex_lock(&usx2y->pcm_mutex);
507 
508 	if (!usx2y->hwdep_pcm_shm) {
509 		usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES,
510 							 GFP_KERNEL);
511 		if (!usx2y->hwdep_pcm_shm) {
512 			err = -ENOMEM;
513 			goto up_prepare_mutex;
514 		}
515 		memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES);
516 	}
517 
518 	usx2y_subs_prepare(subs);
519 	// Start hardware streams
520 	// SyncStream first....
521 	if (atomic_read(&capsubs->state) < STATE_PREPARED) {
522 		if (usx2y->format != runtime->format) {
523 			err = usx2y_format_set(usx2y, runtime->format);
524 			if (err < 0)
525 				goto up_prepare_mutex;
526 		}
527 		if (usx2y->rate != runtime->rate) {
528 			err = usx2y_rate_set(usx2y, runtime->rate);
529 			if (err < 0)
530 				goto up_prepare_mutex;
531 		}
532 		snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
533 			    "self" : "playpipe");
534 		err = usx2y_usbpcm_urbs_start(capsubs);
535 		if (err < 0)
536 			goto up_prepare_mutex;
537 	}
538 
539 	if (subs != capsubs) {
540 		usx2y->hwdep_pcm_shm->playback_iso_start = -1;
541 		if (atomic_read(&subs->state) < STATE_PREPARED) {
542 			while (usx2y_iso_frames_per_buffer(runtime, usx2y) >
543 			       usx2y->hwdep_pcm_shm->captured_iso_frames) {
544 				snd_printdd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
545 					    usx2y_iso_frames_per_buffer(runtime, usx2y),
546 					    usx2y->hwdep_pcm_shm->captured_iso_frames);
547 				if (msleep_interruptible(10)) {
548 					err = -ERESTARTSYS;
549 					goto up_prepare_mutex;
550 				}
551 			}
552 			err = usx2y_usbpcm_urbs_start(subs);
553 			if (err < 0)
554 				goto up_prepare_mutex;
555 		}
556 		snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
557 			    usx2y_iso_frames_per_buffer(runtime, usx2y),
558 			    usx2y->hwdep_pcm_shm->captured_iso_frames);
559 	} else {
560 		usx2y->hwdep_pcm_shm->capture_iso_start = -1;
561 	}
562 
563  up_prepare_mutex:
564 	mutex_unlock(&usx2y->pcm_mutex);
565 	return err;
566 }
567 
568 static const struct snd_pcm_hardware snd_usx2y_4c = {
569 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
570 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
571 				 SNDRV_PCM_INFO_MMAP_VALID),
572 	.formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
573 	.rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
574 	.rate_min =                44100,
575 	.rate_max =                48000,
576 	.channels_min =            2,
577 	.channels_max =            4,
578 	.buffer_bytes_max =	(2*128*1024),
579 	.period_bytes_min =	64,
580 	.period_bytes_max =	(128*1024),
581 	.periods_min =		2,
582 	.periods_max =		1024,
583 	.fifo_size =              0
584 };
585 
586 static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream)
587 {
588 	struct snd_usx2y_substream	*subs =
589 		((struct snd_usx2y_substream **)
590 		 snd_pcm_substream_chip(substream))[substream->stream];
591 	struct snd_pcm_runtime	*runtime = substream->runtime;
592 
593 	if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
594 		return -EBUSY;
595 
596 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
597 		runtime->hw = snd_usx2y_2c;
598 	else
599 		runtime->hw = (subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c);
600 	runtime->private_data = subs;
601 	subs->pcm_substream = substream;
602 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
603 	return 0;
604 }
605 
606 static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream)
607 {
608 	struct snd_pcm_runtime *runtime = substream->runtime;
609 	struct snd_usx2y_substream *subs = runtime->private_data;
610 
611 	subs->pcm_substream = NULL;
612 	return 0;
613 }
614 
615 static const struct snd_pcm_ops snd_usx2y_usbpcm_ops = {
616 	.open =		snd_usx2y_usbpcm_open,
617 	.close =	snd_usx2y_usbpcm_close,
618 	.hw_params =	snd_usx2y_pcm_hw_params,
619 	.hw_free =	snd_usx2y_usbpcm_hw_free,
620 	.prepare =	snd_usx2y_usbpcm_prepare,
621 	.trigger =	snd_usx2y_pcm_trigger,
622 	.pointer =	snd_usx2y_pcm_pointer,
623 };
624 
625 static int usx2y_pcms_busy_check(struct snd_card *card)
626 {
627 	struct usx2ydev	*dev = usx2y(card);
628 	struct snd_usx2y_substream *subs;
629 	int i;
630 
631 	for (i = 0; i < dev->pcm_devs * 2; i++) {
632 		subs = dev->subs[i];
633 		if (subs && subs->pcm_substream &&
634 		    SUBSTREAM_BUSY(subs->pcm_substream))
635 			return -EBUSY;
636 	}
637 	return 0;
638 }
639 
640 static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
641 {
642 	struct snd_card *card = hw->card;
643 	int err;
644 
645 	mutex_lock(&usx2y(card)->pcm_mutex);
646 	err = usx2y_pcms_busy_check(card);
647 	if (!err)
648 		usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
649 	mutex_unlock(&usx2y(card)->pcm_mutex);
650 	return err;
651 }
652 
653 static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
654 {
655 	struct snd_card *card = hw->card;
656 	int err;
657 
658 	mutex_lock(&usx2y(card)->pcm_mutex);
659 	err = usx2y_pcms_busy_check(card);
660 	if (!err)
661 		usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
662 	mutex_unlock(&usx2y(card)->pcm_mutex);
663 	return err;
664 }
665 
666 static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area)
667 {
668 }
669 
670 static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area)
671 {
672 }
673 
674 static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
675 {
676 	unsigned long offset;
677 	void *vaddr;
678 
679 	offset = vmf->pgoff << PAGE_SHIFT;
680 	vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
681 	vmf->page = virt_to_page(vaddr);
682 	get_page(vmf->page);
683 	return 0;
684 }
685 
686 static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = {
687 	.open = snd_usx2y_hwdep_pcm_vm_open,
688 	.close = snd_usx2y_hwdep_pcm_vm_close,
689 	.fault = snd_usx2y_hwdep_pcm_vm_fault,
690 };
691 
692 static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area)
693 {
694 	unsigned long	size = (unsigned long)(area->vm_end - area->vm_start);
695 	struct usx2ydev	*usx2y = hw->private_data;
696 
697 	if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT))
698 		return -EBUSY;
699 
700 	/* if userspace tries to mmap beyond end of our buffer, fail */
701 	if (size > USX2Y_HWDEP_PCM_PAGES) {
702 		snd_printd("%lu > %lu\n", size, (unsigned long)USX2Y_HWDEP_PCM_PAGES);
703 		return -EINVAL;
704 	}
705 
706 	if (!usx2y->hwdep_pcm_shm)
707 		return -ENODEV;
708 
709 	area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops;
710 	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
711 	area->vm_private_data = hw->private_data;
712 	return 0;
713 }
714 
715 static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
716 {
717 	struct usx2ydev *usx2y = hwdep->private_data;
718 
719 	if (usx2y->hwdep_pcm_shm)
720 		free_pages_exact(usx2y->hwdep_pcm_shm, USX2Y_HWDEP_PCM_PAGES);
721 }
722 
723 int usx2y_hwdep_pcm_new(struct snd_card *card)
724 {
725 	int err;
726 	struct snd_hwdep *hw;
727 	struct snd_pcm *pcm;
728 	struct usb_device *dev = usx2y(card)->dev;
729 
730 	if (nr_of_packs() != 1)
731 		return 0;
732 
733 	err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw);
734 	if (err < 0)
735 		return err;
736 
737 	hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
738 	hw->private_data = usx2y(card);
739 	hw->private_free = snd_usx2y_hwdep_pcm_private_free;
740 	hw->ops.open = snd_usx2y_hwdep_pcm_open;
741 	hw->ops.release = snd_usx2y_hwdep_pcm_release;
742 	hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap;
743 	hw->exclusive = 1;
744 	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
745 
746 	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
747 	if (err < 0)
748 		return err;
749 
750 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops);
751 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops);
752 
753 	pcm->private_data = usx2y(card)->subs;
754 	pcm->info_flags = 0;
755 
756 	sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
757 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
758 				   SNDRV_DMA_TYPE_CONTINUOUS,
759 				   NULL,
760 				   64*1024, 128*1024);
761 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
762 				   SNDRV_DMA_TYPE_CONTINUOUS,
763 				   NULL,
764 				   64*1024, 128*1024);
765 
766 	return 0;
767 }
768 
769 #else
770 
771 int usx2y_hwdep_pcm_new(struct snd_card *card)
772 {
773 	return 0;
774 }
775 
776 #endif
777