xref: /openbmc/linux/sound/usb/usx2y/usx2yhwdeppcm.c (revision 8795a739)
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 snd_pcm_lib_free_pages(substream);
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 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 	.ioctl =	snd_pcm_lib_ioctl,
585 	.hw_params =	snd_usX2Y_pcm_hw_params,
586 	.hw_free =	snd_usX2Y_usbpcm_hw_free,
587 	.prepare =	snd_usX2Y_usbpcm_prepare,
588 	.trigger =	snd_usX2Y_pcm_trigger,
589 	.pointer =	snd_usX2Y_pcm_pointer,
590 };
591 
592 
593 static int usX2Y_pcms_busy_check(struct snd_card *card)
594 {
595 	struct usX2Ydev	*dev = usX2Y(card);
596 	int i;
597 
598 	for (i = 0; i < dev->pcm_devs * 2; i++) {
599 		struct snd_usX2Y_substream *subs = dev->subs[i];
600 		if (subs && subs->pcm_substream &&
601 		    SUBSTREAM_BUSY(subs->pcm_substream))
602 			return -EBUSY;
603 	}
604 	return 0;
605 }
606 
607 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
608 {
609 	struct snd_card *card = hw->card;
610 	int err;
611 
612 	mutex_lock(&usX2Y(card)->pcm_mutex);
613 	err = usX2Y_pcms_busy_check(card);
614 	if (!err)
615 		usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
616 	mutex_unlock(&usX2Y(card)->pcm_mutex);
617 	return err;
618 }
619 
620 
621 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
622 {
623 	struct snd_card *card = hw->card;
624 	int err;
625 
626 	mutex_lock(&usX2Y(card)->pcm_mutex);
627 	err = usX2Y_pcms_busy_check(card);
628 	if (!err)
629 		usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
630 	mutex_unlock(&usX2Y(card)->pcm_mutex);
631 	return err;
632 }
633 
634 
635 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
636 {
637 }
638 
639 
640 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
641 {
642 }
643 
644 
645 static vm_fault_t snd_usX2Y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
646 {
647 	unsigned long offset;
648 	void *vaddr;
649 
650 	offset = vmf->pgoff << PAGE_SHIFT;
651 	vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
652 	vmf->page = virt_to_page(vaddr);
653 	get_page(vmf->page);
654 	return 0;
655 }
656 
657 
658 static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
659 	.open = snd_usX2Y_hwdep_pcm_vm_open,
660 	.close = snd_usX2Y_hwdep_pcm_vm_close,
661 	.fault = snd_usX2Y_hwdep_pcm_vm_fault,
662 };
663 
664 
665 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
666 {
667 	unsigned long	size = (unsigned long)(area->vm_end - area->vm_start);
668 	struct usX2Ydev	*usX2Y = hw->private_data;
669 
670 	if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
671 		return -EBUSY;
672 
673 	/* if userspace tries to mmap beyond end of our buffer, fail */
674 	if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
675 		snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm));
676 		return -EINVAL;
677 	}
678 
679 	if (!usX2Y->hwdep_pcm_shm) {
680 		return -ENODEV;
681 	}
682 	area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
683 	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
684 	area->vm_private_data = hw->private_data;
685 	return 0;
686 }
687 
688 
689 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
690 {
691 	struct usX2Ydev *usX2Y = hwdep->private_data;
692 	if (NULL != usX2Y->hwdep_pcm_shm)
693 		free_pages_exact(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
694 }
695 
696 
697 int usX2Y_hwdep_pcm_new(struct snd_card *card)
698 {
699 	int err;
700 	struct snd_hwdep *hw;
701 	struct snd_pcm *pcm;
702 	struct usb_device *dev = usX2Y(card)->dev;
703 	if (1 != nr_of_packs())
704 		return 0;
705 
706 	if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
707 		return err;
708 
709 	hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
710 	hw->private_data = usX2Y(card);
711 	hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
712 	hw->ops.open = snd_usX2Y_hwdep_pcm_open;
713 	hw->ops.release = snd_usX2Y_hwdep_pcm_release;
714 	hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
715 	hw->exclusive = 1;
716 	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
717 
718 	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
719 	if (err < 0) {
720 		return err;
721 	}
722 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
723 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
724 
725 	pcm->private_data = usX2Y(card)->subs;
726 	pcm->info_flags = 0;
727 
728 	sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
729 	snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
730 				      SNDRV_DMA_TYPE_CONTINUOUS,
731 				      snd_dma_continuous_data(GFP_KERNEL),
732 				      64*1024, 128*1024);
733 	snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
734 				      SNDRV_DMA_TYPE_CONTINUOUS,
735 				      snd_dma_continuous_data(GFP_KERNEL),
736 				      64*1024, 128*1024);
737 
738 	return 0;
739 }
740 
741 #else
742 
743 int usX2Y_hwdep_pcm_new(struct snd_card *card)
744 {
745 	return 0;
746 }
747 
748 #endif
749