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