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