summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 08:51:59 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 08:51:59 -0800
commita323ae93a74f669d890926187c68c711895e3454 (patch)
tree9a4ab8ed7bb98dc4321606332a883834ef7c8f6f /drivers
parent3e63430a5cc26bc90a6e33ab33f901196b7b63ac (diff)
parent0e806151e86be52caa1349fa490eab8f09a2b6f5 (diff)
Merge tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "In this batch, you can find lots of cleanups through the whole subsystem, as our good New Year's resolution. Lots of LOCs and commits are about LINE6 driver that was promoted finally from staging tree, and as usual, there've been widely spread ASoC changes. Here some highlights: ALSA core changes - Embedding struct device into ALSA core structures - sequencer core cleanups / fixes - PCM msbits constraints cleanups / fixes - New SNDRV_PCM_TRIGGER_DRAIN command - PCM kerneldoc fixes, header cleanups - PCM code cleanups using more standard codes - Control notification ID fixes Driver cleanups - Cleanups of PCI PM callbacks - Timer helper usages cleanups - Simplification (e.g. argument reduction) of many driver codes HD-audio - Hotkey and LED support on HP laptops with Realtek codecs - Dock station support on HP laptops - Toshiba Satellite S50D fixup - Enhanced wallclock timestamp handling for HD-audio - Componentization to simplify the linkage between i915 and hd-audio drivers for Intel HDMI/DP USB-audio - Akai MPC Element support - Enhanced timestamp handling ASoC - Lots of refactoringin ASoC core, moving drivers to more data driven initialization and rationalizing a lot of DAPM usage - Much improved handling of CDCLK clocks on Samsung I2S controllers - Lots of driver specific cleanups and feature improvements - CODEC support for TI PCM514x and TLV320AIC3104 devices - Board support for Tegra systems with Realtek RT5677 - New driver for Maxim max98357a - More enhancements / fixes for Intel SST driver Others - Promotion of LINE6 driver from staging along with lots of rewrites and cleanups - DT support for old non-ASoC atmel driver - oxygen cleanups, XIO2001 init, Studio Evolution SE6x support - Emu8000 DRAM size detection fix on ISA(!!) AWE64 boards - A few more ak411x fixes for ice1724 boards" * tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (542 commits) ALSA: line6: toneport: Use explicit type for firmware version ALSA: line6: Use explicit type for serial number ALSA: line6: Return EIO if read/write not successful ALSA: line6: Return error if device not responding ALSA: line6: Add delay before reading status ASoC: Intel: Clean data after SST fw fetch ALSA: hda - Add docking station support for another HP machine ALSA: control: fix failure to return new numerical ID in 'replace' event data ALSA: usb: update trigger timestamp on first non-zero URB submitted ALSA: hda: read trigger_timestamp immediately after starting DMA ALSA: pcm: allow for trigger_tstamp snapshot in .trigger ALSA: pcm: don't override timestamp unconditionally ALSA: off by one bug in snd_riptide_joystick_probe() ASoC: rt5670: Set use_single_rw flag for regmap ASoC: rt286: Add rt288 codec support ASoC: max98357a: Fix build in !CONFIG_OF case ASoC: Intel: fix platform_no_drv_owner.cocci warnings ARM: dts: Switch Odroid X2/U2 to simple-audio-card ARM: dts: Exynos4 and Odroid X2/U3 sound device nodes update ALSA: control: fix failure to return numerical ID in 'add' event ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c9
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h8
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c110
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c56
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/line6/Kconfig38
-rw-r--r--drivers/staging/line6/Makefile14
-rw-r--r--drivers/staging/line6/audio.c71
-rw-r--r--drivers/staging/line6/audio.h21
-rw-r--r--drivers/staging/line6/capture.c432
-rw-r--r--drivers/staging/line6/capture.h35
-rw-r--r--drivers/staging/line6/driver.c1162
-rw-r--r--drivers/staging/line6/driver.h215
-rw-r--r--drivers/staging/line6/midi.c321
-rw-r--r--drivers/staging/line6/midi.h72
-rw-r--r--drivers/staging/line6/midibuf.c270
-rw-r--r--drivers/staging/line6/midibuf.h38
-rw-r--r--drivers/staging/line6/pcm.c576
-rw-r--r--drivers/staging/line6/pcm.h382
-rw-r--r--drivers/staging/line6/playback.c592
-rw-r--r--drivers/staging/line6/playback.h41
-rw-r--r--drivers/staging/line6/pod.c458
-rw-r--r--drivers/staging/line6/pod.h102
-rw-r--r--drivers/staging/line6/podhd.c154
-rw-r--r--drivers/staging/line6/podhd.h30
-rw-r--r--drivers/staging/line6/revision.h4
-rw-r--r--drivers/staging/line6/toneport.c460
-rw-r--r--drivers/staging/line6/toneport.h52
-rw-r--r--drivers/staging/line6/usbdefs.h116
-rw-r--r--drivers/staging/line6/variax.c235
-rw-r--r--drivers/staging/line6/variax.h72
34 files changed, 127 insertions, 6028 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ecee3bcc8772..26b3199e0af2 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_runtime_pm_enable(dev_priv);
+ i915_audio_component_init(dev_priv);
+
return 0;
out_power_well:
@@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
+ i915_audio_component_cleanup(dev_priv);
+
ret = i915_gem_suspend(dev);
if (ret) {
DRM_ERROR("failed to idle hardware: %d\n", ret);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 7643300828c3..489b220af02b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -934,8 +934,7 @@ static int i915_pm_suspend(struct device *dev)
static int i915_pm_suspend_late(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
/*
* We have a suspedn ordering issue with the snd-hda driver also
@@ -954,8 +953,7 @@ static int i915_pm_suspend_late(struct device *dev)
static int i915_pm_resume_early(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
@@ -965,8 +963,7 @@ static int i915_pm_resume_early(struct device *dev)
static int i915_pm_resume(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9d7a7155bf02..24cc36a9f3ff 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1698,6 +1698,9 @@ struct drm_i915_private {
struct drm_property *broadcast_rgb_property;
struct drm_property *force_audio_property;
+ /* hda/i915 audio component */
+ bool audio_component_registered;
+
uint32_t hw_context_size;
struct list_head context_list;
@@ -1781,6 +1784,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
return dev->dev_private;
}
+static inline struct drm_i915_private *dev_to_i915(struct device *dev)
+{
+ return to_i915(dev_get_drvdata(dev));
+}
+
/* Iterate over initialised rings */
#define for_each_ring(ring__, dev_priv__, i__) \
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 2c7ed5cb29c0..ee41b882e71a 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -22,6 +22,9 @@
*/
#include <linux/kernel.h>
+#include <linux/component.h>
+#include <drm/i915_component.h>
+#include "intel_drv.h"
#include <drm/drmP.h>
#include <drm/drm_edid.h>
@@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev)
dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
}
}
+
+static void i915_audio_component_get_power(struct device *dev)
+{
+ intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+}
+
+static void i915_audio_component_put_power(struct device *dev)
+{
+ intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+}
+
+/* Get CDCLK in kHz */
+static int i915_audio_component_get_cdclk_freq(struct device *dev)
+{
+ struct drm_i915_private *dev_priv = dev_to_i915(dev);
+ int ret;
+
+ if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
+ return -ENODEV;
+
+ intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
+ ret = intel_ddi_get_cdclk_freq(dev_priv);
+ intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
+
+ return ret;
+}
+
+static const struct i915_audio_component_ops i915_audio_component_ops = {
+ .owner = THIS_MODULE,
+ .get_power = i915_audio_component_get_power,
+ .put_power = i915_audio_component_put_power,
+ .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
+};
+
+static int i915_audio_component_bind(struct device *i915_dev,
+ struct device *hda_dev, void *data)
+{
+ struct i915_audio_component *acomp = data;
+
+ if (WARN_ON(acomp->ops || acomp->dev))
+ return -EEXIST;
+
+ acomp->ops = &i915_audio_component_ops;
+ acomp->dev = i915_dev;
+
+ return 0;
+}
+
+static void i915_audio_component_unbind(struct device *i915_dev,
+ struct device *hda_dev, void *data)
+{
+ struct i915_audio_component *acomp = data;
+
+ acomp->ops = NULL;
+ acomp->dev = NULL;
+}
+
+static const struct component_ops i915_audio_component_bind_ops = {
+ .bind = i915_audio_component_bind,
+ .unbind = i915_audio_component_unbind,
+};
+
+/**
+ * i915_audio_component_init - initialize and register the audio component
+ * @dev_priv: i915 device instance
+ *
+ * This will register with the component framework a child component which
+ * will bind dynamically to the snd_hda_intel driver's corresponding master
+ * component when the latter is registered. During binding the child
+ * initializes an instance of struct i915_audio_component which it receives
+ * from the master. The master can then start to use the interface defined by
+ * this struct. Each side can break the binding at any point by deregistering
+ * its own component after which each side's component unbind callback is
+ * called.
+ *
+ * We ignore any error during registration and continue with reduced
+ * functionality (i.e. without HDMI audio).
+ */
+void i915_audio_component_init(struct drm_i915_private *dev_priv)
+{
+ int ret;
+
+ ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops);
+ if (ret < 0) {
+ DRM_ERROR("failed to add audio component (%d)\n", ret);
+ /* continue with reduced functionality */
+ return;
+ }
+
+ dev_priv->audio_component_registered = true;
+}
+
+/**
+ * i915_audio_component_cleanup - deregister the audio component
+ * @dev_priv: i915 device instance
+ *
+ * Deregisters the audio component, breaking any existing binding to the
+ * corresponding snd_hda_intel driver's master component.
+ */
+void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
+{
+ if (!dev_priv->audio_component_registered)
+ return;
+
+ component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops);
+ dev_priv->audio_component_registered = false;
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3b40a17b8852..29ba962d15e3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -873,6 +873,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
void intel_init_audio(struct drm_device *dev);
void intel_audio_codec_enable(struct intel_encoder *encoder);
void intel_audio_codec_disable(struct intel_encoder *encoder);
+void i915_audio_component_init(struct drm_i915_private *dev_priv);
+void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
/* intel_display.c */
const char *intel_output_name(int output);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index ac6da7102fbb..39ddf40171bf 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -31,7 +31,6 @@
#include "i915_drv.h"
#include "intel_drv.h"
-#include <drm/i915_powerwell.h>
/**
* DOC: runtime pm
@@ -50,8 +49,6 @@
* present for a given platform.
*/
-static struct i915_power_domains *hsw_pwr;
-
#define for_each_power_well(i, power_well, domain_mask, power_domains) \
for (i = 0; \
i < (power_domains)->power_well_count && \
@@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
*/
if (IS_HASWELL(dev_priv->dev)) {
set_power_wells(power_domains, hsw_power_wells);
- hsw_pwr = power_domains;
} else if (IS_BROADWELL(dev_priv->dev)) {
set_power_wells(power_domains, bdw_power_wells);
- hsw_pwr = power_domains;
} else if (IS_CHERRYVIEW(dev_priv->dev)) {
set_power_wells(power_domains, chv_power_wells);
} else if (IS_VALLEYVIEW(dev_priv->dev)) {
@@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
* the power well is not enabled, so just enable it in case
* we're going to unload/reload. */
intel_display_set_init_power(dev_priv, true);
-
- hsw_pwr = NULL;
}
static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
@@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
pm_runtime_put_autosuspend(device);
}
-/* Display audio driver power well request */
-int i915_request_power_well(void)
-{
- struct drm_i915_private *dev_priv;
-
- if (!hsw_pwr)
- return -ENODEV;
-
- dev_priv = container_of(hsw_pwr, struct drm_i915_private,
- power_domains);
- intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
- return 0;
-}
-EXPORT_SYMBOL_GPL(i915_request_power_well);
-
-/* Display audio driver power well release */
-int i915_release_power_well(void)
-{
- struct drm_i915_private *dev_priv;
-
- if (!hsw_pwr)
- return -ENODEV;
-
- dev_priv = container_of(hsw_pwr, struct drm_i915_private,
- power_domains);
- intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
- return 0;
-}
-EXPORT_SYMBOL_GPL(i915_release_power_well);
-
-/*
- * Private interface for the audio driver to get CDCLK in kHz.
- *
- * Caller must request power well using i915_request_power_well() prior to
- * making the call.
- */
-int i915_get_cdclk_freq(void)
-{
- struct drm_i915_private *dev_priv;
-
- if (!hsw_pwr)
- return -ENODEV;
-
- dev_priv = container_of(hsw_pwr, struct drm_i915_private,
- power_domains);
-
- return intel_ddi_get_cdclk_freq(dev_priv);
-}
-EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 815de379a130..9049dd91b569 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig"
source "drivers/staging/rts5208/Kconfig"
-source "drivers/staging/line6/Kconfig"
-
source "drivers/staging/octeon/Kconfig"
source "drivers/staging/octeon-usb/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 33c640b49566..fe26ff162b42 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_R8188EU) += rtl8188eu/
obj-$(CONFIG_R8723AU) += rtl8723au/
obj-$(CONFIG_RTS5208) += rts5208/
-obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_OCTEON_USB) += octeon-usb/
diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig
deleted file mode 100644
index 4f1219b4c692..000000000000
--- a/drivers/staging/line6/Kconfig
+++ /dev/null
@@ -1,38 +0,0 @@
-menuconfig LINE6_USB
- tristate "Line6 USB support"
- depends on USB && SND
- select SND_RAWMIDI
- select SND_PCM
- help
- This is a driver for the guitar amp, cab, and effects modeller
- PODxt Pro by Line6 (and similar devices), supporting the
- following features:
- * Reading/writing individual parameters
- * Reading/writing complete channel, effects setup, and amp
- setup data
- * Channel switching
- * Virtual MIDI interface
- * Tuner access
- * Playback/capture/mixer device for any ALSA-compatible PCM
- audio application
- * Signal routing (record clean/processed guitar signal,
- re-amping)
-
- Preliminary support for the Variax Workbench and TonePort
- devices is included.
-
-if LINE6_USB
-
-config LINE6_USB_IMPULSE_RESPONSE
- bool "measure impulse response"
- default n
- help
- Say Y here to add code to measure the impulse response of a Line6
- device. This is more accurate than user-space methods since it
- bypasses any PCM data buffering (e.g., by ALSA or jack). This is
- useful for assessing the performance of new devices, but is not
- required for normal operation.
-
- If unsure, say N.
-
-endif # LINE6_USB
diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile
deleted file mode 100644
index ae5c374b0f87..000000000000
--- a/drivers/staging/line6/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-obj-$(CONFIG_LINE6_USB) += line6usb.o
-
-line6usb-y := \
- audio.o \
- capture.o \
- driver.o \
- midi.o \
- midibuf.o \
- pcm.o \
- playback.o \
- pod.o \
- toneport.o \
- variax.o \
- podhd.o
diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c
deleted file mode 100644
index 171d80c1b020..000000000000
--- a/drivers/staging/line6/audio.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * 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, version 2.
- *
- */
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <linux/export.h>
-
-#include "driver.h"
-#include "audio.h"
-
-/*
- Initialize the Line6 USB audio system.
-*/
-int line6_init_audio(struct usb_line6 *line6)
-{
- struct snd_card *card;
- int err;
-
- err = snd_card_new(line6->ifcdev,
- SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
- if (err < 0)
- return err;
-
- line6->card = card;
-
- strcpy(card->id, line6->properties->id);
- strcpy(card->driver, DRIVER_NAME);
- strcpy(card->shortname, line6->properties->name);
- /* longname is 80 chars - see asound.h */
- sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
- dev_name(line6->ifcdev));
- return 0;
-}
-
-/*
- Register the Line6 USB audio system.
-*/
-int line6_register_audio(struct usb_line6 *line6)
-{
- int err;
-
- err = snd_card_register(line6->card);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-/*
- Cleanup the Line6 USB audio system.
-*/
-void line6_cleanup_audio(struct usb_line6 *line6)
-{
- struct snd_card *card = line6->card;
-
- if (card == NULL)
- return;
-
- snd_card_disconnect(card);
- snd_card_free(card);
- line6->card = NULL;
-}
diff --git a/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h
deleted file mode 100644
index 5f8a09a0fa95..000000000000
--- a/drivers/staging/line6/audio.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * 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, version 2.
- *
- */
-
-#ifndef AUDIO_H
-#define AUDIO_H
-
-#include "driver.h"
-
-extern void line6_cleanup_audio(struct usb_line6 *);
-extern int line6_init_audio(struct usb_line6 *);
-extern int line6_register_audio(struct usb_line6 *);
-
-#endif
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
deleted file mode 100644
index e6ca631e3f79..000000000000
--- a/drivers/staging/line6/capture.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * 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, version 2.
- *
- */
-
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "pcm.h"
-#include "pod.h"
-
-/*
- Find a free URB and submit it.
-*/
-static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
-{
- int index;
- unsigned long flags;
- int i, urb_size;
- int ret;
- struct urb *urb_in;
-
- spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
- index =
- find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
-
- if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
- dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
- return -EINVAL;
- }
-
- urb_in = line6pcm->urb_audio_in[index];
- urb_size = 0;
-
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- struct usb_iso_packet_descriptor *fin =
- &urb_in->iso_frame_desc[i];
- fin->offset = urb_size;
- fin->length = line6pcm->max_packet_size;
- urb_size += line6pcm->max_packet_size;
- }
-
- urb_in->transfer_buffer =
- line6pcm->buffer_in +
- index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
- urb_in->transfer_buffer_length = urb_size;
- urb_in->context = line6pcm;
-
- ret = usb_submit_urb(urb_in, GFP_ATOMIC);
-
- if (ret == 0)
- set_bit(index, &line6pcm->active_urb_in);
- else
- dev_err(line6pcm->line6->ifcdev,
- "URB in #%d submission failed (%d)\n", index, ret);
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
- return 0;
-}
-
-/*
- Submit all currently available capture URBs.
-*/
-int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
-{
- int ret, i;
-
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- ret = submit_audio_in_urb(line6pcm);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-/*
- Unlink all currently active capture URBs.
-*/
-void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- unsigned int i;
-
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_in)) {
- if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
- struct urb *u = line6pcm->urb_audio_in[i];
-
- usb_unlink_urb(u);
- }
- }
- }
-}
-
-/*
- Wait until unlinking of all currently active capture URBs has been
- finished.
-*/
-void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- int timeout = HZ;
- unsigned int i;
- int alive;
-
- do {
- alive = 0;
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_in))
- alive++;
- }
- if (!alive)
- break;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- } while (--timeout > 0);
- if (alive)
- snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
- Unlink all currently active capture URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- line6_unlink_audio_in_urbs(line6pcm);
- line6_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
- Copy data into ALSA capture buffer.
-*/
-void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
-{
- struct snd_pcm_substream *substream =
- get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
- struct snd_pcm_runtime *runtime = substream->runtime;
- const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
- int frames = fsize / bytes_per_frame;
-
- if (runtime == NULL)
- return;
-
- if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
- /*
- The transferred area goes over buffer boundary,
- copy two separate chunks.
- */
- int len;
-
- len = runtime->buffer_size - line6pcm->pos_in_done;
-
- if (len > 0) {
- memcpy(runtime->dma_area +
- line6pcm->pos_in_done * bytes_per_frame, fbuf,
- len * bytes_per_frame);
- memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
- (frames - len) * bytes_per_frame);
- } else {
- /* this is somewhat paranoid */
- dev_err(line6pcm->line6->ifcdev,
- "driver bug: len = %d\n", len);
- }
- } else {
- /* copy single chunk */
- memcpy(runtime->dma_area +
- line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
- }
-
- line6pcm->pos_in_done += frames;
- if (line6pcm->pos_in_done >= runtime->buffer_size)
- line6pcm->pos_in_done -= runtime->buffer_size;
-}
-
-void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
-{
- struct snd_pcm_substream *substream =
- get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
-
- line6pcm->bytes_in += length;
- if (line6pcm->bytes_in >= line6pcm->period_in) {
- line6pcm->bytes_in %= line6pcm->period_in;
- snd_pcm_period_elapsed(substream);
- }
-}
-
-void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
-{
- kfree(line6pcm->buffer_in);
- line6pcm->buffer_in = NULL;
-}
-
-/*
- * Callback for completed capture URB.
- */
-static void audio_in_callback(struct urb *urb)
-{
- int i, index, length = 0, shutdown = 0;
- unsigned long flags;
-
- struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
-
- line6pcm->last_frame_in = urb->start_frame;
-
- /* find index of URB */
- for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
- if (urb == line6pcm->urb_audio_in[index])
- break;
-
- spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
-
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- char *fbuf;
- int fsize;
- struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
-
- if (fin->status == -EXDEV) {
- shutdown = 1;
- break;
- }
-
- fbuf = urb->transfer_buffer + fin->offset;
- fsize = fin->actual_length;
-
- if (fsize > line6pcm->max_packet_size) {
- dev_err(line6pcm->line6->ifcdev,
- "driver and/or device bug: packet too large (%d > %d)\n",
- fsize, line6pcm->max_packet_size);
- }
-
- length += fsize;
-
- /* the following assumes LINE6_ISO_PACKETS == 1: */
- line6pcm->prev_fbuf = fbuf;
- line6pcm->prev_fsize = fsize;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
- if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
- &line6pcm->flags) && (fsize > 0))
- line6_capture_copy(line6pcm, fbuf, fsize);
- }
-
- clear_bit(index, &line6pcm->active_urb_in);
-
- if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
- shutdown = 1;
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-
- if (!shutdown) {
- submit_audio_in_urb(line6pcm);
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
- if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
- &line6pcm->flags))
- line6_capture_check_period(line6pcm, length);
- }
-}
-
-/* open capture callback */
-static int snd_line6_capture_open(struct snd_pcm_substream *substream)
-{
- int err;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);