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