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