| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  |  *   Copyright (c) 2006-2008 Daniel Mack, Karsten Wiese | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  *   This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *   the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  *   (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *   GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *   along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | #include <linux/device.h>
 | 
					
						
							| 
									
										
										
										
											2009-03-28 21:19:49 +01:00
										 |  |  | #include <linux/spinlock.h>
 | 
					
						
							| 
									
										
											  
											
												include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
  http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.
2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).
   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
											
										 
											2010-03-24 17:04:11 +09:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/usb.h>
 | 
					
						
							|  |  |  | #include <sound/core.h>
 | 
					
						
							|  |  |  | #include <sound/pcm.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 19:05:39 +02:00
										 |  |  | #include "device.h"
 | 
					
						
							|  |  |  | #include "audio.h"
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define N_URBS			32
 | 
					
						
							|  |  |  | #define CLOCK_DRIFT_TOLERANCE	5
 | 
					
						
							|  |  |  | #define FRAMES_PER_URB		8
 | 
					
						
							|  |  |  | #define BYTES_PER_FRAME		512
 | 
					
						
							|  |  |  | #define CHANNELS_PER_STREAM	2
 | 
					
						
							|  |  |  | #define BYTES_PER_SAMPLE	3
 | 
					
						
							|  |  |  | #define BYTES_PER_SAMPLE_USB	4
 | 
					
						
							|  |  |  | #define MAX_BUFFER_SIZE		(128*1024)
 | 
					
						
							| 
									
										
										
										
											2008-04-14 15:40:31 +02:00
										 |  |  | #define MAX_ENDPOINT_SIZE	512
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | #define ENDPOINT_CAPTURE	2
 | 
					
						
							|  |  |  | #define ENDPOINT_PLAYBACK	6
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | #define MAKE_CHECKBYTE(cdev,stream,i) \
 | 
					
						
							|  |  |  | 	(stream << 1) | (~(i / (cdev->n_streams * BYTES_PER_SAMPLE_USB)) & 1) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 	.info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			   SNDRV_PCM_INFO_BLOCK_TRANSFER), | 
					
						
							|  |  |  | 	.formats 	= SNDRV_PCM_FMTBIT_S24_3BE, | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 	.rates 		= (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			   SNDRV_PCM_RATE_96000), | 
					
						
							|  |  |  | 	.rate_min	= 44100, | 
					
						
							|  |  |  | 	.rate_max	= 0, /* will overwrite later */ | 
					
						
							|  |  |  | 	.channels_min	= CHANNELS_PER_STREAM, | 
					
						
							|  |  |  | 	.channels_max	= CHANNELS_PER_STREAM, | 
					
						
							|  |  |  | 	.buffer_bytes_max = MAX_BUFFER_SIZE, | 
					
						
							| 
									
										
										
										
											2008-01-24 18:46:42 +01:00
										 |  |  | 	.period_bytes_min = 128, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	.period_bytes_max = MAX_BUFFER_SIZE, | 
					
						
							|  |  |  | 	.periods_min	= 1, | 
					
						
							|  |  |  | 	.periods_max	= 1024, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | activate_substream(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	           struct snd_pcm_substream *sub) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	spin_lock(&cdev->spinlock); | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->sub_playback[sub->number] = sub; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->sub_capture[sub->number] = sub; | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	spin_unlock(&cdev->spinlock); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | deactivate_substream(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		     struct snd_pcm_substream *sub) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 	unsigned long flags; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	spin_lock_irqsave(&cdev->spinlock, flags); | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->sub_playback[sub->number] = NULL; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->sub_capture[sub->number] = NULL; | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	spin_unlock_irqrestore(&cdev->spinlock, flags); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | all_substreams_zero(struct snd_pcm_substream **subs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	for (i = 0; i < MAX_STREAMS; i++) | 
					
						
							|  |  |  | 		if (subs[i] != NULL) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static int stream_start(struct snd_usb_caiaqdev *cdev) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i, ret; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev_dbg(dev, "%s(%p)\n", __func__, cdev); | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (cdev->streaming) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback)); | 
					
						
							|  |  |  | 	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture)); | 
					
						
							|  |  |  | 	cdev->input_panic = 0; | 
					
						
							|  |  |  | 	cdev->output_panic = 0; | 
					
						
							|  |  |  | 	cdev->first_packet = 4; | 
					
						
							|  |  |  | 	cdev->streaming = 1; | 
					
						
							|  |  |  | 	cdev->warned = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < N_URBS; i++) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		ret = usb_submit_urb(cdev->data_urbs_in[i], GFP_ATOMIC); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		if (ret) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 			dev_err(dev, "unable to trigger read #%d! (ret %d)\n", | 
					
						
							|  |  |  | 				i, ret); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 			cdev->streaming = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			return -EPIPE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void stream_stop(struct snd_usb_caiaqdev *cdev) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev_dbg(dev, "%s(%p)\n", __func__, cdev); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (!cdev->streaming) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->streaming = 0; | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	for (i = 0; i < N_URBS; i++) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		usb_kill_urb(cdev->data_urbs_in[i]); | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		if (test_bit(i, &cdev->outurb_active_mask)) | 
					
						
							|  |  |  | 			usb_kill_urb(cdev->data_urbs_out[i]); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->outurb_active_mask = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(dev, "%s(%p)\n", __func__, substream); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	substream->runtime->hw = cdev->pcm_info; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	snd_pcm_limit_hw_rates(substream->runtime); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev_dbg(dev, "%s(%p)\n", __func__, substream); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (all_substreams_zero(cdev->sub_playback) && | 
					
						
							|  |  |  | 	    all_substreams_zero(cdev->sub_capture)) { | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 		/* when the last client has stopped streaming,
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		 * all sample rates are allowed again */ | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		stream_stop(cdev); | 
					
						
							|  |  |  | 		cdev->pcm_info.rates = cdev->samplerates; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				       struct snd_pcm_hw_params *hw_params) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-21 13:11:49 +02:00
										 |  |  | 	return snd_pcm_lib_alloc_vmalloc_buffer(sub, | 
					
						
							|  |  |  | 						params_buffer_bytes(hw_params)); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); | 
					
						
							|  |  |  | 	deactivate_substream(cdev, sub); | 
					
						
							| 
									
										
										
										
											2013-06-21 13:11:49 +02:00
										 |  |  | 	return snd_pcm_lib_free_vmalloc_buffer(sub); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* this should probably go upstream */ | 
					
						
							|  |  |  | #if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
 | 
					
						
							|  |  |  | #error "Change this table"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				48000, 64000, 88200, 96000, 176400, 192000 }; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int bytes_per_sample, bpp, ret, i; | 
					
						
							|  |  |  | 	int index = substream->number; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	struct snd_pcm_runtime *runtime = substream->runtime; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev_dbg(dev, "%s(%p)\n", __func__, substream); | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-27 12:18:05 +02:00
										 |  |  | 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		int out_pos; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		switch (cdev->spec.data_alignment) { | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		case 0: | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			out_pos = BYTES_PER_SAMPLE + 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 3: | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			out_pos = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->period_out_count[index] = out_pos; | 
					
						
							|  |  |  | 		cdev->audio_out_buf_pos[index] = out_pos; | 
					
						
							| 
									
										
										
										
											2009-04-27 12:18:05 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		int in_pos; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		switch (cdev->spec.data_alignment) { | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		case 0: | 
					
						
							|  |  |  | 			in_pos = BYTES_PER_SAMPLE + 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			in_pos = BYTES_PER_SAMPLE; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 3: | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			in_pos = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->period_in_count[index] = in_pos; | 
					
						
							|  |  |  | 		cdev->audio_in_buf_pos[index] = in_pos; | 
					
						
							| 
									
										
										
										
											2009-04-27 12:18:05 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (cdev->streaming) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	/* the first client that opens a stream defines the sample rate
 | 
					
						
							|  |  |  | 	 * setting for all subsequent calls, until the last client closed. */ | 
					
						
							|  |  |  | 	for (i=0; i < ARRAY_SIZE(rates); i++) | 
					
						
							|  |  |  | 		if (runtime->rate == rates[i]) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 			cdev->pcm_info.rates = 1 << i; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	snd_pcm_limit_hw_rates(runtime); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bytes_per_sample = BYTES_PER_SAMPLE; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (cdev->spec.data_alignment >= 2) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		bytes_per_sample++; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		* bytes_per_sample * CHANNELS_PER_STREAM * cdev->n_streams; | 
					
						
							| 
									
										
										
										
											2008-04-14 15:40:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (bpp > MAX_ENDPOINT_SIZE) | 
					
						
							|  |  |  | 		bpp = MAX_ENDPOINT_SIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	ret = snd_usb_caiaq_set_audio_params(cdev, runtime->rate, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 					     runtime->sample_bits, bpp); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	ret = stream_start(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->output_running = 0; | 
					
						
							|  |  |  | 	wait_event_timeout(cdev->prepare_wait_queue, cdev->output_running, HZ); | 
					
						
							|  |  |  | 	if (!cdev->output_running) { | 
					
						
							|  |  |  | 		stream_stop(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return -EPIPE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev_dbg(dev, "%s(%p) cmd %d\n", __func__, sub, cmd); | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_START: | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		activate_substream(cdev, sub); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_STOP: | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		deactivate_substream(cdev, sub); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static snd_pcm_uframes_t | 
					
						
							|  |  |  | snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int index = sub->number; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:35 +01:00
										 |  |  | 	snd_pcm_uframes_t ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	spin_lock(&cdev->spinlock); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (cdev->input_panic || cdev->output_panic) { | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:35 +01:00
										 |  |  | 		ptr = SNDRV_PCM_POS_XRUN; | 
					
						
							| 
									
										
										
										
											2012-02-21 21:26:31 +00:00
										 |  |  | 		goto unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:35 +01:00
										 |  |  | 		ptr = bytes_to_frames(sub->runtime, | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->audio_out_buf_pos[index]); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:35 +01:00
										 |  |  | 		ptr = bytes_to_frames(sub->runtime, | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->audio_in_buf_pos[index]); | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-21 21:26:31 +00:00
										 |  |  | unlock: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	spin_unlock(&cdev->spinlock); | 
					
						
							| 
									
										
										
										
											2009-10-24 12:59:35 +01:00
										 |  |  | 	return ptr; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* operators for both playback and capture */ | 
					
						
							|  |  |  | static struct snd_pcm_ops snd_usb_caiaq_ops = { | 
					
						
							|  |  |  | 	.open =		snd_usb_caiaq_substream_open, | 
					
						
							|  |  |  | 	.close =	snd_usb_caiaq_substream_close, | 
					
						
							|  |  |  | 	.ioctl =	snd_pcm_lib_ioctl, | 
					
						
							|  |  |  | 	.hw_params =	snd_usb_caiaq_pcm_hw_params, | 
					
						
							|  |  |  | 	.hw_free =	snd_usb_caiaq_pcm_hw_free, | 
					
						
							|  |  |  | 	.prepare =	snd_usb_caiaq_pcm_prepare, | 
					
						
							|  |  |  | 	.trigger =	snd_usb_caiaq_pcm_trigger, | 
					
						
							| 
									
										
										
										
											2013-06-21 13:11:49 +02:00
										 |  |  | 	.pointer =	snd_usb_caiaq_pcm_pointer, | 
					
						
							|  |  |  | 	.page =		snd_pcm_lib_get_vmalloc_page, | 
					
						
							|  |  |  | 	.mmap =		snd_pcm_lib_mmap_vmalloc, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				      struct snd_pcm_substream **subs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int stream, pb, *cnt; | 
					
						
							|  |  |  | 	struct snd_pcm_substream *sub; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	for (stream = 0; stream < cdev->n_streams; stream++) { | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		sub = subs[stream]; | 
					
						
							|  |  |  | 		if (!sub) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-27 12:18:05 +02:00
										 |  |  | 		pb = snd_pcm_lib_period_bytes(sub); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					&cdev->period_out_count[stream] : | 
					
						
							|  |  |  | 					&cdev->period_in_count[stream]; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (*cnt >= pb) { | 
					
						
							|  |  |  | 			snd_pcm_period_elapsed(sub); | 
					
						
							|  |  |  | 			*cnt %= pb; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void read_in_urb_mode0(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			      const struct urb *urb, | 
					
						
							|  |  |  | 			      const struct usb_iso_packet_descriptor *iso) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
					
						
							|  |  |  | 	struct snd_pcm_substream *sub; | 
					
						
							|  |  |  | 	int stream, i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (all_substreams_zero(cdev->sub_capture)) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < iso->actual_length;) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		for (stream = 0; stream < cdev->n_streams; stream++, i++) { | 
					
						
							|  |  |  | 			sub = cdev->sub_capture[stream]; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			if (sub) { | 
					
						
							|  |  |  | 				struct snd_pcm_runtime *rt = sub->runtime; | 
					
						
							|  |  |  | 				char *audio_buf = rt->dma_area; | 
					
						
							|  |  |  | 				int sz = frames_to_bytes(rt, rt->buffer_size); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				audio_buf[cdev->audio_in_buf_pos[stream]++] | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 					= usb_buf[i]; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				cdev->period_in_count[stream]++; | 
					
						
							|  |  |  | 				if (cdev->audio_in_buf_pos[stream] == sz) | 
					
						
							|  |  |  | 					cdev->audio_in_buf_pos[stream] = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void read_in_urb_mode2(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			      const struct urb *urb, | 
					
						
							|  |  |  | 			      const struct usb_iso_packet_descriptor *iso) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
					
						
							|  |  |  | 	unsigned char check_byte; | 
					
						
							|  |  |  | 	struct snd_pcm_substream *sub; | 
					
						
							|  |  |  | 	int stream, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < iso->actual_length;) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		if (i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 			for (stream = 0; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 			     stream < cdev->n_streams; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			     stream++, i++) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				if (cdev->first_packet) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 					continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				check_byte = MAKE_CHECKBYTE(cdev, stream, i); | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				if ((usb_buf[i] & 0x3f) != check_byte) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->input_panic = 1; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (usb_buf[i] & 0x80) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->output_panic = 1; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->first_packet = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		for (stream = 0; stream < cdev->n_streams; stream++, i++) { | 
					
						
							|  |  |  | 			sub = cdev->sub_capture[stream]; | 
					
						
							|  |  |  | 			if (cdev->input_panic) | 
					
						
							| 
									
										
										
										
											2009-03-18 11:03:54 +01:00
										 |  |  | 				usb_buf[i] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			if (sub) { | 
					
						
							|  |  |  | 				struct snd_pcm_runtime *rt = sub->runtime; | 
					
						
							|  |  |  | 				char *audio_buf = rt->dma_area; | 
					
						
							|  |  |  | 				int sz = frames_to_bytes(rt, rt->buffer_size); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				audio_buf[cdev->audio_in_buf_pos[stream]++] = | 
					
						
							| 
									
										
										
										
											2007-03-29 17:02:45 +02:00
										 |  |  | 					usb_buf[i]; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				cdev->period_in_count[stream]++; | 
					
						
							|  |  |  | 				if (cdev->audio_in_buf_pos[stream] == sz) | 
					
						
							|  |  |  | 					cdev->audio_in_buf_pos[stream] = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void read_in_urb_mode3(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 			      const struct urb *urb, | 
					
						
							|  |  |  | 			      const struct usb_iso_packet_descriptor *iso) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 	int stream, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* paranoia check */ | 
					
						
							|  |  |  | 	if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < iso->actual_length;) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		for (stream = 0; stream < cdev->n_streams; stream++) { | 
					
						
							|  |  |  | 			struct snd_pcm_substream *sub = cdev->sub_capture[stream]; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 			char *audio_buf = NULL; | 
					
						
							|  |  |  | 			int c, n, sz = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 			if (sub && !cdev->input_panic) { | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				struct snd_pcm_runtime *rt = sub->runtime; | 
					
						
							|  |  |  | 				audio_buf = rt->dma_area; | 
					
						
							|  |  |  | 				sz = frames_to_bytes(rt, rt->buffer_size); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (c = 0; c < CHANNELS_PER_STREAM; c++) { | 
					
						
							|  |  |  | 				/* 3 audio data bytes, followed by 1 check byte */ | 
					
						
							|  |  |  | 				if (audio_buf) { | 
					
						
							|  |  |  | 					for (n = 0; n < BYTES_PER_SAMPLE; n++) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 						audio_buf[cdev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 						if (cdev->audio_in_buf_pos[stream] == sz) | 
					
						
							|  |  |  | 							cdev->audio_in_buf_pos[stream] = 0; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->period_in_count[stream] += BYTES_PER_SAMPLE; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				i += BYTES_PER_SAMPLE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (usb_buf[i] != ((stream << 1) | c) && | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				    !cdev->first_packet) { | 
					
						
							|  |  |  | 					if (!cdev->input_panic) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 						dev_warn(dev, " EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", | 
					
						
							|  |  |  | 							 ((stream << 1) | c), usb_buf[i], c, stream, i); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->input_panic = 1; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				i++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (cdev->first_packet > 0) | 
					
						
							|  |  |  | 		cdev->first_packet--; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void read_in_urb(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			const struct urb *urb, | 
					
						
							|  |  |  | 			const struct usb_iso_packet_descriptor *iso) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (!cdev->streaming) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (iso->actual_length < cdev->bpp) | 
					
						
							| 
									
										
										
										
											2009-03-18 11:03:54 +01:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	switch (cdev->spec.data_alignment) { | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	case 0: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		read_in_urb_mode0(cdev, urb, iso); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case 2: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		read_in_urb_mode2(cdev, urb, iso); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 	case 3: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		read_in_urb_mode3(cdev, urb, iso); | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if ((cdev->input_panic || cdev->output_panic) && !cdev->warned) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 		dev_warn(dev, "streaming error detected %s %s\n", | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 				cdev->input_panic ? "(input)" : "", | 
					
						
							|  |  |  | 				cdev->output_panic ? "(output)" : ""); | 
					
						
							|  |  |  | 		cdev->warned = 1; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				struct urb *urb, | 
					
						
							|  |  |  | 				const struct usb_iso_packet_descriptor *iso) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
					
						
							|  |  |  | 	struct snd_pcm_substream *sub; | 
					
						
							|  |  |  | 	int stream, i; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	for (i = 0; i < iso->length;) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		for (stream = 0; stream < cdev->n_streams; stream++, i++) { | 
					
						
							|  |  |  | 			sub = cdev->sub_playback[stream]; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			if (sub) { | 
					
						
							|  |  |  | 				struct snd_pcm_runtime *rt = sub->runtime; | 
					
						
							|  |  |  | 				char *audio_buf = rt->dma_area; | 
					
						
							|  |  |  | 				int sz = frames_to_bytes(rt, rt->buffer_size); | 
					
						
							| 
									
										
										
										
											2007-03-29 17:02:45 +02:00
										 |  |  | 				usb_buf[i] = | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					audio_buf[cdev->audio_out_buf_pos[stream]]; | 
					
						
							|  |  |  | 				cdev->period_out_count[stream]++; | 
					
						
							|  |  |  | 				cdev->audio_out_buf_pos[stream]++; | 
					
						
							|  |  |  | 				if (cdev->audio_out_buf_pos[stream] == sz) | 
					
						
							|  |  |  | 					cdev->audio_out_buf_pos[stream] = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			} else | 
					
						
							| 
									
										
										
										
											2007-03-29 17:02:45 +02:00
										 |  |  | 				usb_buf[i] = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* fill in the check bytes */ | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		if (cdev->spec.data_alignment == 2 && | 
					
						
							|  |  |  | 		    i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == | 
					
						
							|  |  |  | 		        (cdev->n_streams * CHANNELS_PER_STREAM)) | 
					
						
							|  |  |  | 			for (stream = 0; stream < cdev->n_streams; stream++, i++) | 
					
						
							|  |  |  | 				usb_buf[i] = MAKE_CHECKBYTE(cdev, stream, i); | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				struct urb *urb, | 
					
						
							|  |  |  | 				const struct usb_iso_packet_descriptor *iso) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
					
						
							|  |  |  | 	int stream, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < iso->length;) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		for (stream = 0; stream < cdev->n_streams; stream++) { | 
					
						
							|  |  |  | 			struct snd_pcm_substream *sub = cdev->sub_playback[stream]; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 			char *audio_buf = NULL; | 
					
						
							|  |  |  | 			int c, n, sz = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (sub) { | 
					
						
							|  |  |  | 				struct snd_pcm_runtime *rt = sub->runtime; | 
					
						
							|  |  |  | 				audio_buf = rt->dma_area; | 
					
						
							|  |  |  | 				sz = frames_to_bytes(rt, rt->buffer_size); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (c = 0; c < CHANNELS_PER_STREAM; c++) { | 
					
						
							|  |  |  | 				for (n = 0; n < BYTES_PER_SAMPLE; n++) { | 
					
						
							|  |  |  | 					if (audio_buf) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 						usb_buf[i+n] = audio_buf[cdev->audio_out_buf_pos[stream]++]; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 						if (cdev->audio_out_buf_pos[stream] == sz) | 
					
						
							|  |  |  | 							cdev->audio_out_buf_pos[stream] = 0; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 					} else { | 
					
						
							|  |  |  | 						usb_buf[i+n] = 0; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (audio_buf) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 					cdev->period_out_count[stream] += BYTES_PER_SAMPLE; | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				i += BYTES_PER_SAMPLE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* fill in the check byte pattern */ | 
					
						
							|  |  |  | 				usb_buf[i++] = (stream << 1) | c; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static inline void fill_out_urb(struct snd_usb_caiaqdev *cdev, | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 				struct urb *urb, | 
					
						
							|  |  |  | 				const struct usb_iso_packet_descriptor *iso) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	switch (cdev->spec.data_alignment) { | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 	case 0: | 
					
						
							|  |  |  | 	case 2: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		fill_out_urb_mode_0(cdev, urb, iso); | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case 3: | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		fill_out_urb_mode_3(cdev, urb, iso); | 
					
						
							| 
									
										
										
										
											2010-09-10 17:04:57 +08:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void read_completed(struct urb *urb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 	struct snd_usb_caiaq_cb_info *info = urb->context; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev; | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 	struct urb *out = NULL; | 
					
						
							|  |  |  | 	int i, frame, len, send_it = 0, outframe = 0; | 
					
						
							| 
									
										
										
										
											2011-08-05 13:49:52 +02:00
										 |  |  | 	size_t offset = 0; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (urb->status || !info) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev = info->cdev; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2008-04-14 15:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (!cdev->streaming) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 	/* find an unused output urb that is unused */ | 
					
						
							|  |  |  | 	for (i = 0; i < N_URBS; i++) | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		if (test_and_set_bit(i, &cdev->outurb_active_mask) == 0) { | 
					
						
							|  |  |  | 			out = cdev->data_urbs_out[i]; | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!out) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 		dev_err(dev, "Unable to find an output urb to use\n"); | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 		goto requeue; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* read the recently received packet and send back one which has
 | 
					
						
							|  |  |  | 	 * the same layout */ | 
					
						
							|  |  |  | 	for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 
					
						
							|  |  |  | 		if (urb->iso_frame_desc[frame].status) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		len = urb->iso_frame_desc[outframe].actual_length; | 
					
						
							|  |  |  | 		out->iso_frame_desc[outframe].length = len; | 
					
						
							|  |  |  | 		out->iso_frame_desc[outframe].actual_length = 0; | 
					
						
							| 
									
										
										
										
											2011-08-05 13:49:52 +02:00
										 |  |  | 		out->iso_frame_desc[outframe].offset = offset; | 
					
						
							|  |  |  | 		offset += len; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		if (len > 0) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 			spin_lock(&cdev->spinlock); | 
					
						
							|  |  |  | 			fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]); | 
					
						
							|  |  |  | 			read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]); | 
					
						
							|  |  |  | 			spin_unlock(&cdev->spinlock); | 
					
						
							|  |  |  | 			check_for_elapsed_periods(cdev, cdev->sub_playback); | 
					
						
							|  |  |  | 			check_for_elapsed_periods(cdev, cdev->sub_capture); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			send_it = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		outframe++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (send_it) { | 
					
						
							| 
									
										
										
										
											2011-08-05 13:49:52 +02:00
										 |  |  | 		out->number_of_packets = outframe; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		usb_submit_urb(out, GFP_ATOMIC); | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		struct snd_usb_caiaq_cb_info *oinfo = out->context; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		clear_bit(oinfo->index, &cdev->outurb_active_mask); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | requeue: | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	/* re-submit inbound urb */ | 
					
						
							|  |  |  | 	for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 
					
						
							|  |  |  | 		urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; | 
					
						
							|  |  |  | 		urb->iso_frame_desc[frame].length = BYTES_PER_FRAME; | 
					
						
							|  |  |  | 		urb->iso_frame_desc[frame].actual_length = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	urb->number_of_packets = FRAMES_PER_URB; | 
					
						
							|  |  |  | 	usb_submit_urb(urb, GFP_ATOMIC); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void write_completed(struct urb *urb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct snd_usb_caiaq_cb_info *info = urb->context; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct snd_usb_caiaqdev *cdev = info->cdev; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (!cdev->output_running) { | 
					
						
							|  |  |  | 		cdev->output_running = 1; | 
					
						
							|  |  |  | 		wake_up(&cdev->prepare_wait_queue); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	clear_bit(info->index, &cdev->outurb_active_mask); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | static struct urb **alloc_urbs(struct snd_usb_caiaqdev *cdev, int dir, int *ret) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i, frame; | 
					
						
							|  |  |  | 	struct urb **urbs; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	struct usb_device *usb_dev = cdev->chip.dev; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	unsigned int pipe; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) : | 
					
						
							|  |  |  | 		usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!urbs) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 		dev_err(dev, "unable to kmalloc() urbs, OOM!?\n"); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		*ret = -ENOMEM; | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < N_URBS; i++) { | 
					
						
							|  |  |  | 		urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL); | 
					
						
							|  |  |  | 		if (!urbs[i]) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 			dev_err(dev, "unable to usb_alloc_urb(), OOM!?\n"); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			*ret = -ENOMEM; | 
					
						
							|  |  |  | 			return urbs; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 		urbs[i]->transfer_buffer = | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL); | 
					
						
							|  |  |  | 		if (!urbs[i]->transfer_buffer) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 			dev_err(dev, "unable to kmalloc() transfer buffer, OOM!?\n"); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			*ret = -ENOMEM; | 
					
						
							|  |  |  | 			return urbs; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 			struct usb_iso_packet_descriptor *iso = | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				&urbs[i]->iso_frame_desc[frame]; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			iso->offset = BYTES_PER_FRAME * frame; | 
					
						
							|  |  |  | 			iso->length = BYTES_PER_FRAME; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		urbs[i]->dev = usb_dev; | 
					
						
							|  |  |  | 		urbs[i]->pipe = pipe; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 		urbs[i]->transfer_buffer_length = FRAMES_PER_URB | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 						* BYTES_PER_FRAME; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		urbs[i]->context = &cdev->data_cb_info[i]; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		urbs[i]->interval = 1; | 
					
						
							|  |  |  | 		urbs[i]->number_of_packets = FRAMES_PER_URB; | 
					
						
							|  |  |  | 		urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ? | 
					
						
							|  |  |  | 					read_completed : write_completed; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*ret = 0; | 
					
						
							|  |  |  | 	return urbs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void free_urbs(struct urb **urbs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!urbs) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < N_URBS; i++) { | 
					
						
							|  |  |  | 		if (!urbs[i]) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		usb_kill_urb(urbs[i]); | 
					
						
							|  |  |  | 		kfree(urbs[i]->transfer_buffer); | 
					
						
							|  |  |  | 		usb_free_urb(urbs[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(urbs); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i, ret; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->n_audio_in  = max(cdev->spec.num_analog_audio_in, | 
					
						
							|  |  |  | 			       cdev->spec.num_digital_audio_in) / | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				CHANNELS_PER_STREAM; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->n_audio_out = max(cdev->spec.num_analog_audio_out, | 
					
						
							|  |  |  | 			       cdev->spec.num_digital_audio_out) / | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				CHANNELS_PER_STREAM; | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->n_streams = max(cdev->n_audio_in, cdev->n_audio_out); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	dev_dbg(dev, "cdev->n_audio_in = %d\n", cdev->n_audio_in); | 
					
						
							|  |  |  | 	dev_dbg(dev, "cdev->n_audio_out = %d\n", cdev->n_audio_out); | 
					
						
							|  |  |  | 	dev_dbg(dev, "cdev->n_streams = %d\n", cdev->n_streams); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (cdev->n_streams > MAX_STREAMS) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 		dev_err(dev, "unable to initialize device, too many streams.\n"); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-07 14:25:13 +02:00
										 |  |  | 	if (cdev->n_streams < 2) { | 
					
						
							|  |  |  | 		dev_err(dev, "bogus number of streams: %d\n", cdev->n_streams); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0, | 
					
						
							|  |  |  | 			cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 		dev_err(dev, "snd_pcm_new() returned %d\n", ret); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->pcm->private_data = cdev; | 
					
						
							|  |  |  | 	strlcpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name)); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback)); | 
					
						
							|  |  |  | 	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture)); | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	memcpy(&cdev->pcm_info, &snd_usb_caiaq_pcm_hardware, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 			sizeof(snd_usb_caiaq_pcm_hardware)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* setup samplerates */ | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->samplerates = cdev->pcm_info.rates; | 
					
						
							|  |  |  | 	switch (cdev->chip.usb_id) { | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | 
					
						
							| 
									
										
										
										
											2007-09-17 14:45:14 +02:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 
					
						
							| 
									
										
										
										
											2008-05-08 15:42:15 +02:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO): | 
					
						
							| 
									
										
										
										
											2009-01-16 11:03:19 +01:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE): | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->samplerates |= SNDRV_PCM_RATE_192000; | 
					
						
							| 
									
										
										
										
											2009-01-16 11:03:19 +01:00
										 |  |  | 		/* fall thru */ | 
					
						
							| 
									
										
										
										
											2009-07-22 14:13:35 +02:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ): | 
					
						
							| 
									
										
										
										
											2009-01-16 11:03:19 +01:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): | 
					
						
							| 
									
										
										
										
											2010-09-01 16:23:46 +08:00
										 |  |  | 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2): | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->samplerates |= SNDRV_PCM_RATE_88200; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				&snd_usb_caiaq_ops); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 				&snd_usb_caiaq_ops); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->data_cb_info = | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 		kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 					GFP_KERNEL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	if (!cdev->data_cb_info) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->outurb_active_mask = 0; | 
					
						
							|  |  |  | 	BUILD_BUG_ON(N_URBS > (sizeof(cdev->outurb_active_mask) * 8)); | 
					
						
							| 
									
										
										
										
											2011-08-14 11:31:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	for (i = 0; i < N_URBS; i++) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		cdev->data_cb_info[i].cdev = cdev; | 
					
						
							|  |  |  | 		cdev->data_cb_info[i].index = i; | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->data_urbs_in = alloc_urbs(cdev, SNDRV_PCM_STREAM_CAPTURE, &ret); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	if (ret < 0) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		kfree(cdev->data_cb_info); | 
					
						
							|  |  |  | 		free_urbs(cdev->data_urbs_in); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-01 21:36:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	cdev->data_urbs_out = alloc_urbs(cdev, SNDRV_PCM_STREAM_PLAYBACK, &ret); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 	if (ret < 0) { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 		kfree(cdev->data_cb_info); | 
					
						
							|  |  |  | 		free_urbs(cdev->data_urbs_in); | 
					
						
							|  |  |  | 		free_urbs(cdev->data_urbs_out); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:22 +01:00
										 |  |  | 	struct device *dev = caiaqdev_to_dev(cdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(dev, "%s(%p)\n", __func__, cdev); | 
					
						
							| 
									
										
										
										
											2013-03-03 20:46:21 +01:00
										 |  |  | 	stream_stop(cdev); | 
					
						
							|  |  |  | 	free_urbs(cdev->data_urbs_in); | 
					
						
							|  |  |  | 	free_urbs(cdev->data_urbs_out); | 
					
						
							|  |  |  | 	kfree(cdev->data_cb_info); | 
					
						
							| 
									
										
										
										
											2007-03-26 19:11:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 |