Linux Audio

Check our new training course

Loading...
  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 dependent 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, functionalities should migrate to more appropriate 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 <linux/gfp.h>
 55#include "usbusx2yaudio.c"
 56
 57#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
 58
 59#include <sound/hwdep.h>
 60
 61
 62static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
 63{
 64	struct urb	*urb = subs->completed_urb;
 65	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
 66	int 		i, lens = 0, hwptr_done = subs->hwptr_done;
 67	struct usX2Ydev	*usX2Y = subs->usX2Y;
 68	if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
 69		int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
 70		if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
 71			head = 0;
 72		usX2Y->hwdep_pcm_shm->capture_iso_start = head;
 73		snd_printdd("cap start %i\n", head);
 74	}
 75	for (i = 0; i < nr_of_packs(); i++) {
 76		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
 77			snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
 78			return urb->iso_frame_desc[i].status;
 79		}
 80		lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
 81	}
 82	if ((hwptr_done += lens) >= runtime->buffer_size)
 83		hwptr_done -= runtime->buffer_size;
 84	subs->hwptr_done = hwptr_done;
 85	subs->transfer_done += lens;
 86	/* update the pointer, call callback if necessary */
 87	if (subs->transfer_done >= runtime->period_size) {
 88		subs->transfer_done -= runtime->period_size;
 89		snd_pcm_period_elapsed(subs->pcm_substream);
 90	}
 91	return 0;
 92}
 93
 94static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
 95					      struct usX2Ydev * usX2Y)
 96{
 97	return (runtime->buffer_size * 1000) / usX2Y->rate + 1;	//FIXME: so far only correct period_size == 2^x ?
 98}
 99
