xref: /openbmc/linux/sound/usb/usx2y/usx2yhwdeppcm.c (revision 2a598d0b)
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->state < SNDRV_PCM_STATE_PREPARED) {
378 			atomic_set(&cap_subs->state, STATE_STOPPED);
379 			if (cap_subs2)
380 				atomic_set(&cap_subs2->state, STATE_STOPPED);
381 			usx2y_usbpcm_urbs_release(cap_subs);
382 			if (cap_subs2)
383 				usx2y_usbpcm_urbs_release(cap_subs2);
384 		}
385 	} else {
386 		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 (cap_subs2)
390 				atomic_set(&cap_subs2->state, STATE_STOPPED);
391 			usx2y_usbpcm_urbs_release(subs);
392 			if (cap_subs2)
393 				usx2y_usbpcm_urbs_release(cap_subs2);
394 		}
395 	}
396 	mutex_unlock(&subs->usx2y->pcm_mutex);
397 	return 0;
398 }
399 
400 static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs)
401 {
402 	struct usx2ydev *usx2y = subs->usx2y;
403 
404 	usx2y->prepare_subs = subs;
405 	subs->urb[0]->start_frame = -1;
406 	smp_wmb();	// Make sure above modifications are seen by i_usx2y_subs_startup()
407 	usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup);
408 }
409 
410 static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs)
411 {
412 	int	p, u, err, stream = subs->pcm_substream->stream;
413 	struct usx2ydev *usx2y = subs->usx2y;
414 	struct urb *urb;
415 	unsigned long pack;
416 
417 	if (stream == SNDRV_PCM_STREAM_CAPTURE) {
418 		usx2y->hwdep_pcm_shm->captured_iso_head = -1;
419 		usx2y->hwdep_pcm_shm->captured_iso_frames = 0;
420 	}
421 
422 	for (p = 0; 3 >= (stream + p); p += 2) {
423 		struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
424 		if (subs) {
425 			err = usx2y_usbpcm_urbs_allocate(subs);
426 			if (err < 0)
427 				return err;
428 			subs->completed_urb = NULL;
429 		}
430 	}
431 
432 	for (p = 0; p < 4; p++) {
433 		struct snd_usx2y_substream *subs = usx2y->subs[p];
434 
435 		if (subs && atomic_read(&subs->state) >= STATE_PREPARED)
436 			goto start;
437 	}
438 
439  start:
440 	usx2y_usbpcm_subs_startup(subs);
441 	for (u = 0; u < NRURBS; u++) {
442 		for (p = 0; 3 >= (stream + p); p += 2) {
443 			struct snd_usx2y_substream *subs = usx2y->subs[stream + p];
444 
445 			if (!subs)
446 				continue;
447 			urb = subs->urb[u];
448 			if (usb_pipein(urb->pipe)) {
449 				if (!u)
450 					atomic_set(&subs->state, STATE_STARTING3);
451 				urb->dev = usx2y->dev;
452 				for (pack = 0; pack < nr_of_packs(); pack++) {
453 					urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
454 					urb->iso_frame_desc[pack].length = subs->maxpacksize;
455 				}
456 				urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
457 				err = usb_submit_urb(urb, GFP_KERNEL);
458 				if (err < 0) {
459 					snd_printk(KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
460 					err = -EPIPE;
461 					goto cleanup;
462 				}  else {
463 					snd_printdd("%i\n", urb->start_frame);
464 					if (!u)
465 						usx2y->wait_iso_frame = urb->start_frame;
466 				}
467 				urb->transfer_flags = 0;
468 			} else {
469 				atomic_set(&subs->state, STATE_STARTING1);
470 				break;
471 			}
472 		}
473 	}
474 	err = 0;
475 	wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs);
476 	if (atomic_read(&subs->state) != STATE_PREPARED)
477 		err = -EPIPE;
478 
479  cleanup:
480 	if (err) {
481 		usx2y_subs_startup_finish(usx2y);	// Call it now
482 		usx2y_clients_stop(usx2y);	// something is completely wrong > stop everything
483 	}
484 	return err;
485 }
486 
487 #define USX2Y_HWDEP_PCM_PAGES	\
488 	PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm))
489 
490 /*
491  * prepare callback
492  *
493  * set format and initialize urbs
494  */
495 static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream)
496 {
497 	struct snd_pcm_runtime *runtime = substream->runtime;
498 	struct snd_usx2y_substream *subs = runtime->private_data;
499 	struct usx2ydev *usx2y = subs->usx2y;
500 	struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
501 	int err = 0;
502 
503 	snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
504 
505 	mutex_lock(&usx2y->pcm_mutex);
506 
507 	if (!usx2y->hwdep_pcm_shm) {
508 		usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES,
509 							 GFP_KERNEL);
510 		if (!usx2y->hwdep_pcm_shm) {
511 			err = -ENOMEM;
512 			goto up_prepare_mutex;
513 		}
514 		memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES);
515 	}
516 
517 	usx2y_subs_prepare(subs);
518 	// Start hardware streams
519 	// SyncStream first....
520 	if (atomic_read(&capsubs->state) < STATE_PREPARED) {
521 		if (usx2y->format != runtime->format) {
522 			err = usx2y_format_set(usx2y, runtime->format);
523 			if (err < 0)
524 				goto up_prepare_mutex;
525 		}
526 		if (usx2y->rate != runtime->rate) {
527 			err = usx2y_rate_set(usx2y, runtime->rate);
528 			if (err < 0)
529 				goto up_prepare_mutex;
530 		}
531 		snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
532 			    "self" : "playpipe");
533 		err = usx2y_usbpcm_urbs_start(capsubs);
534 		if (err < 0)
535 			goto up_prepare_mutex;
536 	}
537 
538 	if (subs != capsubs) {
539 		usx2y->hwdep_pcm_shm->playback_iso_start = -1;
540 		if (atomic_read(&subs->state) < STATE_PREPARED) {
541 			while (usx2y_iso_frames_per_buffer(runtime, usx2y) >
542 			       usx2y->hwdep_pcm_shm->captured_iso_frames) {
543 				snd_printdd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
544 					    usx2y_iso_frames_per_buffer(runtime, usx2y),
545 					    usx2y->hwdep_pcm_shm->captured_iso_frames);
546 				if (msleep_interruptible(10)) {
547 					err = -ERESTARTSYS;
548 					goto up_prepare_mutex;
549 				}
550 			}
551 			err = usx2y_usbpcm_urbs_start(subs);
552 			if (err < 0)
553 				goto up_prepare_mutex;
554 		}
555 		snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
556 			    usx2y_iso_frames_per_buffer(runtime, usx2y),
557 			    usx2y->hwdep_pcm_shm->captured_iso_frames);
558 	} else {
559 		usx2y->hwdep_pcm_shm->capture_iso_start = -1;
560 	}
561 
562  up_prepare_mutex:
563 	mutex_unlock(&usx2y->pcm_mutex);
564 	return err;
565 }
566 
567 static const struct snd_pcm_hardware snd_usx2y_4c = {
568 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
569 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
570 				 SNDRV_PCM_INFO_MMAP_VALID),
571 	.formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
572 	.rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
573 	.rate_min =                44100,
574 	.rate_max =                48000,
575 	.channels_min =            2,
576 	.channels_max =            4,
577 	.buffer_bytes_max =	(2*128*1024),
578 	.period_bytes_min =	64,
579 	.period_bytes_max =	(128*1024),
580 	.periods_min =		2,
581 	.periods_max =		1024,
582 	.fifo_size =              0
583 };
584 
585 static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream)
586 {
587 	struct snd_usx2y_substream	*subs =
588 		((struct snd_usx2y_substream **)
589 		 snd_pcm_substream_chip(substream))[substream->stream];
590 	struct snd_pcm_runtime	*runtime = substream->runtime;
591 
592 	if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
593 		return -EBUSY;
594 
595 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
596 		runtime->hw = snd_usx2y_2c;
597 	else
598 		runtime->hw = (subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c);
599 	runtime->private_data = subs;
600 	subs->pcm_substream = substream;
601 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
602 	return 0;
603 }
604 
605 static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream)
606 {
607 	struct snd_pcm_runtime *runtime = substream->runtime;
608 	struct snd_usx2y_substream *subs = runtime->private_data;
609 
610 	subs->pcm_substream = NULL;
611 	return 0;
612 }
613 
614 static const struct snd_pcm_ops snd_usx2y_usbpcm_ops = {
615 	.open =		snd_usx2y_usbpcm_open,
616 	.close =	snd_usx2y_usbpcm_close,
617 	.hw_params =	snd_usx2y_pcm_hw_params,
618 	.hw_free =	snd_usx2y_usbpcm_hw_free,
619 	.prepare =	snd_usx2y_usbpcm_prepare,
620 	.trigger =	snd_usx2y_pcm_trigger,
621 	.pointer =	snd_usx2y_pcm_pointer,
622 };
623 
624 static int usx2y_pcms_busy_check(struct snd_card *card)
625 {
626 	struct usx2ydev	*dev = usx2y(card);
627 	struct snd_usx2y_substream *subs;
628 	int i;
629 
630 	for (i = 0; i < dev->pcm_devs * 2; i++) {
631 		subs = dev->subs[i];
632 		if (subs && subs->pcm_substream &&
633 		    SUBSTREAM_BUSY(subs->pcm_substream))
634 			return -EBUSY;
635 	}
636 	return 0;
637 }
638 
639 static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
640 {
641 	struct snd_card *card = hw->card;
642 	int err;
643 
644 	mutex_lock(&usx2y(card)->pcm_mutex);
645 	err = usx2y_pcms_busy_check(card);
646 	if (!err)
647 		usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
648 	mutex_unlock(&usx2y(card)->pcm_mutex);
649 	return err;
650 }
651 
652 static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
653 {
654 	struct snd_card *card = hw->card;
655 	int err;
656 
657 	mutex_lock(&usx2y(card)->pcm_mutex);
658 	err = usx2y_pcms_busy_check(card);
659 	if (!err)
660 		usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
661 	mutex_unlock(&usx2y(card)->pcm_mutex);
662 	return err;
663 }
664 
665 static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area)
666 {
667 }
668 
669 static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area)
670 {
671 }
672 
673 static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
674 {
675 	unsigned long offset;
676 	void *vaddr;
677 
678 	offset = vmf->pgoff << PAGE_SHIFT;
679 	vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
680 	vmf->page = virt_to_page(vaddr);
681 	get_page(vmf->page);
682 	return 0;
683 }
684 
685 static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = {
686 	.open = snd_usx2y_hwdep_pcm_vm_open,
687 	.close = snd_usx2y_hwdep_pcm_vm_close,
688 	.fault = snd_usx2y_hwdep_pcm_vm_fault,
689 };
690 
691 static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area)
692 {
693 	unsigned long	size = (unsigned long)(area->vm_end - area->vm_start);
694 	struct usx2ydev	*usx2y = hw->private_data;
695 
696 	if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT))
697 		return -EBUSY;
698 
699 	/* if userspace tries to mmap beyond end of our buffer, fail */
700 	if (size > USX2Y_HWDEP_PCM_PAGES) {
701 		snd_printd("%lu > %lu\n", size, (unsigned long)USX2Y_HWDEP_PCM_PAGES);
702 		return -EINVAL;
703 	}
704 
705 	if (!usx2y->hwdep_pcm_shm)
706 		return -ENODEV;
707 
708 	area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops;
709 	vm_flags_set(area, VM_DONTEXPAND | VM_DONTDUMP);
710 	area->vm_private_data = hw->private_data;
711 	return 0;
712 }
713 
714 static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
715 {
716 	struct usx2ydev *usx2y = hwdep->private_data;
717 
718 	if (usx2y->hwdep_pcm_shm)
719 		free_pages_exact(usx2y->hwdep_pcm_shm, USX2Y_HWDEP_PCM_PAGES);
720 }
721 
722 int usx2y_hwdep_pcm_new(struct snd_card *card)
723 {
724 	int err;
725 	struct snd_hwdep *hw;
726 	struct snd_pcm *pcm;
727 	struct usb_device *dev = usx2y(card)->dev;
728 
729 	if (nr_of_packs() != 1)
730 		return 0;
731 
732 	err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw);
733 	if (err < 0)
734 		return err;
735 
736 	hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
737 	hw->private_data = usx2y(card);
738 	hw->private_free = snd_usx2y_hwdep_pcm_private_free;
739 	hw->ops.open = snd_usx2y_hwdep_pcm_open;
740 	hw->ops.release = snd_usx2y_hwdep_pcm_release;
741 	hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap;
742 	hw->exclusive = 1;
743 	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
744 
745 	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
746 	if (err < 0)
747 		return err;
748 
749 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops);
750 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops);
751 
752 	pcm->private_data = usx2y(card)->subs;
753 	pcm->info_flags = 0;
754 
755 	sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
756 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
757 				   SNDRV_DMA_TYPE_CONTINUOUS,
758 				   NULL,
759 				   64*1024, 128*1024);
760 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
761 				   SNDRV_DMA_TYPE_CONTINUOUS,
762 				   NULL,
763 				   64*1024, 128*1024);
764 
765 	return 0;
766 }
767 
768 #else
769 
770 int usx2y_hwdep_pcm_new(struct snd_card *card)
771 {
772 	return 0;
773 }
774 
775 #endif
776