100/*
101 * prepare urb for playback data pipe
102 *
103 * we copy the data directly from the pcm buffer.
104 * the current position to be copied is held in hwptr field.
105 * since a urb can handle only a single linear buffer, if the total
106 * transferred area overflows the buffer boundary, we cannot send
107 * it directly from the buffer.  thus the data is once copied to
108 * a temporary buffer and urb points to that.
109 */
110static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
111					struct urb *urb)
112{
113	int count, counts, pack;
114	struct usX2Ydev *usX2Y = subs->usX2Y;
115	struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
116	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
117
118	if (0 > shm->playback_iso_start) {
119		shm->playback_iso_start = shm->captured_iso_head -
120			usX2Y_iso_frames_per_buffer(runtime, usX2Y);
121		if (0 > shm->playback_iso_start)
122			shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
123		shm->playback_iso_head = shm->playback_iso_start;
124	}
125
126	count = 0;
127	for (pack = 0; pack < nr_of_packs(); pack++) {
128		/* calculate the size of a packet */
129		counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
130		if (counts < 43 || counts > 50) {
131			snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
132			return -EPIPE;
133		}
134		/* set up descriptor */
135		urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
136		urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
137		if (atomic_read(&subs->state) != state_RUNNING)
138			memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
139			       urb->iso_frame_desc[pack].length);
140		if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
141			shm->playback_iso_head = 0;
142		count += counts;
143	}
144	urb->transfer_buffer_length = count * usX2Y->stride;
145	return 0;
146}
147
148
149static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
150						     struct urb *urb)
151{
152	int pack;
153	for (pack = 0; pack < nr_of_packs(); ++pack) {
154		struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
155		if (NULL != subs) {
156			struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
157			int head = shm->captured_iso_head + 1;
158			if (head >= ARRAY_SIZE(shm->captured_iso))
159				head = 0;
160			shm->captured_iso[head].frame = urb->start_frame + pack;
161			shm->captured_iso[head].offset = desc->offset;
162			shm->captured_iso[head].length = desc->actual_length;
163			shm->captured_iso_head = head;
164			shm->captured_iso_frames++;
165		}
166		if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
167		    desc->length >= SSS)
168			desc->offset -= (SSS - desc->length);
169	}
170}
171
172static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
173						 struct snd_usX2Y_substream *capsubs2,
174						 struct snd_usX2Y_substream *playbacksubs,
175						 int frame)
176{
177	int err, state;
178	struct urb *urb = playbacksubs->completed_urb;
179
180	state = atomic_read(&playbacksubs->state);
181	if (NULL != urb) {
182		if (state == state_RUNNING)
183			usX2Y_urb_play_retire(playbacksubs, urb);
184		else if (state >= state_PRERUNNING)
185			atomic_inc(&playbacksubs->state);
186	} else {
187		switch (state) {
188		case state_STARTING1:
189			urb = playbacksubs->urb[0];
190			atomic_inc(&playbacksubs->state);
191			break;
192		case state_STARTING2:
193			urb = playbacksubs->urb[1];
194			atomic_inc(&playbacksubs->state);
195			break;
196		}
197	}
198	if (urb) {
199		if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
200		    (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
201			return err;
202		}
203	}
204	
205	playbacksubs->completed_urb = NULL;
206
207	state = atomic_read(&capsubs->state);
208	if (state >= state_PREPARED) {
209		if (state == state_RUNNING) {
210			if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
211				return err;
212		} else if (state >= state_PRERUNNING)
213			atomic_inc(&capsubs->state);
214		usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
215		if (NULL != capsubs2)
216			usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
217		if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
218			return err;
219		if (NULL != capsubs2)
220			if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
221				return err;
222	}
223	capsubs->completed_urb = NULL;
224	if (NULL != capsubs2)
225		capsubs2->completed_urb = NULL;
226	return 0;
227}
228
229
230static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
231{
232	struct snd_usX2Y_substream *subs = urb->context;
233	struct usX2Ydev *usX2Y = subs->usX2Y;
234	struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
235
236	if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
237		snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
238			    usb_get_current_frame_number(usX2Y->dev),
239			    subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
240			    urb->status, urb->start_frame);
241		return;
242	}
243	if (unlikely(urb->status)) {
244		usX2Y_error_urb_status(usX2Y, subs, urb);
245		return;
246	}
247	if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
248		subs->completed_urb = urb;
249	else {
250		usX2Y_error_sequence(usX2Y, subs, urb);
251		return;
252	}
253
254	capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
255	capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
256	playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
257	if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
258	    (NULL == capsubs2 || capsubs2->completed_urb) &&
259	    (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
260		if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
261			usX2Y->wait_iso_frame += nr_of_packs();
262		else {
263			snd_printdd("\n");
264			usX2Y_clients_stop(usX2Y);
265		}
266	}
267}
268
269
270static 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 */
280static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *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
288static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
289{
290	usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
291	usX2Y->prepare_subs = NULL;
292}
293
294static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
295{
296	struct snd_usX2Y_substream *subs = urb->context;
297	struct usX2Ydev *usX2Y = subs->usX2Y;
298	struct snd_usX2Y_substream *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			struct snd_usX2Y_substream *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);
312}
313
314/*
315 * initialize a substream's urbs
316 */
317static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *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->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 */
361static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
362{
363	struct snd_pcm_runtime *runtime = substream->runtime;
364	struct snd_usX2Y_substream *subs = runtime->private_data,
365		*cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
366	mutex_lock(&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		struct snd_usX2Y_substream *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		struct snd_usX2Y_substream *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	mutex_unlock(&subs->usX2Y->prepare_mutex);
396	return snd_pcm_lib_free_pages(substream);
397}
398
399static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
400{
401	struct usX2Ydev * usX2Y = subs->usX2Y;
402	usX2Y->prepare_subs = subs;
403	subs->urb[0]->start_frame = -1;
404	smp_wmb();	// Make sure above modifications are seen by i_usX2Y_subs_startup()
405	usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
406}
407
408static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
409{
410	int	p, u, err,
411		stream = subs->pcm_substream->stream;
412	struct usX2Ydev *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		struct snd_usX2Y_substream *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		struct snd_usX2Y_substream *subs = usX2Y->subs[p];
430		if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
431			goto start;
432	}
433
434 start:
435	usX2Y_usbpcm_subs_startup(subs);
436	for (u = 0; u < NRURBS; u++) {
437		for (p = 0; 3 >= (stream + p); p += 2) {
438			struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
439			if (subs != NULL) {
440				struct urb *urb = subs->urb[u];
441				if (usb_pipein(urb->pipe)) {
442					unsigned long pack;
443					if (0 == u)
444						atomic_set(&subs->state, state_STARTING3);
445					urb->dev = usX2Y->dev;
446					urb->transfer_flags = URB_ISO_ASAP;
447					for (pack = 0; pack < nr_of_packs(); pack++) {
448						urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
449						urb->iso_frame_desc[pack].length = subs->maxpacksize;
450					}
451					urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); 
452					if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
453						snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
454						err = -EPIPE;
455						goto cleanup;
456					}  else {
457						snd_printdd("%i\n", urb->start_frame);
458						if (u == 0)
459							usX2Y->wait_iso_frame = urb->start_frame;
460					}
461					urb->transfer_flags = 0;
462				} else {
463					atomic_set(&subs->state, state_STARTING1);
464					break;
465				}			
466			}
467		}
468	}
469	err = 0;
470	wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
471	if (atomic_read(&subs->state) != state_PREPARED)
472		err = -EPIPE;
473		
474 cleanup:
475	if (err) {
476		usX2Y_subs_startup_finish(usX2Y);	// Call it now
477		usX2Y_clients_stop(usX2Y);		// something is completely wroong > stop evrything			
478	}
479	return err;
480}
481
482/*
483 * prepare callback
484 *
485 * set format and initialize urbs
486 */
487static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
488{
489	struct snd_pcm_runtime *runtime = substream->runtime;
490	struct snd_usX2Y_substream *subs = runtime->private_data;
491	struct usX2Ydev *usX2Y = subs->usX2Y;
492	struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
493	int err = 0;
494	snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
495
496	if (NULL == usX2Y->hwdep_pcm_shm) {
497		if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
498			return -ENOMEM;
499		memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
500	}
501
502	mutex_lock(&usX2Y->prepare_mutex);
503	usX2Y_subs_prepare(subs);
504// Start hardware streams
505// SyncStream first....
506	if (atomic_read(&capsubs->state) < state_PREPARED) {
507		if (usX2Y->format != runtime->format)
508			if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
509				goto up_prepare_mutex;
510		if (usX2Y->rate != runtime->rate)
511			if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
512				goto up_prepare_mutex;
513		snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
514			    "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) >
523			       usX2Y->hwdep_pcm_shm->captured_iso_frames) {
524				snd_printdd("Wait: iso_frames_per_buffer=%i,"
525					    "captured_iso_frames=%i\n",
526					    usX2Y_iso_frames_per_buffer(runtime, usX2Y),
527					    usX2Y->hwdep_pcm_shm->captured_iso_frames);
528				if (msleep_interruptible(10)) {
529					err = -ERESTARTSYS;
530					goto up_prepare_mutex;
531				}
532			} 
533			if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
534				goto up_prepare_mutex;
535		}
536		snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
537			    usX2Y_iso_frames_per_buffer(runtime, usX2Y),
538			    usX2Y->hwdep_pcm_shm->captured_iso_frames);
539	} else
540		usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
541
542 up_prepare_mutex:
543	mutex_unlock(&usX2Y->prepare_mutex);
544	return err;
545}
546
547static struct snd_pcm_hardware snd_usX2Y_4c =
548{
549	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
550				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
551				 SNDRV_PCM_INFO_MMAP_VALID),
552	.formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
553	.rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
554	.rate_min =                44100,
555	.rate_max =                48000,
556	.channels_min =            2,
557	.channels_max =            4,
558	.buffer_bytes_max =	(2*128*1024),
559	.period_bytes_min =	64,
560	.period_bytes_max =	(128*1024),
561	.periods_min =		2,
562	.periods_max =		1024,
563	.fifo_size =              0
564};
565
566
567
568static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
569{
570	struct snd_usX2Y_substream	*subs = ((struct snd_usX2Y_substream **)
571					 snd_pcm_substream_chip(substream))[substream->stream];
572	struct snd_pcm_runtime	*runtime = substream->runtime;
573
574	if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
575		return -EBUSY;
576
577	runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
578		(subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
579	runtime->private_data = subs;
580	subs->pcm_substream = substream;
581	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
582	return 0;
583}
584
585
586static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
587{
588	struct snd_pcm_runtime *runtime = substream->runtime;
589	struct snd_usX2Y_substream *subs = runtime->private_data;
590
591	subs->pcm_substream = NULL;
592	return 0;
593}
594
595
596static struct snd_pcm_ops snd_usX2Y_usbpcm_ops = 
597{
598	.open =		snd_usX2Y_usbpcm_open,
599	.close =	snd_usX2Y_usbpcm_close,
600	.ioctl =	snd_pcm_lib_ioctl,
601	.hw_params =	snd_usX2Y_pcm_hw_params,
602	.hw_free =	snd_usX2Y_usbpcm_hw_free,
603	.prepare =	snd_usX2Y_usbpcm_prepare,
604	.trigger =	snd_usX2Y_pcm_trigger,
605	.pointer =	snd_usX2Y_pcm_pointer,
606};
607
608
609static int usX2Y_pcms_lock_check(struct snd_card *card)
610{
611	struct list_head *list;
612	struct snd_device *dev;
613	struct snd_pcm *pcm;
614	int err = 0;
615	list_for_each(list, &card->devices) {
616		dev = snd_device(list);
617		if (dev->type != SNDRV_DEV_PCM)
618			continue;
619		pcm = dev->device_data;
620		mutex_lock(&pcm->open_mutex);
621	}
622	list_for_each(list, &card->devices) {
623		int s;
624		dev = snd_device(list);
625		if (dev->type != SNDRV_DEV_PCM)
626			continue;
627		pcm = dev->device_data;
628		for (s = 0; s < 2; ++s) {
629			struct snd_pcm_substream *substream;
630			substream = pcm->streams[s].substream;
631			if (substream && SUBSTREAM_BUSY(substream))
632				err = -EBUSY;
633		}
634	}
635	return err;
636}
637
638
639static void usX2Y_pcms_unlock(struct snd_card *card)
640{
641	struct list_head *list;
642	struct snd_device *dev;
643	struct snd_pcm *pcm;
644	list_for_each(list, &card->devices) {
645		dev = snd_device(list);
646		if (dev->type != SNDRV_DEV_PCM)
647			continue;
648		pcm = dev->device_data;
649		mutex_unlock(&pcm->open_mutex);
650	}
651}
652
653
654static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
655{
656	// we need to be the first 
657	struct snd_card *card = hw->card;
658	int err = usX2Y_pcms_lock_check(card);
659	if (0 == err)
660		usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
661	usX2Y_pcms_unlock(card);
662	return err;
663}
664
665
666static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
667{
668	struct snd_card *card = hw->card;
669	int err = usX2Y_pcms_lock_check(card);
670	if (0 == err)
671		usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
672	usX2Y_pcms_unlock(card);
673	return err;
674}
675
676
677static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
678{
679}
680
681
682static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
683{
684}
685
686
687static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
688					struct vm_fault *vmf)
689{
690	unsigned long offset;
691	void *vaddr;
692
693	offset = vmf->pgoff << PAGE_SHIFT;
694	vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
695	vmf->page = virt_to_page(vaddr);
696	get_page(vmf->page);
697	return 0;
698}
699
700
701static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
702	.open = snd_usX2Y_hwdep_pcm_vm_open,
703	.close = snd_usX2Y_hwdep_pcm_vm_close,
704	.fault = snd_usX2Y_hwdep_pcm_vm_fault,
705};
706
707
708static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
709{
710	unsigned long	size = (unsigned long)(area->vm_end - area->vm_start);
711	struct usX2Ydev	*usX2Y = hw->private_data;
712
713	if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
714		return -EBUSY;
715
716	/* if userspace tries to mmap beyond end of our buffer, fail */ 
717	if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
718		snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 
719		return -EINVAL;
720	}
721
722	if (!usX2Y->hwdep_pcm_shm) {
723		return -ENODEV;
724	}
725	area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
726	area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
727	area->vm_private_data = hw->private_data;
728	return 0;
729}
730
731
732static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
733{
734	struct usX2Ydev *usX2Y = hwdep->private_data;
735	if (NULL != usX2Y->hwdep_pcm_shm)
736		snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
737}
738
739
740int usX2Y_hwdep_pcm_new(struct snd_card *card)
741{
742	int err;
743	struct snd_hwdep *hw;
744	struct snd_pcm *pcm;
745	struct usb_device *dev = usX2Y(card)->dev;
746	if (1 != nr_of_packs())
747		return 0;
748
749	if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
750		return err;
751
752	hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
753	hw->private_data = usX2Y(card);
754	hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
755	hw->ops.open = snd_usX2Y_hwdep_pcm_open;
756	hw->ops.release = snd_usX2Y_hwdep_pcm_release;
757	hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
758	hw->exclusive = 1;
759	sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
760
761	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
762	if (err < 0) {
763		return err;
764	}
765	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
766	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
767
768	pcm->private_data = usX2Y(card)->subs;
769	pcm->info_flags = 0;
770
771	sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
772	if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
773						     SNDRV_DMA_TYPE_CONTINUOUS,
774						     snd_dma_continuous_data(GFP_KERNEL),
775						     64*1024, 128*1024)) ||
776	    0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
777	    					     SNDRV_DMA_TYPE_CONTINUOUS,
778	    					     snd_dma_continuous_data(GFP_KERNEL),
779						     64*1024, 128*1024))) {
780		return err;
781	}
782
783
784	return 0;
785}
786
787#else
788
789int usX2Y_hwdep_pcm_new(struct snd_card *card)
790{
791	return 0;
792}
793
794#endif