Required properties:
- - compatible : One of "ti,pcm5121" or "ti,pcm5122"
+ - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or
+ "ti,pcm5142"
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
intel_runtime_pm_enable(dev_priv);
+ i915_audio_component_init(dev_priv);
+
return 0;
out_power_well:
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);
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
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;
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;
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;
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__)++) \
*/
#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>
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;
+}
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);
#include "i915_drv.h"
#include "intel_drv.h"
-#include <drm/i915_powerwell.h>
/**
* DOC: runtime pm
* 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 && \
*/
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)) {
* 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)
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);
source "drivers/staging/rts5208/Kconfig"
-source "drivers/staging/line6/Kconfig"
-
source "drivers/staging/octeon/Kconfig"
source "drivers/staging/octeon-usb/Kconfig"
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/
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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);
-
- err = snd_pcm_hw_constraint_ratdens(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- (&line6pcm->
- properties->snd_line6_rates));
- if (err < 0)
- return err;
-
- runtime->hw = line6pcm->properties->snd_line6_capture_hw;
- return 0;
-}
-
-/* close capture callback */
-static int snd_line6_capture_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-/* hw_params capture callback */
-static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- int ret;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- /* -- Florian Demski [FD] */
- /* don't ask me why, but this fixes the bug on my machine */
- if (line6pcm == NULL) {
- if (substream->pcm == NULL)
- return -ENOMEM;
- if (substream->pcm->private_data == NULL)
- return -ENOMEM;
- substream->private_data = substream->pcm->private_data;
- line6pcm = snd_pcm_substream_chip(substream);
- }
- /* -- [FD] end */
-
- ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-
- if (ret < 0)
- return ret;
-
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0) {
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
- return ret;
- }
-
- line6pcm->period_in = params_period_bytes(hw_params);
- return 0;
-}
-
-/* hw_free capture callback */
-static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger callback */
-int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
- int err;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_RESUME:
-#endif
- err = line6_pcm_acquire(line6pcm,
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
- err = line6_pcm_release(line6pcm,
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* capture pointer callback */
-static snd_pcm_uframes_t
-snd_line6_capture_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- return line6pcm->pos_in_done;
-}
-
-/* capture operators */
-struct snd_pcm_ops snd_line6_capture_ops = {
- .open = snd_line6_capture_open,
- .close = snd_line6_capture_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_line6_capture_hw_params,
- .hw_free = snd_line6_capture_hw_free,
- .prepare = snd_line6_prepare,
- .trigger = snd_line6_trigger,
- .pointer = snd_line6_capture_pointer,
-};
-
-int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- int i;
-
- /* create audio URBs and fill in constant values: */
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- struct urb *urb;
-
- /* URB for audio in: */
- urb = line6pcm->urb_audio_in[i] =
- usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
-
- if (urb == NULL) {
- dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- urb->dev = line6pcm->line6->usbdev;
- urb->pipe =
- usb_rcvisocpipe(line6pcm->line6->usbdev,
- line6pcm->ep_audio_read &
- USB_ENDPOINT_NUMBER_MASK);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->start_frame = -1;
- urb->number_of_packets = LINE6_ISO_PACKETS;
- urb->interval = LINE6_ISO_INTERVAL;
- urb->error_count = 0;
- urb->complete = audio_in_callback;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * 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 CAPTURE_H
-#define CAPTURE_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "pcm.h"
-
-extern struct snd_pcm_ops snd_line6_capture_ops;
-
-extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
- int fsize);
-extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
- int length);
-extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
- *line6pcm);
-extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
+++ /dev/null
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "midi.h"
-#include "playback.h"
-#include "pod.h"
-#include "podhd.h"
-#include "revision.h"
-#include "toneport.h"
-#include "usbdefs.h"
-#include "variax.h"
-
-#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>"
-#define DRIVER_DESC "Line6 USB Driver"
-#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION
-
-/* table of devices that work with this driver */
-static const struct usb_device_id line6_id_table[] = {
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD400)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)},
- {},
-};
-
-MODULE_DEVICE_TABLE(usb, line6_id_table);
-
-#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\
- {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\
- .name = dev_name, .capabilities = LINE6_BIT_##dev_cap}
-
-/* *INDENT-OFF* */
-static const struct line6_properties line6_properties_table[] = {
- L6PROP(BASSPODXT, "BassPODxt", "BassPODxt", CTRL_PCM_HW),
- L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW),
- L6PROP(BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW),
- L6PROP(GUITARPORT, "GuitarPort", "GuitarPort", PCM),
- L6PROP(POCKETPOD, "PocketPOD", "Pocket POD", CONTROL),
- L6PROP(PODHD300, "PODHD300", "POD HD300", CTRL_PCM_HW),
- L6PROP(PODHD400, "PODHD400", "POD HD400", CTRL_PCM_HW),
- L6PROP(PODHD500, "PODHD500", "POD HD500", CTRL_PCM_HW),
- L6PROP(PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", PCM),
- L6PROP(PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", PCM),
- L6PROP(PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", PCM),
- L6PROP(PODX3, "PODX3", "POD X3", PCM),
- L6PROP(PODX3LIVE, "PODX3Live", "POD X3 Live", PCM),
- L6PROP(PODXT, "PODxt", "PODxt", CTRL_PCM_HW),
- L6PROP(PODXTLIVE, "PODxtLive", "PODxt Live", CTRL_PCM_HW),
- L6PROP(PODXTPRO, "PODxtPro", "PODxt Pro", CTRL_PCM_HW),
- L6PROP(TONEPORT_GX, "TonePortGX", "TonePort GX", PCM),
- L6PROP(TONEPORT_UX1, "TonePortUX1", "TonePort UX1", PCM),
- L6PROP(TONEPORT_UX2, "TonePortUX2", "TonePort UX2", PCM),
- L6PROP(VARIAX, "Variax", "Variax Workbench", CONTROL),
-};
-/* *INDENT-ON* */
-
-/*
- This is Line6's MIDI manufacturer ID.
-*/
-const unsigned char line6_midi_id[] = {
- 0x00, 0x01, 0x0c
-};
-
-/*
- Code to request version of POD, Variax interface
- (and maybe other devices).
-*/
-static const char line6_request_version[] = {
- 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
-};
-
-/**
- Class for asynchronous messages.
-*/
-struct message {
- struct usb_line6 *line6;
- const char *buffer;
- int size;
- int done;
-};
-
-/*
- Forward declarations.
-*/
-static void line6_data_received(struct urb *urb);
-static int line6_send_raw_message_async_part(struct message *msg,
- struct urb *urb);
-
-/*
- Start to listen on endpoint.
-*/
-static int line6_start_listen(struct usb_line6 *line6)
-{
- int err;
-
- usb_fill_int_urb(line6->urb_listen, line6->usbdev,
- usb_rcvintpipe(line6->usbdev, line6->ep_control_read),
- line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
- line6_data_received, line6, line6->interval);
- line6->urb_listen->actual_length = 0;
- err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
- return err;
-}
-
-/*
- Stop listening on endpoint.
-*/
-static void line6_stop_listen(struct usb_line6 *line6)
-{
- usb_kill_urb(line6->urb_listen);
-}
-
-/*
- Send raw message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
- int size)
-{
- int i, done = 0;
-
- for (i = 0; i < size; i += line6->max_packet_size) {
- int partial;
- const char *frag_buf = buffer + i;
- int frag_size = min(line6->max_packet_size, size - i);
- int retval;
-
- retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- (char *)frag_buf, frag_size,
- &partial, LINE6_TIMEOUT * HZ);
-
- if (retval) {
- dev_err(line6->ifcdev,
- "usb_interrupt_msg failed (%d)\n", retval);
- break;
- }
-
- done += frag_size;
- }
-
- return done;
-}
-
-/*
- Notification of completion of asynchronous request transmission.
-*/
-static void line6_async_request_sent(struct urb *urb)
-{
- struct message *msg = (struct message *)urb->context;
-
- if (msg->done >= msg->size) {
- usb_free_urb(urb);
- kfree(msg);
- } else
- line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
- Asynchronously send part of a raw message.
-*/
-static int line6_send_raw_message_async_part(struct message *msg,
- struct urb *urb)
-{
- int retval;
- struct usb_line6 *line6 = msg->line6;
- int done = msg->done;
- int bytes = min(msg->size - done, line6->max_packet_size);
-
- usb_fill_int_urb(urb, line6->usbdev,
- usb_sndintpipe(line6->usbdev, line6->ep_control_write),
- (char *)msg->buffer + done, bytes,
- line6_async_request_sent, msg, line6->interval);
-
- msg->done += bytes;
- retval = usb_submit_urb(urb, GFP_ATOMIC);
-
- if (retval < 0) {
- dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
- __func__, retval);
- usb_free_urb(urb);
- kfree(msg);
- return retval;
- }
-
- return 0;
-}
-
-/*
- Setup and start timer.
-*/
-void line6_start_timer(struct timer_list *timer, unsigned int msecs,
- void (*function)(unsigned long), unsigned long data)
-{
- setup_timer(timer, function, data);
- timer->expires = jiffies + msecs * HZ / 1000;
- add_timer(timer);
-}
-
-/*
- Asynchronously send raw message.
-*/
-int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
- int size)
-{
- struct message *msg;
- struct urb *urb;
-
- /* create message: */
- msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
- if (msg == NULL)
- return -ENOMEM;
-
- /* create URB: */
- urb = usb_alloc_urb(0, GFP_ATOMIC);
-
- if (urb == NULL) {
- kfree(msg);
- dev_err(line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- /* set message data: */
- msg->line6 = line6;
- msg->buffer = buffer;
- msg->size = size;
- msg->done = 0;
-
- /* start sending: */
- return line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
- Send asynchronous device version request.
-*/
-int line6_version_request_async(struct usb_line6 *line6)
-{
- char *buffer;
- int retval;
-
- buffer = kmemdup(line6_request_version,
- sizeof(line6_request_version), GFP_ATOMIC);
- if (buffer == NULL) {
- dev_err(line6->ifcdev, "Out of memory");
- return -ENOMEM;
- }
-
- retval = line6_send_raw_message_async(line6, buffer,
- sizeof(line6_request_version));
- kfree(buffer);
- return retval;
-}
-
-/*
- Send sysex message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
- int size)
-{
- return line6_send_raw_message(line6, buffer,
- size + SYSEX_EXTRA_SIZE) -
- SYSEX_EXTRA_SIZE;
-}
-
-/*
- Allocate buffer for sysex message and prepare header.
- @param code sysex message code
- @param size number of bytes between code and sysex end
-*/
-char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
- int size)
-{
- char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
-
- if (!buffer)
- return NULL;
-
- buffer[0] = LINE6_SYSEX_BEGIN;
- memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
- buffer[sizeof(line6_midi_id) + 1] = code1;
- buffer[sizeof(line6_midi_id) + 2] = code2;
- buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
- return buffer;
-}
-
-/*
- Notification of data received from the Line6 device.
-*/
-static void line6_data_received(struct urb *urb)
-{
- struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
- struct midi_buffer *mb = &line6->line6midi->midibuf_in;
- int done;
-
- if (urb->status == -ESHUTDOWN)
- return;
-
- done =
- line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
-
- if (done < urb->actual_length) {
- line6_midibuf_ignore(mb, done);
- dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
- done, urb->actual_length);
- }
-
- for (;;) {
- done =
- line6_midibuf_read(mb, line6->buffer_message,
- LINE6_MESSAGE_MAXLEN);
-
- if (done == 0)
- break;
-
- line6->message_length = done;
- line6_midi_receive(line6, line6->buffer_message, done);
-
- switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- line6_pod_process_message((struct usb_line6_pod *)
- line6);
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- case LINE6_DEVID_PODHD500:
- break; /* let userspace handle MIDI */
-
- case LINE6_DEVID_PODXTLIVE:
- switch (line6->interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- line6_pod_process_message((struct usb_line6_pod
- *)line6);
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- line6_variax_process_message((struct
- usb_line6_variax
- *)line6);
- break;
-
- default:
- dev_err(line6->ifcdev,
- "PODxt Live interface %d not supported\n",
- line6->interface_number);
- }
- break;
-
- case LINE6_DEVID_VARIAX:
- line6_variax_process_message((struct usb_line6_variax *)
- line6);
- break;
-
- default:
- MISSING_CASE;
- }
- }
-
- line6_start_listen(line6);
-}
-
-/*
- Send channel number (i.e., switch to a different sound).
-*/
-int line6_send_program(struct usb_line6 *line6, u8 value)
-{
- int retval;
- unsigned char *buffer;
- int partial;
-
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST;
- buffer[1] = value;
-
- retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- buffer, 2, &partial, LINE6_TIMEOUT * HZ);
-
- if (retval)
- dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
- retval);
-
- kfree(buffer);
- return retval;
-}
-
-/*
- Transmit Line6 control parameter.
-*/
-int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value)
-{
- int retval;
- unsigned char *buffer;
- int partial;
-
- buffer = kmalloc(3, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST;
- buffer[1] = param;
- buffer[2] = value;
-
- retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- buffer, 3, &partial, LINE6_TIMEOUT * HZ);
-
- if (retval)
- dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
- retval);
-
- kfree(buffer);
- return retval;
-}
-
-/*
- Read data from device.
-*/
-int line6_read_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen)
-{
- struct usb_device *usbdev = line6->usbdev;
- int ret;
- unsigned char len;
-
- /* query the serial number: */
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- (datalen << 8) | 0x21, address,
- NULL, 0, LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
- return ret;
- }
-
- /* Wait for data length. We'll get 0xff until length arrives. */
- do {
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_IN,
- 0x0012, 0x0000, &len, 1,
- LINE6_TIMEOUT * HZ);
- if (ret < 0) {
- dev_err(line6->ifcdev,
- "receive length failed (error %d)\n", ret);
- return ret;
- }
- } while (len == 0xff);
-
- if (len != datalen) {
- /* should be equal or something went wrong */
- dev_err(line6->ifcdev,
- "length mismatch (expected %d, got %d)\n",
- (int)datalen, (int)len);
- return -EINVAL;
- }
-
- /* receive the result: */
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x0013, 0x0000, data, datalen,
- LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-/*
- Write data to device.
-*/
-int line6_write_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen)
-{
- struct usb_device *usbdev = line6->usbdev;
- int ret;
- unsigned char status;
-
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- 0x0022, address, data, datalen,
- LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev,
- "write request failed (error %d)\n", ret);
- return ret;
- }
-
- do {
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
- 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_IN,
- 0x0012, 0x0000,
- &status, 1, LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev,
- "receiving status failed (error %d)\n", ret);
- return ret;
- }
- } while (status == 0xff);
-
- if (status != 0) {
- dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- Read Line6 device serial number.
- (POD, TonePort, GuitarPort)
-*/
-int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
-{
- return line6_read_data(line6, 0x80d0, serial_number,
- sizeof(*serial_number));
-}
-
-/*
- No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-/*
- Generic destructor.
-*/
-static void line6_destruct(struct usb_interface *interface)
-{
- struct usb_line6 *line6;
-
- if (interface == NULL)
- return;
- line6 = usb_get_intfdata(interface);
- if (line6 == NULL)
- return;
-
- /* free buffer memory first: */
- kfree(line6->buffer_message);
- kfree(line6->buffer_listen);
-
- /* then free URBs: */
- usb_free_urb(line6->urb_listen);
-
- /* make sure the device isn't destructed twice: */
- usb_set_intfdata(interface, NULL);
-
- /* free interface data: */
- kfree(line6);
-}
-
-/*
- Probe USB device.
-*/
-static int line6_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- int devtype;
- struct usb_device *usbdev;
- struct usb_line6 *line6;
- const struct line6_properties *properties;
- int interface_number, alternate = 0;
- int product;
- int size = 0;
- int ep_read = 0, ep_write = 0;
- int ret;
-
- if (interface == NULL)
- return -ENODEV;
- usbdev = interface_to_usbdev(interface);
- if (usbdev == NULL)
- return -ENODEV;
-
- /* we don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1) {
- ret = -ENODEV;
- goto err_put;
- }
-
- /* check vendor and product id */
- for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) {
- u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor);
- u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
- if (idVendor == line6_id_table[devtype].idVendor &&
- idProduct == line6_id_table[devtype].idProduct)
- break;
- }
-
- if (devtype < 0) {
- ret = -ENODEV;
- goto err_put;
- }
-
- /* initialize device info: */
- properties = &line6_properties_table[devtype];
- dev_info(&interface->dev, "Line6 %s found\n", properties->name);
- product = le16_to_cpu(usbdev->descriptor.idProduct);
-
- /* query interface number */
- interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
-
- switch (product) {
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_PODXTLIVE:
- case LINE6_DEVID_VARIAX:
- alternate = 1;
- break;
-
- case LINE6_DEVID_POCKETPOD:
- switch (interface_number) {
- case 0:
- return -ENODEV; /* this interface has no endpoints */
- case 1:
- alternate = 0;
- break;
- default:
- MISSING_CASE;
- }
- break;
-
- case LINE6_DEVID_PODHD500:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- switch (interface_number) {
- case 0:
- alternate = 1;
- break;
- case 1:
- alternate = 0;
- break;
- default:
- MISSING_CASE;
- }
- break;
-
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- alternate = 5;
- break;
-
- case LINE6_DEVID_GUITARPORT:
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- alternate = 2; /* 1..4 seem to be ok */
- break;
-
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX2:
- switch (interface_number) {
- case 0:
- /* defaults to 44.1kHz, 16-bit */
- alternate = 2;
- break;
- case 1:
- /* don't know yet what this is ...
- alternate = 1;
- break;
- */
- return -ENODEV;
- default:
- MISSING_CASE;
- }
- break;
-
- default:
- MISSING_CASE;
- ret = -ENODEV;
- goto err_put;
- }
-
- ret = usb_set_interface(usbdev, interface_number, alternate);
- if (ret < 0) {
- dev_err(&interface->dev, "set_interface failed\n");
- goto err_put;
- }
-
- /* initialize device data based on product id: */
- switch (product) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x84;
- ep_write = 0x03;
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- size = sizeof(struct usb_line6_podhd);
- ep_read = 0x84;
- ep_write = 0x03;
- break;
-
- case LINE6_DEVID_PODHD500:
- size = sizeof(struct usb_line6_podhd);
- ep_read = 0x81;
- ep_write = 0x01;
- break;
-
- case LINE6_DEVID_POCKETPOD:
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x82;
- ep_write = 0x02;
- break;
-
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- /* currently unused! */
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x81;
- ep_write = 0x01;
- break;
-
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- size = sizeof(struct usb_line6_toneport);
- /* these don't have a control channel */
- break;
-
- case LINE6_DEVID_PODXTLIVE:
- switch (interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x84;
- ep_write = 0x03;
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- size = sizeof(struct usb_line6_variax);
- ep_read = 0x86;
- ep_write = 0x05;
- break;
-
- default:
- ret = -ENODEV;
- goto err_put;
- }
- break;
-
- case LINE6_DEVID_VARIAX:
- size = sizeof(struct usb_line6_variax);
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
- default:
- MISSING_CASE;
- ret = -ENODEV;
- goto err_put;
- }
-
- if (size == 0) {
- dev_err(&interface->dev,
- "driver bug: interface data size not set\n");
- ret = -ENODEV;
- goto err_put;
- }
-
- line6 = kzalloc(size, GFP_KERNEL);
- if (line6 == NULL) {
- ret = -ENODEV;
- goto err_put;
- }
-
- /* store basic data: */
- line6->interface_number = interface_number;
- line6->properties = properties;
- line6->usbdev = usbdev;
- line6->ifcdev = &interface->dev;
- line6->ep_control_read = ep_read;
- line6->ep_control_write = ep_write;
- line6->product = product;
-
- /* get data from endpoint descriptor (see usb_maxpacket): */
- {
- struct usb_host_endpoint *ep;
- unsigned epnum =
- usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read));
- ep = usbdev->ep_in[epnum];
-
- if (ep != NULL) {
- line6->interval = ep->desc.bInterval;
- line6->max_packet_size =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- } else {
- line6->interval = LINE6_FALLBACK_INTERVAL;
- line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
- dev_err(line6->ifcdev,
- "endpoint not available, using fallback values");
- }
- }
-
- usb_set_intfdata(interface, line6);
-
- if (properties->capabilities & LINE6_BIT_CONTROL) {
- /* initialize USB buffers: */
- line6->buffer_listen =
- kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
- if (line6->buffer_listen == NULL) {
- ret = -ENOMEM;
- goto err_destruct;
- }
-
- line6->buffer_message =
- kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
- if (line6->buffer_message == NULL) {
- ret = -ENOMEM;
- goto err_destruct;
- }
-
- line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
-
- if (line6->urb_listen == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- line6_destruct(interface);
- ret = -ENOMEM;
- goto err_destruct;
- }
-
- ret = line6_start_listen(line6);
- if (ret < 0) {
- dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
- __func__);
- goto err_destruct;
- }
- }
-
- /* initialize device data based on product id: */
- switch (product) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- ret = line6_pod_init(interface, (struct usb_line6_pod *)line6);
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- case LINE6_DEVID_PODHD500:
- ret = line6_podhd_init(interface,
- (struct usb_line6_podhd *)line6);
- break;
-
- case LINE6_DEVID_PODXTLIVE:
- switch (interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- ret =
- line6_pod_init(interface,
- (struct usb_line6_pod *)line6);
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- ret =
- line6_variax_init(interface,
- (struct usb_line6_variax *)line6);
- break;
-
- default:
- dev_err(&interface->dev,
- "PODxt Live interface %d not supported\n",
- interface_number);
- ret = -ENODEV;
- }
-
- break;
-
- case LINE6_DEVID_VARIAX:
- ret =
- line6_variax_init(interface,
- (struct usb_line6_variax *)line6);
- break;
-
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- ret =
- line6_toneport_init(interface,
- (struct usb_line6_toneport *)line6);
- break;
-
- default:
- MISSING_CASE;
- ret = -ENODEV;
- }
-
- if (ret < 0)
- goto err_destruct;
-
- ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
- "usb_device");
- if (ret < 0)
- goto err_destruct;
-
- /* creation of additional special files should go here */
-
- dev_info(&interface->dev, "Line6 %s now attached\n",
- line6->properties->name);
-
- switch (product) {
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- dev_info(&interface->dev,
- "NOTE: the Line6 %s is detected, but not yet supported\n",
- line6->properties->name);
- }
-
- /* increment reference counters: */
- usb_get_intf(interface);
- usb_get_dev(usbdev);
-
- return 0;
-
-err_destruct:
- line6_destruct(interface);
-err_put:
- return ret;
-}
-
-/*
- Line6 device disconnected.
-*/
-static void line6_disconnect(struct usb_interface *interface)
-{
- struct usb_line6 *line6;
- struct usb_device *usbdev;
- int interface_number;
-
- if (interface == NULL)
- return;
- usbdev = interface_to_usbdev(interface);
- if (usbdev == NULL)
- return;
-
- /* removal of additional special files should go here */
-
- sysfs_remove_link(&interface->dev.kobj, "usb_device");
-
- interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
- line6 = usb_get_intfdata(interface);
-
- if (line6 != NULL) {
- if (line6->urb_listen != NULL)
- line6_stop_listen(line6);
-
- if (usbdev != line6->usbdev)
- dev_err(line6->ifcdev,
- "driver bug: inconsistent usb device\n");
-
- switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- line6_pod_disconnect(interface);
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- case LINE6_DEVID_PODHD500:
- line6_podhd_disconnect(interface);
- break;
-
- case LINE6_DEVID_PODXTLIVE:
- switch (interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- line6_pod_disconnect(interface);
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- line6_variax_disconnect(interface);
- break;
- }
-
- break;
-
- case LINE6_DEVID_VARIAX:
- line6_variax_disconnect(interface);
- break;
-
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- line6_toneport_disconnect(interface);
- break;
-
- default:
- MISSING_CASE;
- }
-
- dev_info(&interface->dev, "Line6 %s now disconnected\n",
- line6->properties->name);
- }
-
- line6_destruct(interface);
-
- /* decrement reference counters: */
- usb_put_intf(interface);
- usb_put_dev(usbdev);
-}
-
-#ifdef CONFIG_PM
-
-/*
- Suspend Line6 device.
-*/
-static int line6_suspend(struct usb_interface *interface, pm_message_t message)
-{
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- struct snd_line6_pcm *line6pcm = line6->line6pcm;
-
- snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
-
- if (line6->properties->capabilities & LINE6_BIT_CONTROL)
- line6_stop_listen(line6);
-
- if (line6pcm != NULL) {
- snd_pcm_suspend_all(line6pcm->pcm);
- line6_pcm_disconnect(line6pcm);
- line6pcm->flags = 0;
- }
-
- return 0;
-}
-
-/*
- Resume Line6 device.
-*/
-static int line6_resume(struct usb_interface *interface)
-{
- struct usb_line6 *line6 = usb_get_intfdata(interface);
-
- if (line6->properties->capabilities & LINE6_BIT_CONTROL)
- line6_start_listen(line6);
-
- snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-
-/*
- Resume Line6 device after reset.
-*/
-static int line6_reset_resume(struct usb_interface *interface)
-{
- struct usb_line6 *line6 = usb_get_intfdata(interface);
-
- switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- line6_toneport_reset_resume((struct usb_line6_toneport *)line6);
- }
-
- return line6_resume(interface);
-}
-
-#endif /* CONFIG_PM */
-
-static struct usb_driver line6_driver = {
- .name = DRIVER_NAME,
- .probe = line6_probe,
- .disconnect = line6_disconnect,
-#ifdef CONFIG_PM
- .suspend = line6_suspend,
- .resume = line6_resume,
- .reset_resume = line6_reset_resume,
-#endif
- .id_table = line6_id_table,
-};
-
-module_usb_driver(line6_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+++ /dev/null
-/*
- * 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 DRIVER_H
-#define DRIVER_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "midi.h"
-
-#define DRIVER_NAME "line6usb"
-
-#define LINE6_TIMEOUT 1
-#define LINE6_BUFSIZE_LISTEN 32
-#define LINE6_MESSAGE_MAXLEN 256
-
-/*
- Line6 MIDI control commands
-*/
-#define LINE6_PARAM_CHANGE 0xb0
-#define LINE6_PROGRAM_CHANGE 0xc0
-#define LINE6_SYSEX_BEGIN 0xf0
-#define LINE6_SYSEX_END 0xf7
-#define LINE6_RESET 0xff
-
-/*
- MIDI channel for messages initiated by the host
- (and eventually echoed back by the device)
-*/
-#define LINE6_CHANNEL_HOST 0x00
-
-/*
- MIDI channel for messages initiated by the device
-*/
-#define LINE6_CHANNEL_DEVICE 0x02
-
-#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */
-
-#define LINE6_CHANNEL_MASK 0x0f
-
-#define MISSING_CASE \
- pr_err("line6usb driver bug: missing case in %s:%d\n", \
- __FILE__, __LINE__)
-
-#define CHECK_RETURN(x) \
-do { \
- err = x; \
- if (err < 0) \
- return err; \
-} while (0)
-
-#define CHECK_STARTUP_PROGRESS(x, n) \
-do { \
- if ((x) >= (n)) \
- return; \
- x = (n); \
-} while (0)
-
-extern const unsigned char line6_midi_id[3];
-
-static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
-static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
-
-/**
- Common properties of Line6 devices.
-*/
-struct line6_properties {
- /**
- Bit identifying this device in the line6usb driver.
- */
- int device_bit;
-
- /**
- Card id string (maximum 16 characters).
- This can be used to address the device in ALSA programs as
- "default:CARD=<id>"
- */
- const char *id;
-
- /**
- Card short name (maximum 32 characters).
- */
- const char *name;
-
- /**
- Bit vector defining this device's capabilities in the
- line6usb driver.
- */
- int capabilities;
-};
-
-/**
- Common data shared by all Line6 devices.
- Corresponds to a pair of USB endpoints.
-*/
-struct usb_line6 {
- /**
- USB device.
- */
- struct usb_device *usbdev;
-
- /**
- Product id.
- */
- int product;
-
- /**
- Properties.
- */
- const struct line6_properties *properties;
-
- /**
- Interface number.
- */
- int interface_number;
-
- /**
- Interval (ms).
- */
- int interval;
-
- /**
- Maximum size of USB packet.
- */
- int max_packet_size;
-
- /**
- Device representing the USB interface.
- */
- struct device *ifcdev;
-
- /**
- Line6 sound card data structure.
- Each device has at least MIDI or PCM.
- */
- struct snd_card *card;
-
- /**
- Line6 PCM device data structure.
- */
- struct snd_line6_pcm *line6pcm;
-
- /**
- Line6 MIDI device data structure.
- */
- struct snd_line6_midi *line6midi;
-
- /**
- USB endpoint for listening to control commands.
- */
- int ep_control_read;
-
- /**
- USB endpoint for writing control commands.
- */
- int ep_control_write;
-
- /**
- URB for listening to PODxt Pro control endpoint.
- */
- struct urb *urb_listen;
-
- /**
- Buffer for listening to PODxt Pro control endpoint.
- */
- unsigned char *buffer_listen;
-
- /**
- Buffer for message to be processed.
- */
- unsigned char *buffer_message;
-
- /**
- Length of message to be processed.
- */
- int message_length;
-};
-
-extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
- int code2, int size);
-extern ssize_t line6_nop_read(struct device *dev,
- struct device_attribute *attr, char *buf);
-extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen);
-extern int line6_read_serial_number(struct usb_line6 *line6,
- int *serial_number);
-extern int line6_send_program(struct usb_line6 *line6, u8 value);
-extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
- int size);
-extern int line6_send_raw_message_async(struct usb_line6 *line6,
- const char *buffer, int size);
-extern int line6_send_sysex_message(struct usb_line6 *line6,
- const char *buffer, int size);
-extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count);
-extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
- void (*function)(unsigned long),
- unsigned long data);
-extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
- u8 value);
-extern int line6_version_request_async(struct usb_line6 *line6);
-extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen);
-
-#endif
+++ /dev/null
-/*
- * 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 <linux/usb.h>
-#include <sound/core.h>
-#include <sound/rawmidi.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "midi.h"
-#include "pod.h"
-#include "usbdefs.h"
-
-#define line6_rawmidi_substream_midi(substream) \
- ((struct snd_line6_midi *)((substream)->rmidi->private_data))
-
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
- int length);
-
-/*
- Pass data received via USB to MIDI.
-*/
-void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
- int length)
-{
- if (line6->line6midi->substream_receive)
- snd_rawmidi_receive(line6->line6midi->substream_receive,
- data, length);
-}
-
-/*
- Read data from MIDI buffer and transmit them via USB.
-*/
-static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
-{
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
- struct snd_line6_midi *line6midi = line6->line6midi;
- struct midi_buffer *mb = &line6midi->midibuf_out;
- unsigned long flags;
- unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
- int req, done;
-
- spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
-
- for (;;) {
- req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
- done = snd_rawmidi_transmit_peek(substream, chunk, req);
-
- if (done == 0)
- break;
-
- line6_midibuf_write(mb, chunk, done);
- snd_rawmidi_transmit_ack(substream, done);
- }
-
- for (;;) {
- done = line6_midibuf_read(mb, chunk,
- LINE6_FALLBACK_MAXPACKETSIZE);
-
- if (done == 0)
- break;
-
- send_midi_async(line6, chunk, done);
- }
-
- spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
-}
-
-/*
- Notification of completion of MIDI transmission.
-*/
-static void midi_sent(struct urb *urb)
-{
- unsigned long flags;
- int status;
- int num;
- struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-
- status = urb->status;
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
-
- if (status == -ESHUTDOWN)
- return;
-
- spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
- num = --line6->line6midi->num_active_send_urbs;
-
- if (num == 0) {
- line6_midi_transmit(line6->line6midi->substream_transmit);
- num = line6->line6midi->num_active_send_urbs;
- }
-
- if (num == 0)
- wake_up(&line6->line6midi->send_wait);
-
- spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-/*
- Send an asynchronous MIDI message.
- Assumes that line6->line6midi->send_urb_lock is held
- (i.e., this function is serialized).
-*/
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
- int length)
-{
- struct urb *urb;
- int retval;
- unsigned char *transfer_buffer;
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
-
- if (urb == NULL) {
- dev_err(line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
-
- if (transfer_buffer == NULL) {
- usb_free_urb(urb);
- dev_err(line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- usb_fill_int_urb(urb, line6->usbdev,
- usb_sndbulkpipe(line6->usbdev,
- line6->ep_control_write),
- transfer_buffer, length, midi_sent, line6,
- line6->interval);
- urb->actual_length = 0;
- retval = usb_submit_urb(urb, GFP_ATOMIC);
-
- if (retval < 0) {
- dev_err(line6->ifcdev, "usb_submit_urb failed\n");
- usb_free_urb(urb);
- return retval;
- }
-
- ++line6->line6midi->num_active_send_urbs;
- return 0;
-}
-
-static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
- int up)
-{
- unsigned long flags;
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
-
- line6->line6midi->substream_transmit = substream;
- spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
-
- if (line6->line6midi->num_active_send_urbs == 0)
- line6_midi_transmit(substream);
-
- spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
-{
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
- struct snd_line6_midi *midi = line6->line6midi;
-
- wait_event_interruptible(midi->send_wait,
- midi->num_active_send_urbs == 0);
-}
-
-static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
- int up)
-{
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
-
- if (up)
- line6->line6midi->substream_receive = substream;
- else
- line6->line6midi->substream_receive = NULL;
-}
-
-static struct snd_rawmidi_ops line6_midi_output_ops = {
- .open = line6_midi_output_open,
- .close = line6_midi_output_close,
- .trigger = line6_midi_output_trigger,
- .drain = line6_midi_output_drain,
-};
-
-static struct snd_rawmidi_ops line6_midi_input_ops = {
- .open = line6_midi_input_open,
- .close = line6_midi_input_close,
- .trigger = line6_midi_input_trigger,
-};
-
-/*
- Cleanup the Line6 MIDI device.
-*/
-static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
-{
-}
-
-/* Create a MIDI device */
-static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
-{
- struct snd_rawmidi *rmidi;
- int err;
-
- err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
- &rmidi);
- if (err < 0)
- return err;
-
- rmidi->private_data = line6midi;
- rmidi->private_free = line6_cleanup_midi;
- strcpy(rmidi->id, line6midi->line6->properties->id);
- strcpy(rmidi->name, line6midi->line6->properties->name);
-
- rmidi->info_flags =
- SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &line6_midi_output_ops);
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &line6_midi_input_ops);
- return 0;
-}
-
-/* MIDI device destructor */
-static int snd_line6_midi_free(struct snd_device *device)
-{
- struct snd_line6_midi *line6midi = device->device_data;
-
- line6_midibuf_destroy(&line6midi->midibuf_in);
- line6_midibuf_destroy(&line6midi->midibuf_out);
- return 0;
-}
-
-/*
- Initialize the Line6 MIDI subsystem.
-*/
-int line6_init_midi(struct usb_line6 *line6)
-{
- static struct snd_device_ops midi_ops = {
- .dev_free = snd_line6_midi_free,
- };
-
- int err;
- struct snd_line6_midi *line6midi;
-
- if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) {
- /* skip MIDI initialization and report success */
- return 0;
- }
-
- line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
-
- if (line6midi == NULL)
- return -ENOMEM;
-
- err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
- if (err < 0) {
- kfree(line6midi);
- return err;
- }
-
- err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
- if (err < 0) {
- kfree(line6midi->midibuf_in.buf);
- kfree(line6midi);
- return err;
- }
-
- line6midi->line6 = line6;
- line6->line6midi = line6midi;
-
- err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
- &midi_ops);
- if (err < 0)
- return err;
-
- err = snd_line6_new_midi(line6midi);
- if (err < 0)
- return err;
-
- init_waitqueue_head(&line6midi->send_wait);
- spin_lock_init(&line6midi->send_urb_lock);
- spin_lock_init(&line6midi->midi_transmit_lock);
- return 0;
-}
+++ /dev/null
-/*
- * 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 MIDI_H
-#define MIDI_H
-
-#include <sound/rawmidi.h>
-
-#include "midibuf.h"
-
-#define MIDI_BUFFER_SIZE 1024
-
-struct snd_line6_midi {
- /**
- Pointer back to the Line6 driver data structure.
- */
- struct usb_line6 *line6;
-
- /**
- MIDI substream for receiving (or NULL if not active).
- */
- struct snd_rawmidi_substream *substream_receive;
-
- /**
- MIDI substream for transmitting (or NULL if not active).
- */
- struct snd_rawmidi_substream *substream_transmit;
-
- /**
- Number of currently active MIDI send URBs.
- */
- int num_active_send_urbs;
-
- /**
- Spin lock to protect updates of send_urb.
- */
- spinlock_t send_urb_lock;
-
- /**
- Spin lock to protect MIDI buffer handling.
- */
- spinlock_t midi_transmit_lock;
-
- /**
- Wait queue for MIDI transmission.
- */
- wait_queue_head_t send_wait;
-
- /**
- Buffer for incoming MIDI stream.
- */
- struct midi_buffer midibuf_in;
-
- /**
- Buffer for outgoing MIDI stream.
- */
- struct midi_buffer midibuf_out;
-};
-
-extern int line6_init_midi(struct usb_line6 *line6);
-extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
- int length);
-
-#endif
+++ /dev/null
-/*
- * 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 "midibuf.h"
-
-static int midibuf_message_length(unsigned char code)
-{
- int message_length;
-
- if (code < 0x80)
- message_length = -1;
- else if (code < 0xf0) {
- static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
-
- message_length = length[(code >> 4) - 8];
- } else {
- /*
- Note that according to the MIDI specification 0xf2 is
- the "Song Position Pointer", but this is used by Line6
- to send sysex messages to the host.
- */
- static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
- 1, 1, 1, -1, 1, 1
- };
- message_length = length[code & 0x0f];
- }
-
- return message_length;
-}
-
-static int midibuf_is_empty(struct midi_buffer *this)
-{
- return (this->pos_read == this->pos_write) && !this->full;
-}
-
-static int midibuf_is_full(struct midi_buffer *this)
-{
- return this->full;
-}
-
-void line6_midibuf_reset(struct midi_buffer *this)
-{
- this->pos_read = this->pos_write = this->full = 0;
- this->command_prev = -1;
-}
-
-int line6_midibuf_init(struct midi_buffer *this, int size, int split)
-{
- this->buf = kmalloc(size, GFP_KERNEL);
-
- if (this->buf == NULL)
- return -ENOMEM;
-
- this->size = size;
- this->split = split;
- line6_midibuf_reset(this);
- return 0;
-}
-
-void line6_midibuf_status(struct midi_buffer *this)
-{
- pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
- this->size, this->split, this->pos_read, this->pos_write,
- this->full, this->command_prev);
-}
-
-int line6_midibuf_bytes_free(struct midi_buffer *this)
-{
- return
- midibuf_is_full(this) ?
- 0 :
- (this->pos_read - this->pos_write + this->size - 1) % this->size +
- 1;
-}
-
-int line6_midibuf_bytes_used(struct midi_buffer *this)
-{
- return
- midibuf_is_empty(this) ?
- 0 :
- (this->pos_write - this->pos_read + this->size - 1) % this->size +
- 1;
-}
-
-int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
- int length)
-{
- int bytes_free;
- int length1, length2;
- int skip_active_sense = 0;
-
- if (midibuf_is_full(this) || (length <= 0))
- return 0;
-
- /* skip trailing active sense */
- if (data[length - 1] == 0xfe) {
- --length;
- skip_active_sense = 1;
- }
-
- bytes_free = line6_midibuf_bytes_free(this);
-
- if (length > bytes_free)
- length = bytes_free;
-
- if (length > 0) {
- length1 = this->size - this->pos_write;
-
- if (length < length1) {
- /* no buffer wraparound */
- memcpy(this->buf + this->pos_write, data, length);
- this->pos_write += length;
- } else {
- /* buffer wraparound */
- length2 = length - length1;
- memcpy(this->buf + this->pos_write, data, length1);
- memcpy(this->buf, data + length1, length2);
- this->pos_write = length2;
- }
-
- if (this->pos_write == this->pos_read)
- this->full = 1;
- }
-
- return length + skip_active_sense;
-}
-
-int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
- int length)
-{
- int bytes_used;
- int length1, length2;
- int command;
- int midi_length;
- int repeat = 0;
- int i;
-
- /* we need to be able to store at least a 3 byte MIDI message */
- if (length < 3)
- return -EINVAL;
-
- if (midibuf_is_empty(this))
- return 0;
-
- bytes_used = line6_midibuf_bytes_used(this);
-
- if (length > bytes_used)
- length = bytes_used;
-
- length1 = this->size - this->pos_read;
-
- /* check MIDI command length */
- command = this->buf[this->pos_read];
-
- if (command & 0x80) {
- midi_length = midibuf_message_length(command);
- this->command_prev = command;
- } else {
- if (this->command_prev > 0) {
- int midi_length_prev =
- midibuf_message_length(this->command_prev);
-
- if (midi_length_prev > 0) {
- midi_length = midi_length_prev - 1;
- repeat = 1;
- } else
- midi_length = -1;
- } else
- midi_length = -1;
- }
-
- if (midi_length < 0) {
- /* search for end of message */
- if (length < length1) {
- /* no buffer wraparound */
- for (i = 1; i < length; ++i)
- if (this->buf[this->pos_read + i] & 0x80)
- break;
-
- midi_length = i;
- } else {
- /* buffer wraparound */
- length2 = length - length1;
-
- for (i = 1; i < length1; ++i)
- if (this->buf[this->pos_read + i] & 0x80)
- break;
-
- if (i < length1)
- midi_length = i;
- else {
- for (i = 0; i < length2; ++i)
- if (this->buf[i] & 0x80)
- break;
-
- midi_length = length1 + i;
- }
- }
-
- if (midi_length == length)
- midi_length = -1; /* end of message not found */
- }
-
- if (midi_length < 0) {
- if (!this->split)
- return 0; /* command is not yet complete */
- } else {
- if (length < midi_length)
- return 0; /* command is not yet complete */
-
- length = midi_length;
- }
-
- if (length < length1) {
- /* no buffer wraparound */
- memcpy(data + repeat, this->buf + this->pos_read, length);
- this->pos_read += length;
- } else {
- /* buffer wraparound */
- length2 = length - length1;
- memcpy(data + repeat, this->buf + this->pos_read, length1);
- memcpy(data + repeat + length1, this->buf, length2);
- this->pos_read = length2;
- }
-
- if (repeat)
- data[0] = this->command_prev;
-
- this->full = 0;
- return length + repeat;
-}
-
-int line6_midibuf_ignore(struct midi_buffer *this, int length)
-{
- int bytes_used = line6_midibuf_bytes_used(this);
-
- if (length > bytes_used)
- length = bytes_used;
-
- this->pos_read = (this->pos_read + length) % this->size;
- this->full = 0;
- return length;
-}
-
-int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
-{
- int cmd = this->command_prev;
-
- if ((cmd >= 0x80) && (cmd < 0xf0))
- if ((mask & (1 << (cmd & 0x0f))) == 0)
- return 1;
-
- return 0;
-}
-
-void line6_midibuf_destroy(struct midi_buffer *this)
-{
- kfree(this->buf);
- this->buf = NULL;
-}
+++ /dev/null
-/*
- * 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 MIDIBUF_H
-#define MIDIBUF_H
-
-struct midi_buffer {
- unsigned char *buf;
- int size;
- int split;
- int pos_read, pos_write;
- int full;
- int command_prev;
-};
-
-extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
-extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
-extern void line6_midibuf_destroy(struct midi_buffer *mb);
-extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
-extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
-extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
- int length);
-extern void line6_midibuf_reset(struct midi_buffer *mb);
-extern int line6_midibuf_skip_message(struct midi_buffer *mb,
- unsigned short mask);
-extern void line6_midibuf_status(struct midi_buffer *mb);
-extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
- int length);
-
-#endif
+++ /dev/null
-/*
- * 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/control.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-static struct snd_line6_pcm *dev2pcm(struct device *dev)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- struct snd_line6_pcm *line6pcm = line6->line6pcm;
- return line6pcm;
-}
-
-/*
- "read" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
-}
-
-/*
- "write" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct snd_line6_pcm *line6pcm = dev2pcm(dev);
- int value;
- int ret;
-
- ret = kstrtoint(buf, 10, &value);
- if (ret < 0)
- return ret;
-
- line6pcm->impulse_volume = value;
-
- if (value > 0)
- line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
- else
- line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
-
- return count;
-}
-static DEVICE_ATTR_RW(impulse_volume);
-
-/*
- "read" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
-}
-
-/*
- "write" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int value;
- int ret;
-
- ret = kstrtoint(buf, 10, &value);
- if (ret < 0)
- return ret;
-
- dev2pcm(dev)->impulse_period = value;
- return count;
-}
-static DEVICE_ATTR_RW(impulse_period);
-
-#endif
-
-static bool test_flags(unsigned long flags0, unsigned long flags1,
- unsigned long mask)
-{
- return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
-}
-
-int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
-{
- unsigned long flags_old, flags_new, flags_final;
- int err;
-
- do {
- flags_old = ACCESS_ONCE(line6pcm->flags);
- flags_new = flags_old | channels;
- } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
- flags_final = flags_old;
-
- line6pcm->prev_fbuf = NULL;
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
- /* Invoked multiple times in a row so allocate once only */
- if (!line6pcm->buffer_in) {
- line6pcm->buffer_in =
- kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
- line6pcm->max_packet_size, GFP_KERNEL);
- if (!line6pcm->buffer_in) {
- err = -ENOMEM;
- goto pcm_acquire_error;
- }
-
- flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
- }
- }
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
- /*
- Waiting for completion of active URBs in the stop handler is
- a bug, we therefore report an error if capturing is restarted
- too soon.
- */
- if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
- dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
- return -EBUSY;
- }
-
- line6pcm->count_in = 0;
- line6pcm->prev_fsize = 0;
- err = line6_submit_audio_in_all_urbs(line6pcm);
-
- if (err < 0)
- goto pcm_acquire_error;
-
- flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
- }
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
- /* Invoked multiple times in a row so allocate once only */
- if (!line6pcm->buffer_out) {
- line6pcm->buffer_out =
- kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
- line6pcm->max_packet_size, GFP_KERNEL);
- if (!line6pcm->buffer_out) {
- err = -ENOMEM;
- goto pcm_acquire_error;
- }
-
- flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
- }
- }
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
- /*
- See comment above regarding PCM restart.
- */
- if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
- dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
- return -EBUSY;
- }
-
- line6pcm->count_out = 0;
- err = line6_submit_audio_out_all_urbs(line6pcm);
-
- if (err < 0)
- goto pcm_acquire_error;
-
- flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
- }
-
- return 0;
-
-pcm_acquire_error:
- /*
- If not all requested resources/streams could be obtained, release
- those which were successfully obtained (if any).
- */
- line6_pcm_release(line6pcm, flags_final & channels);
- return err;
-}
-
-int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
-{
- unsigned long flags_old, flags_new;
-
- do {
- flags_old = ACCESS_ONCE(line6pcm->flags);
- flags_new = flags_old & ~channels;
- } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
- line6_unlink_audio_in_urbs(line6pcm);
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
- line6_wait_clear_audio_in_urbs(line6pcm);
- line6_free_capture_buffer(line6pcm);
- }
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
- line6_unlink_audio_out_urbs(line6pcm);
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
- line6_wait_clear_audio_out_urbs(line6pcm);
- line6_free_playback_buffer(line6pcm);
- }
-
- return 0;
-}
-
-/* trigger callback */
-int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- struct snd_pcm_substream *s;
- int err;
- unsigned long flags;
-
- spin_lock_irqsave(&line6pcm->lock_trigger, flags);
- clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
-
- snd_pcm_group_for_each_entry(s, substream) {
- switch (s->stream) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- err = snd_line6_playback_trigger(line6pcm, cmd);
-
- if (err < 0) {
- spin_unlock_irqrestore(&line6pcm->lock_trigger,
- flags);
- return err;
- }
-
- break;
-
- case SNDRV_PCM_STREAM_CAPTURE:
- err = snd_line6_capture_trigger(line6pcm, cmd);
-
- if (err < 0) {
- spin_unlock_irqrestore(&line6pcm->lock_trigger,
- flags);
- return err;
- }
-
- break;
-
- default:
- dev_err(line6pcm->line6->ifcdev,
- "Unknown stream direction %d\n", s->stream);
- }
- }
-
- spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
- return 0;
-}
-
-/* control info callback */
-static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 256;
- return 0;
-}
-
-/* control get callback */
-static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int i;
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- for (i = 2; i--;)
- ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
-
- return 0;
-}
-
-/* control put callback */
-static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int i, changed = 0;
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- for (i = 2; i--;)
- if (line6pcm->volume_playback[i] !=
- ucontrol->value.integer.value[i]) {
- line6pcm->volume_playback[i] =
- ucontrol->value.integer.value[i];
- changed = 1;
- }
-
- return changed;
-}
-
-/* control definition */
-static struct snd_kcontrol_new line6_control_playback = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Volume",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_line6_control_playback_info,
- .get = snd_line6_control_playback_get,
- .put = snd_line6_control_playback_put
-};
-
-/*
- Cleanup the PCM device.
-*/
-static void line6_cleanup_pcm(struct snd_pcm *pcm)
-{
- int i;
- struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
- device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
-#endif
-
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (line6pcm->urb_audio_out[i]) {
- usb_kill_urb(line6pcm->urb_audio_out[i]);
- usb_free_urb(line6pcm->urb_audio_out[i]);
- }
- if (line6pcm->urb_audio_in[i]) {
- usb_kill_urb(line6pcm->urb_audio_in[i]);
- usb_free_urb(line6pcm->urb_audio_in[i]);
- }
- }
-}
-
-/* create a PCM device */
-static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
-{
- struct snd_pcm *pcm;
- int err;
-
- err = snd_pcm_new(line6pcm->line6->card,
- (char *)line6pcm->line6->properties->name,
- 0, 1, 1, &pcm);
- if (err < 0)
- return err;
-
- pcm->private_data = line6pcm;
- pcm->private_free = line6_cleanup_pcm;
- line6pcm->pcm = pcm;
- strcpy(pcm->name, line6pcm->line6->properties->name);
-
- /* set operators */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_line6_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
-
- /* pre-allocation of buffers */
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data
- (GFP_KERNEL), 64 * 1024,
- 128 * 1024);
-
- return 0;
-}
-
-/* PCM device destructor */
-static int snd_line6_pcm_free(struct snd_device *device)
-{
- return 0;
-}
-
-/*
- Stop substream if still running.
-*/
-static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
-{
- if (substream->runtime && snd_pcm_running(substream)) {
- snd_pcm_stream_lock_irq(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
- snd_pcm_stream_unlock_irq(substream);
- }
-}
-
-/*
- Stop PCM stream.
-*/
-void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
-{
- pcm_disconnect_substream(get_substream
- (line6pcm, SNDRV_PCM_STREAM_CAPTURE));
- pcm_disconnect_substream(get_substream
- (line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
- line6_unlink_wait_clear_audio_out_urbs(line6pcm);
- line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
- Create and register the PCM device and mixer entries.
- Create URBs for playback and capture.
-*/
-int line6_init_pcm(struct usb_line6 *line6,
- struct line6_pcm_properties *properties)
-{
- static struct snd_device_ops pcm_ops = {
- .dev_free = snd_line6_pcm_free,
- };
-
- int err;
- int ep_read = 0, ep_write = 0;
- struct snd_line6_pcm *line6pcm;
-
- if (!(line6->properties->capabilities & LINE6_BIT_PCM))
- return 0; /* skip PCM initialization and report success */
-
- /* initialize PCM subsystem based on product id: */
- switch (line6->product) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTLIVE:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
- case LINE6_DEVID_PODHD500:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- ep_read = 0x86;
- ep_write = 0x02;
- break;
-
- case LINE6_DEVID_POCKETPOD:
- ep_read = 0x82;
- ep_write = 0x02;
- break;
-
- case LINE6_DEVID_GUITARPORT:
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
- /* this is for interface_number == 1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX2:
- ep_read = 0x87;
- ep_write = 0x00;
- break; */
-
- default:
- MISSING_CASE;
- }
-
- line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
-
- if (line6pcm == NULL)
- return -ENOMEM;
-
- line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
- line6pcm->volume_monitor = 255;
- line6pcm->line6 = line6;
- line6pcm->ep_audio_read = ep_read;
- line6pcm->ep_audio_write = ep_write;
-
- /* Read and write buffers are sized identically, so choose minimum */
- line6pcm->max_packet_size = min(
- usb_maxpacket(line6->usbdev,
- usb_rcvisocpipe(line6->usbdev, ep_read), 0),
- usb_maxpacket(line6->usbdev,
- usb_sndisocpipe(line6->usbdev, ep_write), 1));
-
- line6pcm->properties = properties;
- line6->line6pcm = line6pcm;
-
- /* PCM device: */
- err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
- if (err < 0)
- return err;
-
- err = snd_line6_new_pcm(line6pcm);
- if (err < 0)
- return err;
-
- spin_lock_init(&line6pcm->lock_audio_out);
- spin_lock_init(&line6pcm->lock_audio_in);
- spin_lock_init(&line6pcm->lock_trigger);
-
- err = line6_create_audio_out_urbs(line6pcm);
- if (err < 0)
- return err;
-
- err = line6_create_audio_in_urbs(line6pcm);
- if (err < 0)
- return err;
-
- /* mixer: */
- err =
- snd_ctl_add(line6->card,
- snd_ctl_new1(&line6_control_playback, line6pcm));
- if (err < 0)
- return err;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- /* impulse response test: */
- err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
- if (err < 0)
- return err;
-
- err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
- if (err < 0)
- return err;
-
- line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
-#endif
-
- return 0;
-}
-
-/* prepare pcm callback */
-int snd_line6_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- switch (substream->stream) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
- line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-
- break;
-
- case SNDRV_PCM_STREAM_CAPTURE:
- if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
- line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-
- break;
-
- default:
- MISSING_CASE;
- }
-
- if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
- line6pcm->count_out = 0;
- line6pcm->pos_out = 0;
- line6pcm->pos_out_done = 0;
- line6pcm->bytes_out = 0;
- line6pcm->count_in = 0;
- line6pcm->pos_in_done = 0;
- line6pcm->bytes_in = 0;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * 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.
- *
- */
-
-/*
- PCM interface to POD series devices.
-*/
-
-#ifndef PCM_H
-#define PCM_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "usbdefs.h"
-
-/* number of URBs */
-#define LINE6_ISO_BUFFERS 2
-
-/*
- number of USB frames per URB
- The Line6 Windows driver always transmits two frames per packet, but
- the Linux driver performs significantly better (i.e., lower latency)
- with only one frame per packet.
-*/
-#define LINE6_ISO_PACKETS 1
-
-/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
-#define LINE6_ISO_INTERVAL 1
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-#define LINE6_IMPULSE_DEFAULT_PERIOD 100
-#endif
-
-/*
- Get substream from Line6 PCM data structure
-*/
-#define get_substream(line6pcm, stream) \
- (line6pcm->pcm->streams[stream].substream)
-
-/*
- PCM mode bits.
-
- There are several features of the Line6 USB driver which require PCM
- data to be exchanged with the device:
- *) PCM playback and capture via ALSA
- *) software monitoring (for devices without hardware monitoring)
- *) optional impulse response measurement
- However, from the device's point of view, there is just a single
- capture and playback stream, which must be shared between these
- subsystems. It is therefore necessary to maintain the state of the
- subsystems with respect to PCM usage. We define several constants of
- the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
- following meanings:
- *) <subsystem> is one of
- -) ALSA: PCM playback and capture via ALSA
- -) MONITOR: software monitoring
- -) IMPULSE: optional impulse response measurement
- *) <direction> is one of
- -) PLAYBACK: audio output (from host to device)
- -) CAPTURE: audio input (from device to host)
- *) <resource> is one of
- -) BUFFER: buffer required by PCM data stream
- -) STREAM: actual PCM data stream
-
- The subsystems call line6_pcm_acquire() to acquire the (shared)
- resources needed for a particular operation (e.g., allocate the buffer
- for ALSA playback or start the capture stream for software monitoring).
- When a resource is no longer needed, it is released by calling
- line6_pcm_release(). Buffer allocation and stream startup are handled
- separately to allow the ALSA kernel driver to perform them at
- appropriate places (since the callback which starts a PCM stream is not
- allowed to sleep).
-*/
-enum {
- /* individual bit indices: */
- LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
- LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
- LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
- LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
- LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
- LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
- LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
- LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
- LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
- LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
- LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
- LINE6_INDEX_PAUSE_PLAYBACK,
- LINE6_INDEX_PREPARED,
-
- /* individual bit masks: */
- LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
- LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
- LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
- LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
- LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
- LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
- LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
- LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
- LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
- LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
- LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
-#endif
- LINE6_BIT(PAUSE_PLAYBACK),
- LINE6_BIT(PREPARED),
-
- /* combined bit masks (by operation): */
- LINE6_BITS_PCM_ALSA_BUFFER =
- LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
-
- LINE6_BITS_PCM_ALSA_STREAM =
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
-
- LINE6_BITS_PCM_MONITOR =
- LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
- LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
- LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BITS_PCM_IMPULSE =
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
- LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
- LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
-
- /* combined bit masks (by direction): */
- LINE6_BITS_PLAYBACK_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
-#endif
- LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER ,
-
- LINE6_BITS_PLAYBACK_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
-#endif
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
- LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM ,
-
- LINE6_BITS_CAPTURE_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
-#endif
- LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
- LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER ,
-
- LINE6_BITS_CAPTURE_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
-#endif
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
- LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
-
- LINE6_BITS_STREAM =
- LINE6_BITS_PLAYBACK_STREAM |
- LINE6_BITS_CAPTURE_STREAM
-};
-
-struct line6_pcm_properties {
- struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
- struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
- int bytes_per_frame;
-};
-
-struct snd_line6_pcm {
- /**
- Pointer back to the Line6 driver data structure.
- */
- struct usb_line6 *line6;
-
- /**
- Properties.
- */
- struct line6_pcm_properties *properties;
-
- /**
- ALSA pcm stream
- */
- struct snd_pcm *pcm;
-
- /**
- URBs for audio playback.
- */
- struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
-
- /**
- URBs for audio capture.
- */
- struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
-
- /**
- Temporary buffer for playback.
- Since the packet size is not known in advance, this buffer is
- large enough to store maximum size packets.
- */
- unsigned char *buffer_out;
-
- /**
- Temporary buffer for capture.
- Since the packet size is not known in advance, this buffer is
- large enough to store maximum size packets.
- */
- unsigned char *buffer_in;
-
- /**
- Previously captured frame (for software monitoring).
- */
- unsigned char *prev_fbuf;
-
- /**
- Size of previously captured frame (for software monitoring).
- */
- int prev_fsize;
-
- /**
- Free frame position in the playback buffer.
- */
- snd_pcm_uframes_t pos_out;
-
- /**
- Count processed bytes for playback.
- This is modulo period size (to determine when a period is
- finished).
- */
- unsigned bytes_out;
-
- /**
- Counter to create desired playback sample rate.
- */
- unsigned count_out;
-
- /**
- Playback period size in bytes
- */
- unsigned period_out;
-
- /**
- Processed frame position in the playback buffer.
- The contents of the output ring buffer have been consumed by
- the USB subsystem (i.e., sent to the USB device) up to this
- position.
- */
- snd_pcm_uframes_t pos_out_done;
-
- /**
- Count processed bytes for capture.
- This is modulo period size (to determine when a period is
- finished).
- */
- unsigned bytes_in;
-
- /**
- Counter to create desired capture sample rate.
- */
- unsigned count_in;
-
- /**
- Capture period size in bytes
- */
- unsigned period_in;
-
- /**
- Processed frame position in the capture buffer.
- The contents of the output ring buffer have been consumed by
- the USB subsystem (i.e., sent to the USB device) up to this
- position.
- */
- snd_pcm_uframes_t pos_in_done;
-
- /**
- Bit mask of active playback URBs.
- */
- unsigned long active_urb_out;
-
- /**
- Maximum size of USB packet.
- */
- int max_packet_size;
-
- /**
- USB endpoint for listening to audio data.
- */
- int ep_audio_read;
-
- /**
- USB endpoint for writing audio data.
- */
- int ep_audio_write;
-
- /**
- Bit mask of active capture URBs.
- */
- unsigned long active_urb_in;
-
- /**
- Bit mask of playback URBs currently being unlinked.
- */
- unsigned long unlink_urb_out;
-
- /**
- Bit mask of capture URBs currently being unlinked.
- */
- unsigned long unlink_urb_in;
-
- /**
- Spin lock to protect updates of the playback buffer positions (not
- contents!)
- */
- spinlock_t lock_audio_out;
-
- /**
- Spin lock to protect updates of the capture buffer positions (not
- contents!)
- */
- spinlock_t lock_audio_in;
-
- /**
- Spin lock to protect trigger.
- */
- spinlock_t lock_trigger;
-
- /**
- PCM playback volume (left and right).
- */
- int volume_playback[2];
-
- /**
- PCM monitor volume.
- */
- int volume_monitor;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- /**
- Volume of impulse response test signal (if zero, test is disabled).
- */
- int impulse_volume;
-
- /**
- Period of impulse response test signal.
- */
- int impulse_period;
-
- /**
- Counter for impulse response test signal.
- */
- int impulse_count;
-#endif
-
- /**
- Several status bits (see LINE6_BIT_*).
- */
- unsigned long flags;
-
- int last_frame_in, last_frame_out;
-};
-
-extern int line6_init_pcm(struct usb_line6 *line6,
- struct line6_pcm_properties *properties);
-extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
-extern int snd_line6_prepare(struct snd_pcm_substream *substream);
-extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
-extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
-extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
-
-#endif
+++ /dev/null
-/*
- * 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"
-#include "playback.h"
-
-/*
- Software stereo volume control.
-*/
-static void change_volume(struct urb *urb_out, int volume[],
- int bytes_per_frame)
-{
- int chn = 0;
-
- if (volume[0] == 256 && volume[1] == 256)
- return; /* maximum volume - no change */
-
- if (bytes_per_frame == 4) {
- short *p, *buf_end;
-
- p = (short *)urb_out->transfer_buffer;
- buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
-
- for (; p < buf_end; ++p) {
- *p = (*p * volume[chn & 1]) >> 8;
- ++chn;
- }
- } else if (bytes_per_frame == 6) {
- unsigned char *p, *buf_end;
-
- p = (unsigned char *)urb_out->transfer_buffer;
- buf_end = p + urb_out->transfer_buffer_length;
-
- for (; p < buf_end; p += 3) {
- int val;
-
- val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
- val = (val * volume[chn & 1]) >> 8;
- p[0] = val;
- p[1] = val >> 8;
- p[2] = val >> 16;
- ++chn;
- }
- }
-}
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-/*
- Create signal for impulse response test.
-*/
-static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
- struct urb *urb_out, int bytes_per_frame)
-{
- int frames = urb_out->transfer_buffer_length / bytes_per_frame;
-
- if (bytes_per_frame == 4) {
- int i;
- short *pi = (short *)line6pcm->prev_fbuf;
- short *po = (short *)urb_out->transfer_buffer;
-
- for (i = 0; i < frames; ++i) {
- po[0] = pi[0];
- po[1] = 0;
- pi += 2;
- po += 2;
- }
- } else if (bytes_per_frame == 6) {
- int i, j;
- unsigned char *pi = line6pcm->prev_fbuf;
- unsigned char *po = urb_out->transfer_buffer;
-
- for (i = 0; i < frames; ++i) {
- for (j = 0; j < bytes_per_frame / 2; ++j)
- po[j] = pi[j];
-
- for (; j < bytes_per_frame; ++j)
- po[j] = 0;
-
- pi += bytes_per_frame;
- po += bytes_per_frame;
- }
- }
- if (--line6pcm->impulse_count <= 0) {
- ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
- 1] =
- line6pcm->impulse_volume;
- line6pcm->impulse_count = line6pcm->impulse_period;
- }
-}
-
-#endif
-
-/*
- Add signal to buffer for software monitoring.
-*/
-static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
- int volume, int bytes_per_frame)
-{
- if (volume == 0)
- return; /* zero volume - no change */
-
- if (bytes_per_frame == 4) {
- short *pi, *po, *buf_end;
-
- pi = (short *)signal;
- po = (short *)urb_out->transfer_buffer;
- buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
-
- for (; po < buf_end; ++pi, ++po)
- *po += (*pi * volume) >> 8;
- }
-
- /*
- We don't need to handle devices with 6 bytes per frame here
- since they all support hardware monitoring.
- */
-}
-
-/*
- Find a free URB, prepare audio data, and submit URB.
-*/
-static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
-{
- int index;
- unsigned long flags;
- int i, urb_size, urb_frames;
- int ret;
- const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
- const int frame_increment =
- line6pcm->properties->snd_line6_rates.rats[0].num_min;
- const int frame_factor =
- line6pcm->properties->snd_line6_rates.rats[0].den *
- (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
- struct urb *urb_out;
-
- spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
- index =
- find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
-
- if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
- dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
- return -EINVAL;
- }
-
- urb_out = line6pcm->urb_audio_out[index];
- urb_size = 0;
-
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- /* compute frame size for given sampling rate */
- int fsize = 0;
- struct usb_iso_packet_descriptor *fout =
- &urb_out->iso_frame_desc[i];
-
- if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
- fsize = line6pcm->prev_fsize;
-
- if (fsize == 0) {
- int n;
-
- line6pcm->count_out += frame_increment;
- n = line6pcm->count_out / frame_factor;
- line6pcm->count_out -= n * frame_factor;
- fsize = n * bytes_per_frame;
- }
-
- fout->offset = urb_size;
- fout->length = fsize;
- urb_size += fsize;
- }
-
- if (urb_size == 0) {
- /* can't determine URB size */
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
- dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
- return -EINVAL;
- }
-
- urb_frames = urb_size / bytes_per_frame;
- urb_out->transfer_buffer =
- line6pcm->buffer_out +
- index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
- urb_out->transfer_buffer_length = urb_size;
- urb_out->context = line6pcm;
-
- if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
- !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
- struct snd_pcm_runtime *runtime =
- get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
-
- if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
- /*
- The transferred area goes over buffer boundary,
- copy the data to the temp buffer.
- */
- int len;
-
- len = runtime->buffer_size - line6pcm->pos_out;
-
- if (len > 0) {
- memcpy(urb_out->transfer_buffer,
- runtime->dma_area +
- line6pcm->pos_out * bytes_per_frame,
- len * bytes_per_frame);
- memcpy(urb_out->transfer_buffer +
- len * bytes_per_frame, runtime->dma_area,
- (urb_frames - len) * bytes_per_frame);
- } else
- dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
- len);
- } else {
- memcpy(urb_out->transfer_buffer,
- runtime->dma_area +
- line6pcm->pos_out * bytes_per_frame,
- urb_out->transfer_buffer_length);
- }
-
- line6pcm->pos_out += urb_frames;
- if (line6pcm->pos_out >= runtime->buffer_size)
- line6pcm->pos_out -= runtime->buffer_size;
- } else {
- memset(urb_out->transfer_buffer, 0,
- urb_out->transfer_buffer_length);
- }
-
- change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
-
- if (line6pcm->prev_fbuf != NULL) {
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
- create_impulse_test_signal(line6pcm, urb_out,
- bytes_per_frame);
- if (line6pcm->flags &
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
- line6_capture_copy(line6pcm,
- urb_out->transfer_buffer,
- urb_out->
- transfer_buffer_length);
- line6_capture_check_period(line6pcm,
- urb_out->transfer_buffer_length);
- }
- } else {
-#endif
- if (!
- (line6pcm->line6->
- properties->capabilities & LINE6_BIT_HWMON)
- && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
- && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
- add_monitor_signal(urb_out, line6pcm->prev_fbuf,
- line6pcm->volume_monitor,
- bytes_per_frame);
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- }
-#endif
- }
-
- ret = usb_submit_urb(urb_out, GFP_ATOMIC);
-
- if (ret == 0)
- set_bit(index, &line6pcm->active_urb_out);
- else
- dev_err(line6pcm->line6->ifcdev,
- "URB out #%d submission failed (%d)\n", index, ret);
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
- return 0;
-}
-
-/*
- Submit all currently available playback URBs.
-*/
-int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
-{
- int ret, i;
-
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- ret = submit_audio_out_urb(line6pcm);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-/*
- Unlink all currently active playback URBs.
-*/
-void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- unsigned int i;
-
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_out)) {
- if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
- struct urb *u = line6pcm->urb_audio_out[i];
-
- usb_unlink_urb(u);
- }
- }
- }
-}
-
-/*
- Wait until unlinking of all currently active playback URBs has been
- finished.
-*/
-void line6_wait_clear_audio_out_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_out))
- 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 playback URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- line6_unlink_audio_out_urbs(line6pcm);
- line6_wait_clear_audio_out_urbs(line6pcm);
-}
-
-void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
-{
- kfree(line6pcm->buffer_out);
- line6pcm->buffer_out = NULL;
-}
-
-/*
- Callback for completed playback URB.
-*/
-static void audio_out_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;
- struct snd_pcm_substream *substream =
- get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
-
-#if USE_CLEAR_BUFFER_WORKAROUND
- memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
-#endif
-
- line6pcm->last_frame_out = urb->start_frame;
-
- /* find index of URB */
- for (index = LINE6_ISO_BUFFERS; index--;)
- if (urb == line6pcm->urb_audio_out[index])
- break;
-
- if (index < 0)
- return; /* URB has been unlinked asynchronously */
-
- for (i = LINE6_ISO_PACKETS; i--;)
- length += urb->iso_frame_desc[i].length;
-
- spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
-
- if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- line6pcm->pos_out_done +=
- length / line6pcm->properties->bytes_per_frame;
-
- if (line6pcm->pos_out_done >= runtime->buffer_size)
- line6pcm->pos_out_done -= runtime->buffer_size;
- }
-
- clear_bit(index, &line6pcm->active_urb_out);
-
- for (i = LINE6_ISO_PACKETS; i--;)
- if (urb->iso_frame_desc[i].status == -EXDEV) {
- shutdown = 1;
- break;
- }
-
- if (test_and_clear_bit(index, &line6pcm->unlink_urb_out))
- shutdown = 1;
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-
- if (!shutdown) {
- submit_audio_out_urb(line6pcm);
-
- if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
- &line6pcm->flags)) {
- line6pcm->bytes_out += length;
- if (line6pcm->bytes_out >= line6pcm->period_out) {
- line6pcm->bytes_out %= line6pcm->period_out;
- snd_pcm_period_elapsed(substream);
- }
- }
- }
-}
-
-/* open playback callback */
-static int snd_line6_playback_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);
-
- err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- (&line6pcm->
- properties->snd_line6_rates));
- if (err < 0)
- return err;
-
- runtime->hw = line6pcm->properties->snd_line6_playback_hw;
- return 0;
-}
-
-/* close playback callback */
-static int snd_line6_playback_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-/* hw_params playback callback */
-static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- int ret;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- /* -- Florian Demski [FD] */
- /* don't ask me why, but this fixes the bug on my machine */
- if (line6pcm == NULL) {
- if (substream->pcm == NULL)
- return -ENOMEM;
- if (substream->pcm->private_data == NULL)
- return -ENOMEM;
- substream->private_data = substream->pcm->private_data;
- line6pcm = snd_pcm_substream_chip(substream);
- }
- /* -- [FD] end */
-
- ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-
- if (ret < 0)
- return ret;
-
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0) {
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
- return ret;
- }
-
- line6pcm->period_out = params_period_bytes(hw_params);
- return 0;
-}
-
-/* hw_free playback callback */
-static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger playback callback */
-int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
- int err;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_RESUME:
-#endif
- err = line6_pcm_acquire(line6pcm,
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
- err = line6_pcm_release(line6pcm,
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* playback pointer callback */
-static snd_pcm_uframes_t
-snd_line6_playback_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- return line6pcm->pos_out_done;
-}
-
-/* playback operators */
-struct snd_pcm_ops snd_line6_playback_ops = {
- .open = snd_line6_playback_open,
- .close = snd_line6_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_line6_playback_hw_params,
- .hw_free = snd_line6_playback_hw_free,
- .prepare = snd_line6_prepare,
- .trigger = snd_line6_trigger,
- .pointer = snd_line6_playback_pointer,
-};
-
-int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- int i;
-
- /* create audio URBs and fill in constant values: */
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- struct urb *urb;
-
- /* URB for audio out: */
- urb = line6pcm->urb_audio_out[i] =
- usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
-
- if (urb == NULL) {
- dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- urb->dev = line6pcm->line6->usbdev;
- urb->pipe =
- usb_sndisocpipe(line6pcm->line6->usbdev,
- line6pcm->ep_audio_write &
- USB_ENDPOINT_NUMBER_MASK);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->start_frame = -1;
- urb->number_of_packets = LINE6_ISO_PACKETS;
- urb->interval = LINE6_ISO_INTERVAL;
- urb->error_count = 0;
- urb->complete = audio_out_callback;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * 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 PLAYBACK_H
-#define PLAYBACK_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-
-/*
- * When the TonePort is used with jack in full duplex mode and the outputs are
- * not connected, the software monitor produces an ugly noise since everything
- * written to the output buffer (i.e., the input signal) will be repeated in
- * the next period (sounds like a delay effect). As a workaround, the output
- * buffer is cleared after the data have been read, but there must be a better
- * solution. Until one is found, this workaround can be used to fix the
- * problem.
- */
-#define USE_CLEAR_BUFFER_WORKAROUND 1
-
-extern struct snd_pcm_ops snd_line6_playback_ops;
-
-extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
- *line6pcm);
-extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
+++ /dev/null
-/*
- * 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 <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#define POD_SYSEX_CODE 3
-#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
-
-/* *INDENT-OFF* */
-
-enum {
- POD_SYSEX_SAVE = 0x24,
- POD_SYSEX_SYSTEM = 0x56,
- POD_SYSEX_SYSTEMREQ = 0x57,
- /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
- POD_SYSEX_STORE = 0x71,
- POD_SYSEX_FINISH = 0x72,
- POD_SYSEX_DUMPMEM = 0x73,
- POD_SYSEX_DUMP = 0x74,
- POD_SYSEX_DUMPREQ = 0x75
-
- /* dumps entire internal memory of PODxt Pro */
- /* POD_SYSEX_DUMPMEM2 = 0x76 */
-};
-
-enum {
- POD_MONITOR_LEVEL = 0x04,
- POD_SYSTEM_INVALID = 0x10000
-};
-
-/* *INDENT-ON* */
-
-enum {
- POD_DUMP_MEMORY = 2
-};
-
-enum {
- POD_BUSY_READ,
- POD_BUSY_WRITE,
- POD_CHANNEL_DIRTY,
- POD_SAVE_PRESSED,
- POD_BUSY_MIDISEND
-};
-
-static struct snd_ratden pod_ratden = {
- .num_min = 78125,
- .num_max = 78125,
- .num_step = 1,
- .den = 2
-};
-
-static struct line6_pcm_properties pod_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 39062,
- .rate_max = 39063,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 39062,
- .rate_max = 39063,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_rates = {
- .nrats = 1,
- .rats = &pod_ratden},
- .bytes_per_frame = POD_BYTES_PER_FRAME
-};
-
-static const char pod_version_header[] = {
- 0xf2, 0x7e, 0x7f, 0x06, 0x02
-};
-
-/* forward declarations: */
-static void pod_startup2(unsigned long data);
-static void pod_startup3(struct usb_line6_pod *pod);
-
-static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
- int size)
-{
- return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
- size);
-}
-
-/*
- Process a completely received message.
-*/
-void line6_pod_process_message(struct usb_line6_pod *pod)
-{
- const unsigned char *buf = pod->line6.buffer_message;
-
- if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
- pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
- pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
- (int) buf[10];
- pod_startup3(pod);
- return;
- }
-
- /* Only look for sysex messages from this device */
- if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
- buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
- return;
- }
- if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
- return;
-
- if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
- short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
- ((int)buf[9] << 4) | (int)buf[10];
- pod->monitor_level = value;
- }
-}
-
-/*
- Transmit PODxt Pro control parameter.
-*/
-void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
- u8 value)
-{
- line6_transmit_parameter(&pod->line6, param, value);
-}
-
-/*
- Send system parameter (from integer).
-*/
-static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
- int code)
-{
- char *sysex;
- static const int size = 5;
-
- sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
- if (!sysex)
- return -ENOMEM;
- sysex[SYSEX_DATA_OFS] = code;
- sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
- sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
- sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
- sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
- line6_send_sysex_message(&pod->line6, sysex, size);
- kfree(sysex);
- return 0;
-}
-
-/*
- "read" request on "serial_number" special file.
-*/
-static ssize_t serial_number_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- return sprintf(buf, "%d\n", pod->serial_number);
-}
-
-/*
- "read" request on "firmware_version" special file.
-*/
-static ssize_t firmware_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
- pod->firmware_version % 100);
-}
-
-/*
- "read" request on "device_id" special file.
-*/
-static ssize_t device_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- return sprintf(buf, "%d\n", pod->device_id);
-}
-
-/*
- POD startup procedure.
- This is a sequence of functions with special requirements (e.g., must
- not run immediately after initialization, must not run in interrupt
- context). After the last one has finished, the device is ready to use.
-*/
-
-static void pod_startup1(struct usb_line6_pod *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
- (unsigned long)pod);
-}
-
-static void pod_startup2(unsigned long data)
-{
- struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
- struct usb_line6 *line6 = &pod->line6;
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
-
- /* request firmware version: */
- line6_version_request_async(line6);
-}
-
-static void pod_startup3(struct usb_line6_pod *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&pod->startup_work);
-}
-
-static void pod_startup4(struct work_struct *work)
-{
- struct usb_line6_pod *pod =
- container_of(work, struct usb_line6_pod, startup_work);
- struct usb_line6 *line6 = &pod->line6;
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
-
- /* serial number: */
- line6_read_serial_number(&pod->line6, &pod->serial_number);
-
- /* ALSA audio interface: */
- line6_register_audio(line6);
-}
-
-/* POD special files: */
-static DEVICE_ATTR_RO(device_id);
-static DEVICE_ATTR_RO(firmware_version);
-static DEVICE_ATTR_RO(serial_number);
-
-/* control info callback */
-static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 65535;
- return 0;
-}
-
-/* control get callback */
-static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
-
- ucontrol->value.integer.value[0] = pod->monitor_level;
- return 0;
-}
-
-/* control put callback */
-static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
-
- if (ucontrol->value.integer.value[0] == pod->monitor_level)
- return 0;
-
- pod->monitor_level = ucontrol->value.integer.value[0];
- pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
- POD_MONITOR_LEVEL);
- return 1;
-}
-
-/* control definition */
-static struct snd_kcontrol_new pod_control_monitor = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Monitor Playback Volume",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_pod_control_monitor_info,
- .get = snd_pod_control_monitor_get,
- .put = snd_pod_control_monitor_put
-};
-
-/*
- POD destructor.
-*/
-static void pod_destruct(struct usb_interface *interface)
-{
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- if (pod == NULL)
- return;
- line6_cleanup_audio(&pod->line6);
-
- del_timer(&pod->startup_timer);
- cancel_work_sync(&pod->startup_work);
-}
-
-/*
- Create sysfs entries.
-*/
-static int pod_create_files2(struct device *dev)
-{
- int err;
-
- CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
- CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
- CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
- return 0;
-}
-
-/*
- Try to init POD device.
-*/
-static int pod_try_init(struct usb_interface *interface,
- struct usb_line6_pod *pod)
-{
- int err;
- struct usb_line6 *line6 = &pod->line6;
-
- init_timer(&pod->startup_timer);
- INIT_WORK(&pod->startup_work, pod_startup4);
-
- if ((interface == NULL) || (pod == NULL))
- return -ENODEV;
-
- /* create sysfs entries: */
- err = pod_create_files2(&interface->dev);
- if (err < 0)
- return err;
-
- /* initialize audio system: */
- err = line6_init_audio(line6);
- if (err < 0)
- return err;
-
- /* initialize MIDI subsystem: */
- err = line6_init_midi(line6);
- if (err < 0)
- return err;
-
- /* initialize PCM subsystem: */
- err = line6_init_pcm(line6, &pod_pcm_properties);
- if (err < 0)
- return err;
-
- /* register monitor control: */
- err = snd_ctl_add(line6->card,
- snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
- if (err < 0)
- return err;
-
- /*
- When the sound card is registered at this point, the PODxt Live
- displays "Invalid Code Error 07", so we do it later in the event
- handler.
- */
-
- if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
- pod->monitor_level = POD_SYSTEM_INVALID;
-
- /* initiate startup procedure: */
- pod_startup1(pod);
- }
-
- return 0;
-}
-
-/*
- Init POD device (and clean up in case of failure).
-*/
-int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
-{
- int err = pod_try_init(interface, pod);
-
- if (err < 0)
- pod_destruct(interface);
-
- return err;
-}
-
-/*
- POD device disconnected.
-*/
-void line6_pod_disconnect(struct usb_interface *interface)
-{
- struct usb_line6_pod *pod;
-
- if (interface == NULL)
- return;
- pod = usb_get_intfdata(interface);
-
- if (pod != NULL) {
- struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
- struct device *dev = &interface->dev;
-
- if (line6pcm != NULL)
- line6_pcm_disconnect(line6pcm);
-
- if (dev != NULL) {
- /* remove sysfs entries: */
- device_remove_file(dev, &dev_attr_device_id);
- device_remove_file(dev, &dev_attr_firmware_version);
- device_remove_file(dev, &dev_attr_serial_number);
- }
- }
-
- pod_destruct(interface);
-}
+++ /dev/null
-/*
- * 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 POD_H
-#define POD_H
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <sound/core.h>
-
-#include "driver.h"
-
-/*
- PODxt Live interfaces
-*/
-#define PODXTLIVE_INTERFACE_POD 0
-#define PODXTLIVE_INTERFACE_VARIAX 1
-
-/*
- Locate name in binary program dump
-*/
-#define POD_NAME_OFFSET 0
-#define POD_NAME_LENGTH 16
-
-/*
- Other constants
-*/
-#define POD_CONTROL_SIZE 0x80
-#define POD_BUFSIZE_DUMPREQ 7
-#define POD_STARTUP_DELAY 1000
-
-/*
- Stages of POD startup procedure
-*/
-enum {
- POD_STARTUP_INIT = 1,
- POD_STARTUP_VERSIONREQ,
- POD_STARTUP_WORKQUEUE,
- POD_STARTUP_SETUP,
- POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
-};
-
-struct usb_line6_pod {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-
- /**
- Instrument monitor level.
- */
- int monitor_level;
-
- /**
- Timer for device initializaton.
- */
- struct timer_list startup_timer;
-
- /**
- Work handler for device initializaton.
- */
- struct work_struct startup_work;
-
- /**
- Current progress in startup procedure.
- */
- int startup_progress;
-
- /**
- Serial number of device.
- */
- int serial_number;
-
- /**
- Firmware version (x 100).
- */
- int firmware_version;
-
- /**
- Device ID.
- */
- int device_id;
-};
-
-extern void line6_pod_disconnect(struct usb_interface *interface);
-extern int line6_pod_init(struct usb_interface *interface,
- struct usb_line6_pod *pod);
-extern void line6_pod_process_message(struct usb_line6_pod *pod);
-extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
- u8 value);
-
-#endif
+++ /dev/null
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
- *
- * 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/pcm.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "pcm.h"
-#include "podhd.h"
-
-#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
-
-static struct snd_ratden podhd_ratden = {
- .num_min = 48000,
- .num_max = 48000,
- .num_step = 1,
- .den = 1,
-};
-
-static struct line6_pcm_properties podhd_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_rates = {
- .nrats = 1,
- .rats = &podhd_ratden},
- .bytes_per_frame = PODHD_BYTES_PER_FRAME
-};
-
-/*
- POD HD destructor.
-*/
-static void podhd_destruct(struct usb_interface *interface)
-{
- struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
-
- if (podhd == NULL)
- return;
- line6_cleanup_audio(&podhd->line6);
-}
-
-/*
- Try to init POD HD device.
-*/
-static int podhd_try_init(struct usb_interface *interface,
- struct usb_line6_podhd *podhd)
-{
- int err;
- struct usb_line6 *line6 = &podhd->line6;
-
- if ((interface == NULL) || (podhd == NULL))
- return -ENODEV;
-
- /* initialize audio system: */
- err = line6_init_audio(line6);
- if (err < 0)
- return err;
-
- /* initialize MIDI subsystem: */
- err = line6_init_midi(line6);
- if (err < 0)
- return err;
-
- /* initialize PCM subsystem: */
- err = line6_init_pcm(line6, &podhd_pcm_properties);
- if (err < 0)
- return err;
-
- /* register USB audio system: */
- err = line6_register_audio(line6);
- return err;
-}
-
-/*
- Init POD HD device (and clean up in case of failure).
-*/
-int line6_podhd_init(struct usb_interface *interface,
- struct usb_line6_podhd *podhd)
-{
- int err = podhd_try_init(interface, podhd);
-
- if (err < 0)
- podhd_destruct(interface);
-
- return err;
-}
-
-/*
- POD HD device disconnected.
-*/
-void line6_podhd_disconnect(struct usb_interface *interface)
-{
- struct usb_line6_podhd *podhd;
-
- if (interface == NULL)
- return;
- podhd = usb_get_intfdata(interface);
-
- if (podhd != NULL) {
- struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
-
- if (line6pcm != NULL)
- line6_pcm_disconnect(line6pcm);
- }
-
- podhd_destruct(interface);
-}
+++ /dev/null
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
- *
- * 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 PODHD_H
-#define PODHD_H
-
-#include <linux/usb.h>
-
-#include "driver.h"
-
-struct usb_line6_podhd {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-};
-
-extern void line6_podhd_disconnect(struct usb_interface *interface);
-extern int line6_podhd_init(struct usb_interface *interface,
- struct usb_line6_podhd *podhd);
-
-#endif /* PODHD_H */
+++ /dev/null
-#ifndef DRIVER_REVISION
-/* current subversion revision */
-#define DRIVER_REVISION " (904)"
-#endif
+++ /dev/null
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- * Emil Myhrman (emil.myhrman@gmail.com)
- *
- * 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/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "toneport.h"
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
-
-#define TONEPORT_PCM_DELAY 1
-
-static struct snd_ratden toneport_ratden = {
- .num_min = 44100,
- .num_max = 44100,
- .num_step = 1,
- .den = 1
-};
-
-static struct line6_pcm_properties toneport_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 44100,
- .rate_max = 44100,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 44100,
- .rate_max = 44100,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_rates = {
- .nrats = 1,
- .rats = &toneport_ratden},
- .bytes_per_frame = 4
-};
-
-/*
- For the led on Guitarport.
- Brightness goes from 0x00 to 0x26. Set a value above this to have led
- blink.
- (void cmd_0x02(byte red, byte green)
-*/
-static int led_red = 0x00;
-static int led_green = 0x26;
-
-static const struct {
- const char *name;
- int code;
-} toneport_source_info[] = {
- {"Microphone", 0x0a01},
- {"Line", 0x0801},
- {"Instrument", 0x0b01},
- {"Inst & Mic", 0x0901}
-};
-
-static bool toneport_has_led(short product)
-{
- return
- (product == LINE6_DEVID_GUITARPORT) ||
- (product == LINE6_DEVID_TONEPORT_GX);
- /* add your device here if you are missing support for the LEDs */
-}
-
-static void toneport_update_led(struct device *dev)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_toneport *tp = usb_get_intfdata(interface);
- struct usb_line6 *line6;
-
- if (!tp)
- return;
-
- line6 = &tp->line6;
- if (line6)
- toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
- led_green);
-}
-
-static ssize_t toneport_set_led_red(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int retval;
-
- retval = kstrtoint(buf, 10, &led_red);
- if (retval)
- return retval;
-
- toneport_update_led(dev);
- return count;
-}
-
-static ssize_t toneport_set_led_green(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int retval;
-
- retval = kstrtoint(buf, 10, &led_green);
- if (retval)
- return retval;
-
- toneport_update_led(dev);
- return count;
-}
-
-static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
- toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
- toneport_set_led_green);
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
-{
- int ret;
-
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-/* monitor info callback */
-static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 256;
- return 0;
-}
-
-/* monitor get callback */
-static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
- return 0;
-}
-
-/* monitor put callback */
-static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
- return 0;
-
- line6pcm->volume_monitor = ucontrol->value.integer.value[0];
-
- if (line6pcm->volume_monitor > 0)
- line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
- else
- line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
-
- return 1;
-}
-
-/* source info callback */
-static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- const int size = ARRAY_SIZE(toneport_source_info);
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = size;
-
- if (uinfo->value.enumerated.item >= size)
- uinfo->value.enumerated.item = size - 1;
-
- strcpy(uinfo->value.enumerated.name,
- toneport_source_info[uinfo->value.enumerated.item].name);
-
- return 0;
-}
-
-/* source get callback */
-static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6pcm->line6;
- ucontrol->value.enumerated.item[0] = toneport->source;
- return 0;
-}
-
-/* source put callback */
-static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6pcm->line6;
- unsigned int source;
-
- source = ucontrol->value.enumerated.item[0];
- if (source >= ARRAY_SIZE(toneport_source_info))
- return -EINVAL;
- if (source == toneport->source)
- return 0;
-
- toneport->source = source;
- toneport_send_cmd(toneport->line6.usbdev,
- toneport_source_info[source].code, 0x0000);
- return 1;
-}
-
-static void toneport_start_pcm(unsigned long arg)
-{
- struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
- struct usb_line6 *line6 = &toneport->line6;
-
- line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
-}
-
-/* control definition */
-static struct snd_kcontrol_new toneport_control_monitor = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Monitor Playback Volume",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_toneport_monitor_info,
- .get = snd_toneport_monitor_get,
- .put = snd_toneport_monitor_put
-};
-
-/* source selector definition */
-static struct snd_kcontrol_new toneport_control_source = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Capture Source",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_toneport_source_info,
- .get = snd_toneport_source_get,
- .put = snd_toneport_source_put
-};
-
-/*
- Toneport destructor.
-*/
-static void toneport_destruct(struct usb_interface *interface)
-{
- struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
-
- if (toneport == NULL)
- return;
- line6_cleanup_audio(&toneport->line6);
-}
-
-/*
- Setup Toneport device.
-*/
-static void toneport_setup(struct usb_line6_toneport *toneport)
-{
- int ticks;
- struct usb_line6 *line6 = &toneport->line6;
- struct usb_device *usbdev = line6->usbdev;
- u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
- /* sync time on device with host: */
- ticks = (int)get_seconds();
- line6_write_data(line6, 0x80c6, &ticks, 4);
-
- /* enable device: */
- toneport_send_cmd(usbdev, 0x0301, 0x0000);
-
- /* initialize source select: */
- switch (le16_to_cpu(usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- toneport_send_cmd(usbdev,
- toneport_source_info[toneport->source].code,
- 0x0000);
- }
-
- if (toneport_has_led(idProduct))
- toneport_update_led(&usbdev->dev);
-}
-
-/*
- Try to init Toneport device.
-*/
-static int toneport_try_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport)
-{
- int err;
- struct usb_line6 *line6 = &toneport->line6;
- struct usb_device *usbdev = line6->usbdev;
- u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
- if ((interface == NULL) || (toneport == NULL))
- return -ENODEV;
-
- /* initialize audio system: */
- err = line6_init_audio(line6);
- if (err < 0)
- return err;
-
- /* initialize PCM subsystem: */
- err = line6_init_pcm(line6, &toneport_pcm_properties);
- if (err < 0)
- return err;
-
- /* register monitor control: */
- err = snd_ctl_add(line6->card,
- snd_ctl_new1(&toneport_control_monitor,
- line6->line6pcm));
- if (err < 0)
- return err;
-
- /* register source select control: */
- switch (le16_to_cpu(usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- err =
- snd_ctl_add(line6->card,
- snd_ctl_new1(&toneport_control_source,
- line6->line6pcm));
- if (err < 0)
- return err;
- }
-
- /* register audio system: */
- err = line6_register_audio(line6);
- if (err < 0)
- return err;
-
- line6_read_serial_number(line6, &toneport->serial_number);
- line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
-
- if (toneport_has_led(idProduct)) {
- CHECK_RETURN(device_create_file
- (&interface->dev, &dev_attr_led_red));
- CHECK_RETURN(device_create_file
- (&interface->dev, &dev_attr_led_green));
- }
-
- toneport_setup(toneport);
-
- init_timer(&toneport->timer);
- toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
- toneport->timer.function = toneport_start_pcm;
- toneport->timer.data = (unsigned long)toneport;
- add_timer(&toneport->timer);
-
- return 0;
-}
-
-/*
- Init Toneport device (and clean up in case of failure).
-*/
-int line6_toneport_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport)
-{
- int err = toneport_try_init(interface, toneport);
-
- if (err < 0)
- toneport_destruct(interface);
-
- return err;
-}
-
-/*
- Resume Toneport device after reset.
-*/
-void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
-{
- toneport_setup(toneport);
-}
-
-/*
- Toneport device disconnected.
-*/
-void line6_toneport_disconnect(struct usb_interface *interface)
-{
- struct usb_line6_toneport *toneport;
- u16 idProduct;
-
- if (interface == NULL)
- return;
-
- toneport = usb_get_intfdata(interface);
- del_timer_sync(&toneport->timer);
- idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct);
-
- if (toneport_has_led(idProduct)) {
- device_remove_file(&interface->dev, &dev_attr_led_red);
- device_remove_file(&interface->dev, &dev_attr_led_green);
- }
-
- if (toneport != NULL) {
- struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
-
- if (line6pcm != NULL) {
- line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
- line6_pcm_disconnect(line6pcm);
- }
- }
-
- toneport_destruct(interface);
-}
+++ /dev/null
-/*
- * 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 TONEPORT_H
-#define TONEPORT_H
-
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-struct usb_line6_toneport {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-
- /**
- Source selector.
- */
- int source;
-
- /**
- Serial number of device.
- */
- int serial_number;
-
- /**
- Firmware version (x 100).
- */
- int firmware_version;
-
- /**
- Timer for delayed PCM startup.
- */
- struct timer_list timer;
-};
-
-extern void line6_toneport_disconnect(struct usb_interface *interface);
-extern int line6_toneport_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport);
-extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
-
-#endif
+++ /dev/null
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2005-2008 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 USBDEFS_H
-#define USBDEFS_H
-
-#define LINE6_VENDOR_ID 0x0e41
-
-#define USB_INTERVALS_PER_SECOND 1000
-
-/*
- Device ids.
-*/
-#define LINE6_DEVID_BASSPODXT 0x4250
-#define LINE6_DEVID_BASSPODXTLIVE 0x4642
-#define LINE6_DEVID_BASSPODXTPRO 0x4252
-#define LINE6_DEVID_GUITARPORT 0x4750
-#define LINE6_DEVID_POCKETPOD 0x5051
-#define LINE6_DEVID_PODHD300 0x5057
-#define LINE6_DEVID_PODHD400 0x5058
-#define LINE6_DEVID_PODHD500 0x414D
-#define LINE6_DEVID_PODSTUDIO_GX 0x4153
-#define LINE6_DEVID_PODSTUDIO_UX1 0x4150
-#define LINE6_DEVID_PODSTUDIO_UX2 0x4151
-#define LINE6_DEVID_PODX3 0x414a
-#define LINE6_DEVID_PODX3LIVE 0x414b
-#define LINE6_DEVID_PODXT 0x5044
-#define LINE6_DEVID_PODXTLIVE 0x4650
-#define LINE6_DEVID_PODXTPRO 0x5050
-#define LINE6_DEVID_TONEPORT_GX 0x4147
-#define LINE6_DEVID_TONEPORT_UX1 0x4141
-#define LINE6_DEVID_TONEPORT_UX2 0x4142
-#define LINE6_DEVID_VARIAX 0x534d
-
-#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
-
-enum {
- LINE6_INDEX_BASSPODXT,
- LINE6_INDEX_BASSPODXTLIVE,
- LINE6_INDEX_BASSPODXTPRO,
- LINE6_INDEX_GUITARPORT,
- LINE6_INDEX_POCKETPOD,
- LINE6_INDEX_PODHD300,
- LINE6_INDEX_PODHD400,
- LINE6_INDEX_PODHD500,
- LINE6_INDEX_PODSTUDIO_GX,
- LINE6_INDEX_PODSTUDIO_UX1,
- LINE6_INDEX_PODSTUDIO_UX2,
- LINE6_INDEX_PODX3,
- LINE6_INDEX_PODX3LIVE,
- LINE6_INDEX_PODXT,
- LINE6_INDEX_PODXTLIVE,
- LINE6_INDEX_PODXTPRO,
- LINE6_INDEX_TONEPORT_GX,
- LINE6_INDEX_TONEPORT_UX1,
- LINE6_INDEX_TONEPORT_UX2,
- LINE6_INDEX_VARIAX,
-
- LINE6_BIT(BASSPODXT),
- LINE6_BIT(BASSPODXTLIVE),
- LINE6_BIT(BASSPODXTPRO),
- LINE6_BIT(GUITARPORT),
- LINE6_BIT(POCKETPOD),
- LINE6_BIT(PODHD300),
- LINE6_BIT(PODHD400),
- LINE6_BIT(PODHD500),
- LINE6_BIT(PODSTUDIO_GX),
- LINE6_BIT(PODSTUDIO_UX1),
- LINE6_BIT(PODSTUDIO_UX2),
- LINE6_BIT(PODX3),
- LINE6_BIT(PODX3LIVE),
- LINE6_BIT(PODXT),
- LINE6_BIT(PODXTLIVE),
- LINE6_BIT(PODXTPRO),
- LINE6_BIT(TONEPORT_GX),
- LINE6_BIT(TONEPORT_UX1),
- LINE6_BIT(TONEPORT_UX2),
- LINE6_BIT(VARIAX),
-
- LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO,
- LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE |
- LINE6_BIT_PODX3LIVE,
- LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE |
- LINE6_BIT_PODXTPRO,
- LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE,
- LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
- LINE6_BIT_PODHD400 |
- LINE6_BIT_PODHD500,
- LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT |
- LINE6_BIT_BASSPODXTLIVE |
- LINE6_BIT_BASSPODXTPRO
-};
-
-/* device supports settings parameter via USB */
-#define LINE6_BIT_CONTROL (1 << 0)
-/* device supports PCM input/output via USB */
-#define LINE6_BIT_PCM (1 << 1)
-/* device support hardware monitoring */
-#define LINE6_BIT_HWMON (1 << 2)
-
-#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \
- LINE6_BIT_PCM | \
- LINE6_BIT_HWMON)
-
-#define LINE6_FALLBACK_INTERVAL 10
-#define LINE6_FALLBACK_MAXPACKETSIZE 16
-
-#endif
+++ /dev/null
-/*
- * 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 "audio.h"
-#include "driver.h"
-#include "variax.h"
-
-#define VARIAX_OFFSET_ACTIVATE 7
-
-/*
- This message is sent by the device during initialization and identifies
- the connected guitar version.
-*/
-static const char variax_init_version[] = {
- 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
- 0x07, 0x00, 0x00, 0x00
-};
-
-/*
- This message is the last one sent by the device during initialization.
-*/
-static const char variax_init_done[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
-};
-
-static const char variax_activate[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
- 0xf7
-};
-
-/* forward declarations: */
-static void variax_startup2(unsigned long data);
-static void variax_startup4(unsigned long data);
-static void variax_startup5(unsigned long data);
-
-static void variax_activate_async(struct usb_line6_variax *variax, int a)
-{
- variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
- line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
- sizeof(variax_activate));
-}
-
-/*
- Variax startup procedure.
- This is a sequence of functions with special requirements (e.g., must
- not run immediately after initialization, must not run in interrupt
- context). After the last one has finished, the device is ready to use.
-*/
-
-static void variax_startup1(struct usb_line6_variax *variax)
-{
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
- variax_startup2, (unsigned long)variax);
-}
-
-static void variax_startup2(unsigned long data)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
- struct usb_line6 *line6 = &variax->line6;
-
- /* schedule another startup procedure until startup is complete: */
- if (variax->startup_progress >= VARIAX_STARTUP_LAST)
- return;
-
- variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
- line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
- variax_startup2, (unsigned long)variax);
-
- /* request firmware version: */
- line6_version_request_async(line6);
-}
-
-static void variax_startup3(struct usb_line6_variax *variax)
-{
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
-
- /* delay startup procedure: */
- line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
- variax_startup4, (unsigned long)variax);
-}
-
-static void variax_startup4(unsigned long data)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress,
- VARIAX_STARTUP_ACTIVATE);
-
- /* activate device: */
- variax_activate_async(variax, 1);
- line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
- variax_startup5, (unsigned long)variax);
-}
-
-static void variax_startup5(unsigned long data)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress,
- VARIAX_STARTUP_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&variax->startup_work);
-}
-
-static void variax_startup6(struct work_struct *work)
-{
- struct usb_line6_variax *variax =
- container_of(work, struct usb_line6_variax, startup_work);
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-
- /* ALSA audio interface: */
- line6_register_audio(&variax->line6);
-}
-
-/*
- Process a completely received message.
-*/
-void line6_variax_process_message(struct usb_line6_variax *variax)
-{
- const unsigned char *buf = variax->line6.buffer_message;
-
- switch (buf[0]) {
- case LINE6_RESET:
- dev_info(variax->line6.ifcdev, "VARIAX reset\n");
- break;
-
- case LINE6_SYSEX_BEGIN:
- if (memcmp(buf + 1, variax_init_version + 1,
- sizeof(variax_init_version) - 1) == 0) {
- variax_startup3(variax);
- } else if (memcmp(buf + 1, variax_init_done + 1,
- sizeof(variax_init_done) - 1) == 0) {
- /* notify of complete initialization: */
- variax_startup4((unsigned long)variax);
- }
- break;
- }
-}
-
-/*
- Variax destructor.
-*/
-static void variax_destruct(struct usb_interface *interface)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(interface);
-
- if (variax == NULL)
- return;
- line6_cleanup_audio(&variax->line6);
-
- del_timer(&variax->startup_timer1);
- del_timer(&variax->startup_timer2);
- cancel_work_sync(&variax->startup_work);
-
- kfree(variax->buffer_activate);
-}
-
-/*
- Try to init workbench device.
-*/
-static int variax_try_init(struct usb_interface *interface,
- struct usb_line6_variax *variax)
-{
- int err;
-
- init_timer(&variax->startup_timer1);
- init_timer(&variax->startup_timer2);
- INIT_WORK(&variax->startup_work, variax_startup6);
-
- if ((interface == NULL) || (variax == NULL))
- return -ENODEV;
-
- /* initialize USB buffers: */
- variax->buffer_activate = kmemdup(variax_activate,
- sizeof(variax_activate), GFP_KERNEL);
-
- if (variax->buffer_activate == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- return -ENOMEM;
- }
-
- /* initialize audio system: */
- err = line6_init_audio(&variax->line6);
- if (err < 0)
- return err;
-
- /* initialize MIDI subsystem: */
- err = line6_init_midi(&variax->line6);
- if (err < 0)
- return err;
-
- /* initiate startup procedure: */
- variax_startup1(variax);
- return 0;
-}
-
-/*
- Init workbench device (and clean up in case of failure).
-*/
-int line6_variax_init(struct usb_interface *interface,
- struct usb_line6_variax *variax)
-{
- int err = variax_try_init(interface, variax);
-
- if (err < 0)
- variax_destruct(interface);
-
- return err;
-}
-
-/*
- Workbench device disconnected.
-*/
-void line6_variax_disconnect(struct usb_interface *interface)
-{
- if (interface == NULL)
- return;
-
- variax_destruct(interface);
-}
+++ /dev/null
-/*
- * 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 VARIAX_H
-#define VARIAX_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-#define VARIAX_STARTUP_DELAY1 1000
-#define VARIAX_STARTUP_DELAY3 100
-#define VARIAX_STARTUP_DELAY4 100
-
-/*
- Stages of Variax startup procedure
-*/
-enum {
- VARIAX_STARTUP_INIT = 1,
- VARIAX_STARTUP_VERSIONREQ,
- VARIAX_STARTUP_WAIT,
- VARIAX_STARTUP_ACTIVATE,
- VARIAX_STARTUP_WORKQUEUE,
- VARIAX_STARTUP_SETUP,
- VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
-};
-
-struct usb_line6_variax {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-
- /**
- Buffer for activation code.
- */
- unsigned char *buffer_activate;
-
- /**
- Handler for device initializaton.
- */
- struct work_struct startup_work;
-
- /**
- Timers for device initializaton.
- */
- struct timer_list startup_timer1;
- struct timer_list startup_timer2;
-
- /**
- Current progress in startup procedure.
- */
- int startup_progress;
-};
-
-extern void line6_variax_disconnect(struct usb_interface *interface);
-extern int line6_variax_init(struct usb_interface *interface,
- struct usb_line6_variax *variax);
-extern void line6_variax_process_message(struct usb_line6_variax *variax);
-
-#endif
--- /dev/null
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _I915_COMPONENT_H_
+#define _I915_COMPONENT_H_
+
+struct i915_audio_component {
+ struct device *dev;
+
+ const struct i915_audio_component_ops {
+ struct module *owner;
+ void (*get_power)(struct device *);
+ void (*put_power)(struct device *);
+ int (*get_cdclk_freq)(struct device *);
+ } *ops;
+};
+
+#endif /* _I915_COMPONENT_H_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2013 Intel Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- *
- **************************************************************************/
-
-#ifndef _I915_POWERWELL_H_
-#define _I915_POWERWELL_H_
-
-/* For use by hda_i915 driver */
-extern int i915_request_power_well(void);
-extern int i915_release_power_well(void);
-extern int i915_get_cdclk_freq(void);
-
-#endif /* _I915_POWERWELL_H_ */
int irq, int dma1, int dma2,
struct snd_ad1816a *chip);
-extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
+extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device);
extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
-extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
- struct snd_timer **rtimer);
+extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device);
#ifdef CONFIG_PM
extern void snd_ad1816a_suspend(struct snd_ad1816a *chip);
extern void snd_ad1816a_resume(struct snd_ad1816a *chip);
#include <linux/types.h>
#include <linux/sched.h>
+#include <sound/core.h>
#include <sound/compress_offload.h>
#include <sound/asound.h>
#include <sound/pcm.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/firmware.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <uapi/sound/emu10k1.h>
/* ------------------- DEFINES -------------------- */
uint subsystem,
struct snd_emu10k1 ** remu);
-int snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_p16v_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device);
+int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device);
+int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device);
+int snd_p16v_pcm(struct snd_emu10k1 *emu, int device);
int snd_p16v_free(struct snd_emu10k1 * emu);
int snd_p16v_mixer(struct snd_emu10k1 * emu);
-int snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device);
+int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 *emu, int device);
int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device);
int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device);
-int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep);
+int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device);
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id);
int mpu_irq,
int dma8,
unsigned short hardware);
-int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device,
- struct snd_pcm **rpcm);
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device);
int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip);
int snd_es1688_reset(struct snd_es1688 *chip);
#include <sound/timer.h>
#include <sound/seq_midi_emul.h>
#include <sound/seq_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
/* IO ports */
/* gus_pcm.c */
-int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm);
+int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index);
#ifdef CONFIG_SND_DEBUG
extern void snd_gf1_print_voice_registers(struct snd_gus_card * gus);
/* gus_uart.c */
-int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi **rrawmidi);
+int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device);
/* gus_dram.c */
int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr,
#define SNDRV_PCM_DEVICES 8
#endif
-#define SNDRV_PCM_IOCTL1_FALSE ((void *)0)
-#define SNDRV_PCM_IOCTL1_TRUE ((void *)1)
-
#define SNDRV_PCM_IOCTL1_RESET 0
#define SNDRV_PCM_IOCTL1_INFO 1
#define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2
#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4
#define SNDRV_PCM_TRIGGER_SUSPEND 5
#define SNDRV_PCM_TRIGGER_RESUME 6
+#define SNDRV_PCM_TRIGGER_DRAIN 7
#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1)
int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
struct snd_pcm_substream **rsubstream);
void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
-void snd_pcm_vma_notify_data(void *client, void *data);
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
-snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian);
void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
const struct snd_pcm_ops *ops);
void snd_pcm_set_sync(struct snd_pcm_substream *substream);
-int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
int snd_pcm_update_state(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime);
int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
-int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
-int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
-int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream);
-int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream);
void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
#define MASK_OFS(i) ((i) >> 5)
#define MASK_BIT(i) (1U << ((i) & 31))
-static inline unsigned int ld2(u_int32_t v)
-{
- unsigned r = 0;
-
- if (v >= 0x10000) {
- v >>= 16;
- r += 16;
- }
- if (v >= 0x100) {
- v >>= 8;
- r += 8;
- }
- if (v >= 0x10) {
- v >>= 4;
- r += 4;
- }
- if (v >= 4) {
- v >>= 2;
- r += 2;
- }
- if (v >= 2)
- r++;
- return r;
-}
-
static inline size_t snd_mask_sizeof(void)
{
return sizeof(struct snd_mask);
int i;
for (i = 0; i < SNDRV_MASK_SIZE; i++) {
if (mask->bits[i])
- return ffs(mask->bits[i]) - 1 + (i << 5);
+ return __ffs(mask->bits[i]) + (i << 5);
}
return 0;
}
int i;
for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
if (mask->bits[i])
- return ld2(mask->bits[i]) + (i << 5);
+ return __fls(mask->bits[i]) + (i << 5);
}
return 0;
}
i1->max == i2->max && i1->openmax == i2->openmax;
}
-static inline unsigned int add(unsigned int a, unsigned int b)
+/**
+ * params_access - get the access type from the hw params
+ * @p: hw params
+ */
+static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
{
- if (a >= UINT_MAX - b)
- return UINT_MAX;
- return a + b;
+ return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
+ SNDRV_PCM_HW_PARAM_ACCESS));
}
-static inline unsigned int sub(unsigned int a, unsigned int b)
+/**
+ * params_format - get the sample format from the hw params
+ * @p: hw params
+ */
+static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
{
- if (a > b)
- return a - b;
- return 0;
+ return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
+ SNDRV_PCM_HW_PARAM_FORMAT));
}
-#define params_access(p) ((__force snd_pcm_access_t)\
- snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS)))
-#define params_format(p) ((__force snd_pcm_format_t)\
- snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT)))
-#define params_subformat(p) \
- snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
+/**
+ * params_subformat - get the sample subformat from the hw params
+ * @p: hw params
+ */
+static inline snd_pcm_subformat_t
+params_subformat(const struct snd_pcm_hw_params *p)
+{
+ return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
+ SNDRV_PCM_HW_PARAM_SUBFORMAT));
+}
+/**
+ * params_period_bytes - get the period size (in bytes) from the hw params
+ * @p: hw params
+ */
static inline unsigned int
params_period_bytes(const struct snd_pcm_hw_params *p)
{
- return (params_period_size(p) *
- snd_pcm_format_physical_width(params_format(p)) *
- params_channels(p)) / 8;
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
}
-static inline int
-params_width(const struct snd_pcm_hw_params *p)
+/**
+ * params_width - get the number of bits of the sample format from the hw params
+ * @p: hw params
+ *
+ * This function returns the number of bits per sample that the selected sample
+ * format of the hw params has.
+ */
+static inline int params_width(const struct snd_pcm_hw_params *p)
{
return snd_pcm_format_width(params_format(p));
}
-static inline int
-params_physical_width(const struct snd_pcm_hw_params *p)
+/*
+ * params_physical_width - get the storage size of the sample format from the hw params
+ * @p: hw params
+ *
+ * This functions returns the number of bits per sample that the selected sample
+ * format of the hw params takes up in memory. This will be equal or larger than
+ * params_width().
+ */
+static inline int params_physical_width(const struct snd_pcm_hw_params *p)
{
return snd_pcm_format_physical_width(params_format(p));
}
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <linux/interrupt.h>
-#include <asm/io.h>
+#include <linux/io.h>
enum sb_hw_type {
SB_HW_AUTO,
#endif
/* sb8_init.c */
-int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+int snd_sb8dsp_pcm(struct snd_sb *chip, int device);
/* sb8.c */
irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip);
int snd_sb8_playback_open(struct snd_pcm_substream *substream);
int snd_sb8_capture_close(struct snd_pcm_substream *substream);
/* midi8.c */
irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip);
-int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi);
+int snd_sb8dsp_midi(struct snd_sb *chip, int device);
/* sb16_init.c */
-int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+int snd_sb16dsp_pcm(struct snd_sb *chip, int device);
const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction);
int snd_sb16dsp_configure(struct snd_sb *chip);
/* sb16.c */
typedef struct snd_seq_real_time snd_seq_real_time_t;
typedef union snd_seq_timestamp snd_seq_timestamp_t;
-/* maximum number of events dequeued per schedule interval */
-#define SNDRV_SEQ_MAX_DEQUEUE 50
-
/* maximum number of queues */
-#define SNDRV_SEQ_MAX_QUEUES 8
+#define SNDRV_SEQ_MAX_QUEUES 32
/* max number of concurrent clients */
#define SNDRV_SEQ_MAX_CLIENTS 192
/* max number of events in memory pool */
#define SNDRV_SEQ_MAX_EVENTS 2000
-/* default number of events in memory chunk */
-#define SNDRV_SEQ_DEFAULT_CHUNK_EVENTS 64
-
/* default number of events in memory pool */
#define SNDRV_SEQ_DEFAULT_EVENTS 500
int (*unuse)(void *private_data, struct snd_seq_port_subscribe *info);
int (*event_input)(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
void (*private_free)(void *private_data);
- unsigned int callback_all; /* call subscribe callbacks at each connection/disconnection */
/*...*/
};
const char *pin);
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
const char *pin);
-void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
/* Mostly internal - should not normally be used */
unsigned short hardware,
unsigned short hwshare,
struct snd_wss **rchip);
-int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
-int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
+int snd_wss_pcm(struct snd_wss *chip, int device);
+int snd_wss_timer(struct snd_wss *chip, int device);
int snd_wss_mixer(struct snd_wss *chip);
const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction);
unsigned short hardware,
unsigned short hwshare,
struct snd_wss **rchip);
-int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
+int snd_cs4236_pcm(struct snd_wss *chip, int device);
int snd_cs4236_mixer(struct snd_wss *chip);
/*
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
typedef int __bitwise snd_pcm_state_t;
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _UAPI__SOUND_USB_STREAM_H
+#define _UAPI__SOUND_USB_STREAM_H
+
+#define USB_STREAM_INTERFACE_VERSION 2
+
+#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
+ _IOW('H', 0x90, struct usb_stream_config)
+
+struct usb_stream_packet {
+ unsigned offset;
+ unsigned length;
+};
+
+
+struct usb_stream_config {
+ unsigned version;
+ unsigned sample_rate;
+ unsigned period_frames;
+ unsigned frame_size;
+};
+
+struct usb_stream {
+ struct usb_stream_config cfg;
+ unsigned read_size;
+ unsigned write_size;
+
+ int period_size;
+
+ unsigned state;
+
+ int idle_insize;
+ int idle_outsize;
+ int sync_packet;
+ unsigned insize_done;
+ unsigned periods_done;
+ unsigned periods_polled;
+
+ struct usb_stream_packet outpacket[2];
+ unsigned inpackets;
+ unsigned inpacket_head;
+ unsigned inpacket_split;
+ unsigned inpacket_split_at;
+ unsigned next_inpacket_split;
+ unsigned next_inpacket_split_at;
+ struct usb_stream_packet inpacket[0];
+};
+
+enum usb_stream_state {
+ usb_stream_invalid,
+ usb_stream_stopped,
+ usb_stream_sync0,
+ usb_stream_sync1,
+ usb_stream_ready,
+ usb_stream_running,
+ usb_stream_xrun,
+};
+
+#endif /* _UAPI__SOUND_USB_STREAM_H */
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/prom.h>
#include <asm/macio.h>
#include <asm/pmac_feature.h>
int i;
i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
-
- if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
- if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
- if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
+ iounmap(i2sdev->intfregs);
+ iounmap(i2sdev->out.dbdma);
+ iounmap(i2sdev->in.dbdma);
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
release_and_free_resource(i2sdev->allocated_resource[i]);
free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
free_irq(dev->interrupts[i], dev);
free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
- if (dev->intfregs) iounmap(dev->intfregs);
- if (dev->out.dbdma) iounmap(dev->out.dbdma);
- if (dev->in.dbdma) iounmap(dev->in.dbdma);
+ iounmap(dev->intfregs);
+ iounmap(dev->out.dbdma);
+ iounmap(dev->in.dbdma);
for (i=0;i<3;i++)
release_and_free_resource(dev->allocated_resource[i]);
mutex_destroy(&dev->lock);
list_for_each_entry(i2sdev, &control->list, item) {
/* Notify Alsa */
- if (i2sdev->sound.pcm) {
- /* Suspend PCM streams */
- snd_pcm_suspend_all(i2sdev->sound.pcm);
- }
+ /* Suspend PCM streams */
+ snd_pcm_suspend_all(i2sdev->sound.pcm);
/* Notify codecs */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
* GPL v2, can be found in COPYING.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/core.h>
static void aaci_free_card(struct snd_card *card)
{
struct aaci *aaci = card->private_data;
- if (aaci->base)
- iounmap(aaci->base);
+
+ iounmap(aaci->base);
}
static struct aaci *aaci_init_card(struct amba_device *dev)
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/platform_data/dma-dw.h>
#include <linux/dma/dw.h>
+#ifdef CONFIG_AVR32
#include <mach/cpu.h>
-
-#ifdef CONFIG_ARCH_AT91
-#include <mach/hardware.h>
+#else
+#define cpu_is_at32ap7000() 0
#endif
#include "ac97c.h"
}
}
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ac97c_dt_ids[] = {
+ { .compatible = "atmel,at91sam9263-ac97c", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids);
+
+static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
+{
+ struct ac97c_platform_data *pdata;
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *match;
+
+ if (!node) {
+ dev_err(dev, "Device does not have associated DT data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
+
+ return pdata;
+}
+#else
+static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
+{
+ dev_err(dev, "no platform data defined\n");
+ return ERR_PTR(-ENXIO);
+}
+#endif
+
static int atmel_ac97c_probe(struct platform_device *pdev)
{
struct snd_card *card;
return -ENXIO;
}
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
- dev_dbg(&pdev->dev, "no platform data\n");
- return -ENXIO;
+ pdata = atmel_ac97c_probe_dt(&pdev->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
}
irq = platform_get_irq(pdev, 0);
.driver = {
.name = "atmel_ac97c",
.pm = ATMEL_AC97C_PM_OPS,
+ .of_match_table = of_match_ptr(atmel_ac97c_dt_ids),
},
};
module_platform_driver(atmel_ac97c_driver);
*/
#include <linux/export.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
#include <sound/core.h>
/**
oss_buffer_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
- oss_buffer_size = 1 << ld2(oss_buffer_size);
+ oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes;
min_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
min_period_size *= oss_frame_size;
- min_period_size = 1 << (ld2(min_period_size - 1) + 1);
+ min_period_size = roundup_pow_of_two(min_period_size);
if (oss_period_size < min_period_size)
oss_period_size = min_period_size;
max_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
max_period_size *= oss_frame_size;
- max_period_size = 1 << ld2(max_period_size);
+ max_period_size = rounddown_pow_of_two(max_period_size);
if (oss_period_size > max_period_size)
oss_period_size = max_period_size;
int width = l & 0xffff;
unsigned int msbits = l >> 16;
struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
- if (snd_interval_single(i) && snd_interval_value(i) == width)
- params->msbits = msbits;
+
+ if (!snd_interval_single(i))
+ return 0;
+
+ if ((snd_interval_value(i) == width) ||
+ (width == 0 && snd_interval_value(i) > msbits))
+ params->msbits = min_not_zero(params->msbits, msbits);
+
return 0;
}
* @width: sample bits width
* @msbits: msbits width
*
+ * This constraint will set the number of most significant bits (msbits) if a
+ * sample format with the specified width has been select. If width is set to 0
+ * the msbits will be set for any sample format with a width larger than the
+ * specified msbits.
+ *
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/pm_qos.h>
#include <linux/aio.h>
+#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/timer.h>
#include <sound/minors.h>
-#include <asm/io.h>
/*
* Compatibility
hw = &substream->runtime->hw;
if (!params->info) {
- params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+ params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER);
if (!hw_support_mmap(substream))
params->info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID);
snd_pcm_post_stop(substream, new_state);
}
}
+
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+ runtime->trigger_master == substream &&
+ (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER))
+ return substream->ops->trigger(substream,
+ SNDRV_PCM_TRIGGER_DRAIN);
+
return 0;
}
spin_unlock_irqrestore(®ister_lock, flags);
snd_use_lock_free(&mdev->use_lock);
snd_use_lock_sync(&mdev->use_lock);
- if (mdev->coder)
- snd_midi_event_free(mdev->coder);
+ snd_midi_event_free(mdev->coder);
kfree(mdev);
}
spin_lock_irqsave(®ister_lock, flags);
spin_lock_irqsave(®ister_lock, flags);
for (i = 0; i < max_midi_devs; i++) {
if ((mdev = midi_devs[i]) != NULL) {
- if (mdev->coder)
- snd_midi_event_free(mdev->coder);
+ snd_midi_event_free(mdev->coder);
kfree(mdev);
midi_devs[i] = NULL;
}
/* fill the info fields */
info.queues = SNDRV_SEQ_MAX_QUEUES;
info.clients = SNDRV_SEQ_MAX_CLIENTS;
- info.ports = 256; /* fixed limit */
+ info.ports = SNDRV_SEQ_MAX_PORTS;
info.channels = 256; /* fixed limit */
info.cur_clients = client_usage.cur;
info.cur_queues = snd_seq_queue_get_cur_queues();
port->owner = callback->owner;
port->private_data = callback->private_data;
port->private_free = callback->private_free;
- port->callback_all = callback->callback_all;
port->event_input = callback->event_input;
port->c_src.open = callback->subscribe;
port->c_src.close = callback->unsubscribe;
snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
}
- if (msynth->parser)
- snd_midi_event_free(msynth->parser);
+ snd_midi_event_free(msynth->parser);
}
/* register new midi synth port */
if (snd_BUG_ON(!client))
return NULL;
- if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
+ if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
return NULL;
}
* invoked.
* This feature is useful if these callbacks are associated with
* initialization or termination of devices (see seq_midi.c).
- *
- * If callback_all option is set, the callback function is invoked
- * at each connection/disconnection.
*/
static int subscribe_port(struct snd_seq_client *client,
if (!try_module_get(port->owner))
return -EFAULT;
grp->count++;
- if (grp->open && (port->callback_all || grp->count == 1)) {
+ if (grp->open && grp->count == 1) {
err = grp->open(port->private_data, info);
if (err < 0) {
module_put(port->owner);
if (! grp->count)
return -EINVAL;
grp->count--;
- if (grp->close && (port->callback_all || grp->count == 0))
+ if (grp->close && grp->count == 0)
err = grp->close(port->private_data, info);
if (send_ack && client->type == USER_CLIENT)
snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
int atomic, int hop);
void (*private_free)(void *private_data);
void *private_data;
- unsigned int callback_all : 1;
unsigned int closing : 1;
unsigned int timestamping: 1;
unsigned int time_real: 1;
snd_timer_free(timer);
return -ENOMEM;
}
- init_timer(&priv->tlist);
- priv->tlist.function = snd_timer_s_function;
- priv->tlist.data = (unsigned long) timer;
+ setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer);
timer->private_data = priv;
timer->private_free = snd_timer_free_system;
return snd_timer_global_register(timer);
}
tick = dpcm->period_size_frac - dpcm->irq_pos;
tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
- dpcm->timer.expires = jiffies + tick;
- add_timer(&dpcm->timer);
+ mod_timer(&dpcm->timer, jiffies + tick);
}
/* call in cable->lock */
static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
{
- dpcm->timer.expires = jiffies +
- (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate;
- add_timer(&dpcm->timer);
+ mod_timer(&dpcm->timer, jiffies +
+ (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
}
static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
if (!dpcm)
return -ENOMEM;
substream->runtime->private_data = dpcm;
- init_timer(&dpcm->timer);
- dpcm->timer.data = (unsigned long) dpcm;
- dpcm->timer.function = dummy_systimer_callback;
+ setup_timer(&dpcm->timer, dummy_systimer_callback,
+ (unsigned long) dpcm);
spin_lock_init(&dpcm->lock);
dpcm->substream = substream;
return 0;
if (ml403_ac97cr->capture_irq >= 0)
free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr);
/* give back "port" */
- if (ml403_ac97cr->port != NULL)
- iounmap(ml403_ac97cr->port);
+ iounmap(ml403_ac97cr->port);
kfree(ml403_ac97cr);
PDEBUG(INIT_INFO, "free(): (done)\n");
return 0;
}
static int
-snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
- struct snd_pcm **rpcm)
+snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1,
&pcm);
if (err < 0)
snd_dma_continuous_data(GFP_KERNEL),
64 * 1024,
128 * 1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
return err;
}
PDEBUG(INIT_INFO, "probe(): mixer done\n");
- err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL);
+ err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0);
if (err < 0) {
snd_card_free(card);
return err;
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
spin_lock_irqsave(&mpu->timer_lock, flags);
/*mpu->mode |= MPU401_MODE_TIMER;*/
- mpu->timer.expires = 1 + jiffies;
- add_timer(&mpu->timer);
+ mod_timer(&mpu->timer, 1 + jiffies);
spin_unlock_irqrestore(&mpu->timer_lock, flags);
if (mpu->rmidi)
_snd_mpu401_uart_interrupt(mpu);
spin_lock_irqsave (&mpu->timer_lock, flags);
if (mpu->timer_invoked == 0) {
- init_timer(&mpu->timer);
- mpu->timer.data = (unsigned long)mpu;
- mpu->timer.function = snd_mpu401_uart_timer;
- mpu->timer.expires = 1 + jiffies;
- add_timer(&mpu->timer);
+ setup_timer(&mpu->timer, snd_mpu401_uart_timer,
+ (unsigned long)mpu);
+ mod_timer(&mpu->timer, 1 + jiffies);
}
mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
MPU401_MODE_OUTPUT_TIMER;
spin_lock_irqsave(&chip->spinlock, flags);
/* reprogram timer */
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
/* process each port */
for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) {
struct mtpav_port *portp = &chip->ports[p];
/* spinlock held! */
static void snd_mtpav_add_output_timer(struct mtpav *chip)
{
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
}
/* spinlock held! */
mtp_card = card->private_data;
spin_lock_init(&mtp_card->spinlock);
- init_timer(&mtp_card->timer);
mtp_card->card = card;
mtp_card->irq = -1;
mtp_card->share_irq = 0;
mtp_card->inmidistate = 0;
mtp_card->outmidihwport = 0xffffffff;
- init_timer(&mtp_card->timer);
- mtp_card->timer.function = snd_mtpav_output_timer;
- mtp_card->timer.data = (unsigned long) mtp_card;
+ setup_timer(&mtp_card->timer, snd_mtpav_output_timer,
+ (unsigned long) mtp_card);
card->private_free = snd_mtpav_free;
*/
#include <sound/opl3.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
spin_unlock_irqrestore(&opl3->voice_lock, flags);
spin_lock_irqsave(&opl3->sys_timer_lock, flags);
- if (again) {
- opl3->tlist.expires = jiffies + 1; /* invoke again */
- add_timer(&opl3->tlist);
- } else {
+ if (again)
+ mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */
+ else
opl3->sys_timer_status = 0;
- }
spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
}
unsigned long flags;
spin_lock_irqsave(&opl3->sys_timer_lock, flags);
if (! opl3->sys_timer_status) {
- opl3->tlist.expires = jiffies + 1;
- add_timer(&opl3->tlist);
+ mod_timer(&opl3->tlist, jiffies + 1);
opl3->sys_timer_status = 1;
}
spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
}
/* setup system timer */
- init_timer(&opl3->tlist);
- opl3->tlist.function = snd_opl3_timer_func;
- opl3->tlist.data = (unsigned long) opl3;
+ setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3);
spin_lock_init(&opl3->sys_timer_lock);
opl3->sys_timer_status = 0;
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("OPL4 driver");
#include "opl4_local.h"
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/asoundef.h>
/* GM2 controllers */
#include <sound/pcm.h>
#include <linux/input.h>
#include <linux/delay.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include "pcsp_input.h"
#include "pcsp.h"
#include <linux/init.h>
#include <linux/input.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "pcsp.h"
#include "pcsp_input.h"
#include <linux/gfp.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <sound/pcm.h>
-#include <asm/io.h>
#include "pcsp.h"
static bool nforce_wa;
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
#include <linux/serial_reg.h>
#include <linux/jiffies.h>
-#include <asm/io.h>
-
MODULE_DESCRIPTION("MIDI serial u16550");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}");
{
if (!uart->timer_running) {
/* timer 38600bps * 10bit * 16byte */
- uart->buffer_timer.expires = jiffies + (HZ+255)/256;
+ mod_timer(&uart->buffer_timer, jiffies + (HZ + 255) / 256);
uart->timer_running = 1;
- add_timer(&uart->buffer_timer);
}
}
uart->prev_in = 0;
uart->rstatus = 0;
memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS);
- init_timer(&uart->buffer_timer);
- uart->buffer_timer.function = snd_uart16550_buffer_timer;
- uart->buffer_timer.data = (unsigned long)uart;
+ setup_timer(&uart->buffer_timer, snd_uart16550_buffer_timer,
+ (unsigned long)uart);
uart->timer_running = 0;
/* Register device */
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/asoundef.h>
#include <sound/info.h>
-#include <asm/io.h>
#include <sound/vx_core.h>
#include "vx_cmd.h"
chip->read = read;
chip->write = write;
chip->private_data = private_data;
- init_timer(&chip->timer);
- chip->timer.data = (unsigned long)chip;
- chip->timer.function = snd_ak4117_timer;
+ setup_timer(&chip->timer, snd_ak4117_timer, (unsigned long)chip);
for (reg = 0; reg < 5; reg++)
chip->regmap[reg] = pgm[reg];
/* release powerdown, everything is initialized now */
reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN);
chip->init = 0;
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
}
static unsigned int external_rate(unsigned char rcs1)
if (chip->init)
return;
snd_ak4117_check_rate_and_errors(chip, 0);
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
}
EXPORT_SYMBOL(snd_ak4117_create);
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
struct snd_card *card;
struct snd_ad1816a *chip;
struct snd_opl3 *opl3;
- struct snd_timer *timer;
error = snd_card_new(&pcard->card->dev,
index[dev], id[dev], THIS_MODULE,
sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
- if ((error = snd_ad1816a_pcm(chip, 0, NULL)) < 0) {
+ if ((error = snd_ad1816a_pcm(chip, 0)) < 0) {
snd_card_free(card);
return error;
}
return error;
}
- error = snd_ad1816a_timer(chip, 0, &timer);
+ error = snd_ad1816a_timer(chip, 0);
if (error < 0) {
snd_card_free(card);
return error;
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/ad1816a.h>
-#include <asm/io.h>
#include <asm/dma.h>
static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
.pointer = snd_ad1816a_capture_pointer,
};
-int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
+int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device)
{
int error;
struct snd_pcm *pcm;
64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
chip->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
return 0;
}
-int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
- struct snd_timer **rtimer)
+int snd_ad1816a_timer(struct snd_ad1816a *chip, int device)
{
struct snd_timer *timer;
struct snd_timer_id tid;
timer->private_data = chip;
chip->timer = timer;
timer->hw = snd_ad1816a_timer_table;
- if (rtimer)
- *rtimer = timer;
return 0;
}
{
struct snd_card *card;
struct snd_wss *chip;
- struct snd_pcm *pcm;
int error;
error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
card->private_data = chip;
- error = snd_wss_pcm(chip, 0, &pcm);
+ error = snd_wss_pcm(chip, 0);
if (error < 0)
goto out;
goto out;
strcpy(card->driver, "AD1848");
- strcpy(card->shortname, pcm->name);
+ strcpy(card->shortname, chip->pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
- pcm->name, chip->port, irq[n], dma1[n]);
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
if (thinkpad[n])
strcat(card->longname, " [Thinkpad]");
irq[dev], dma8[dev], dma16[dev]);
}
- if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) {
+ if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) {
snd_card_free(card);
return error;
}
activation method (full-duplex audio!).
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
- error = snd_wss_pcm(chip, 0, NULL);
+ error = snd_wss_pcm(chip, 0);
if (error < 0) {
snd_card_free(card);
return error;
snd_card_free(card);
return error;
}
- error = snd_wss_timer(chip, 0, NULL);
+ error = snd_wss_timer(chip, 0);
if (error < 0) {
snd_card_free(card);
return error;
if (err < 0)
goto error;
- err = snd_wss_pcm(cmi->wss, 0, NULL);
+ err = snd_wss_pcm(cmi->wss, 0);
if (err < 0)
goto error;
if (err < 0)
goto error;
- if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+ if (snd_wss_timer(cmi->wss, 0) < 0)
snd_printk(KERN_WARNING "error initializing WSS timer\n");
if (mpuport[ndev] == SNDRV_AUTO_PORT) {
{
struct snd_card *card;
struct snd_wss *chip;
- struct snd_pcm *pcm;
int error;
error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
card->private_data = chip;
- error = snd_wss_pcm(chip, 0, &pcm);
+ error = snd_wss_pcm(chip, 0);
if (error < 0)
goto out;
strcpy(card->driver, "CS4231");
- strcpy(card->shortname, pcm->name);
+ strcpy(card->shortname, chip->pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
- pcm->name, chip->port, irq[n], dma1[n]);
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
if (dma2[n] >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]);
if (error < 0)
goto out;
- error = snd_wss_timer(chip, 0, NULL);
+ error = snd_wss_timer(chip, 0);
if (error < 0)
goto out;
static int snd_cs423x_probe(struct snd_card *card, int dev)
{
struct snd_card_cs4236 *acard;
- struct snd_pcm *pcm;
struct snd_wss *chip;
struct snd_opl3 *opl3;
int err;
acard->chip = chip;
if (chip->hardware & WSS_HW_CS4236B_MASK) {
- err = snd_cs4236_pcm(chip, 0, &pcm);
+ err = snd_cs4236_pcm(chip, 0);
if (err < 0)
return err;
if (err < 0)
return err;
} else {
- err = snd_wss_pcm(chip, 0, &pcm);
+ err = snd_wss_pcm(chip, 0);
if (err < 0)
return err;
if (err < 0)
return err;
}
- strcpy(card->driver, pcm->name);
- strcpy(card->shortname, pcm->name);
+ strcpy(card->driver, chip->pcm->name);
+ strcpy(card->shortname, chip->pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
- pcm->name,
+ chip->pcm->name,
chip->port,
irq[dev],
dma1[dev]);
if (dma2[dev] >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0)
return err;
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
return 0;
}
-int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+int snd_cs4236_pcm(struct snd_wss *chip, int device)
{
- struct snd_pcm *pcm;
int err;
- err = snd_wss_pcm(chip, device, &pcm);
+ err = snd_wss_pcm(chip, device);
if (err < 0)
return err;
- pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
- if (rpcm)
- *rpcm = pcm;
+ chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
return 0;
}
{
struct snd_es1688 *chip = card->private_data;
struct snd_opl3 *opl3;
- struct snd_pcm *pcm;
int error;
- error = snd_es1688_pcm(card, chip, 0, &pcm);
+ error = snd_es1688_pcm(card, chip, 0);
if (error < 0)
return error;
return error;
strlcpy(card->driver, "ES1688", sizeof(card->driver));
- strlcpy(card->shortname, pcm->name, sizeof(card->shortname));
+ strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port,
+ "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
chip->irq, chip->dma8);
if (fm_port[n] == SNDRV_AUTO_PORT)
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/es1688.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <asm/dma.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
.pointer = snd_es1688_capture_pointer,
};
-int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
- int device, struct snd_pcm **rpcm)
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device)
{
struct snd_pcm *pcm;
int err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
64*1024, 64*1024);
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
#include <linux/isapnp.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/control.h>
.pointer = snd_es18xx_capture_pointer,
};
-static int snd_es18xx_pcm(struct snd_card *card, int device,
- struct snd_pcm **rpcm)
+static int snd_es18xx_pcm(struct snd_card *card, int device)
{
struct snd_es18xx *chip = card->private_data;
struct snd_pcm *pcm;
char str[16];
int err;
- if (rpcm)
- *rpcm = NULL;
sprintf(str, "ES%x", chip->version);
if (chip->caps & ES18XX_PCM2)
err = snd_pcm_new(card, str, device, 2, 1, &pcm);
snd_dma_isa_data(),
64*1024,
chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
chip->port,
irq[dev], dma1[dev]);
- err = snd_es18xx_pcm(card, 0, NULL);
+ err = snd_es18xx_pcm(card, 0);
if (err < 0)
return err;
if (err < 0)
goto error;
- err = snd_wss_pcm(chip, 0, NULL);
+ err = snd_wss_pcm(chip, 0);
if (err < 0)
goto error;
if (err < 0)
goto error;
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0)
goto error;
+++ /dev/null
-/*
- * Routines for Gravis UltraSound soundcards - Synthesizer
- * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- * 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
- *
- */
-
-#include <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-
-/*
- *
- */
-
-int snd_gus_iwffff_put_sample(void *private_data, struct iwffff_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
- struct snd_gf1_mem_block *block;
- int err;
-
- if (wave->format & IWFFFF_WAVE_ROM)
- return 0; /* it's probably ok - verify the address? */
- if (wave->format & IWFFFF_WAVE_STEREO)
- return -EINVAL; /* not supported */
- block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
- SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF,
- NULL, wave->size,
- wave->format & IWFFFF_WAVE_16BIT, 1,
- wave->share_id);
- if (block == NULL)
- return -ENOMEM;
- err = snd_gus_dram_write(gus, data,
- block->ptr, wave->size);
- if (err < 0) {
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
- snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
- return err;
- }
- wave->address.memory = block->ptr;
- return 0;
-}
-
-int snd_gus_iwffff_get_sample(void *private_data, struct iwffff_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gus_dram_read(gus, data, wave->address.memory, wave->size,
- wave->format & IWFFFF_WAVE_ROM ? 1 : 0);
-}
-
-int snd_gus_iwffff_remove_sample(void *private_data, struct iwffff_wave *wave,
- int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- if (wave->format & IWFFFF_WAVE_ROM)
- return 0; /* it's probably ok - verify the address? */
- return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
-}
-
-/*
- *
- */
-
-int snd_gus_gf1_put_sample(void *private_data, struct gf1_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
- struct snd_gf1_mem_block *block;
- int err;
-
- if (wave->format & GF1_WAVE_STEREO)
- return -EINVAL; /* not supported */
- block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
- SNDRV_GF1_MEM_OWNER_WAVE_GF1,
- NULL, wave->size,
- wave->format & GF1_WAVE_16BIT, 1,
- wave->share_id);
- if (block == NULL)
- return -ENOMEM;
- err = snd_gus_dram_write(gus, data,
- block->ptr, wave->size);
- if (err < 0) {
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
- snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
- return err;
- }
- wave->address.memory = block->ptr;
- return 0;
-}
-
-int snd_gus_gf1_get_sample(void *private_data, struct gf1_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0);
-}
-
-int snd_gus_gf1_remove_sample(void *private_data, struct gf1_wave *wave,
- int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
-}
-
-/*
- *
- */
-
-int snd_gus_simple_put_sample(void *private_data, struct simple_instrument *instr,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
- struct snd_gf1_mem_block *block;
- int err;
-
- if (instr->format & SIMPLE_WAVE_STEREO)
- return -EINVAL; /* not supported */
- block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
- SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE,
- NULL, instr->size,
- instr->format & SIMPLE_WAVE_16BIT, 1,
- instr->share_id);
- if (block == NULL)
- return -ENOMEM;
- err = snd_gus_dram_write(gus, data, block->ptr, instr->size);
- if (err < 0) {
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
- snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
- return err;
- }
- instr->address.memory = block->ptr;
- return 0;
-}
-
-int snd_gus_simple_get_sample(void *private_data, struct simple_instrument *instr,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0);
-}
-
-int snd_gus_simple_remove_sample(void *private_data, struct simple_instrument *instr,
- int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory);
-}
.pointer = snd_gf1_pcm_capture_pointer,
};
-int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm)
+int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
{
struct snd_card *card;
struct snd_kcontrol *kctl;
struct snd_pcm_substream *substream;
int capture, err;
- if (rpcm)
- *rpcm = NULL;
card = gus->card;
capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0;
err = snd_pcm_new(card,
return err;
kctl->id.index = control_index;
- if (rpcm)
- *rpcm = pcm;
return 0;
}
.trigger = snd_gf1_uart_input_trigger,
};
-int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi ** rrawmidi)
+int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = gus;
gus->midi_uart = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return err;
}
if (error < 0)
goto out;
- error = snd_gf1_pcm_new(gus, 0, 0, NULL);
+ error = snd_gf1_pcm_new(gus, 0, 0);
if (error < 0)
goto out;
if (!gus->ace_flag) {
- error = snd_gf1_rawmidi_new(gus, 0, NULL);
+ error = snd_gf1_rawmidi_new(gus, 0);
if (error < 0)
goto out;
}
}
gus->codec_flag = 1;
- error = snd_es1688_pcm(card, es1688, 0, NULL);
+ error = snd_es1688_pcm(card, es1688, 0);
if (error < 0)
goto out;
snd_component_add(card, "ES1688");
if (pcm_channels[n] > 0) {
- error = snd_gf1_pcm_new(gus, 1, 1, NULL);
+ error = snd_gf1_pcm_new(gus, 1, 1);
if (error < 0)
goto out;
}
if (err < 0)
goto _err;
- err = snd_wss_pcm(wss, 0, NULL);
+ err = snd_wss_pcm(wss, 0);
if (err < 0)
goto _err;
if (err < 0)
goto _err;
- err = snd_wss_timer(wss, 2, NULL);
+ err = snd_wss_timer(wss, 2);
if (err < 0)
goto _err;
if (pcm_channels[dev] > 0) {
- if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+ if ((err = snd_gf1_pcm_new(gus, 1, 1)) < 0)
goto _err;
}
err = snd_gusmax_mixer(wss);
if (err < 0)
goto _err;
- err = snd_gf1_rawmidi_new(gus, 0, NULL);
+ err = snd_gf1_rawmidi_new(gus, 0);
if (err < 0)
goto _err;
#ifdef SNDRV_STB
struct snd_i2c_bus *i2c_bus;
#endif
- struct snd_pcm *pcm;
char *str;
int err;
if (err < 0)
return err;
- err = snd_wss_pcm(wss, 0, &pcm);
+ err = snd_wss_pcm(wss, 0);
if (err < 0)
return err;
- sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
- strcat(pcm->name, " (codec)");
+ sprintf(wss->pcm->name + strlen(wss->pcm->name), " rev %c",
+ gus->revision + 'A');
+ strcat(wss->pcm->name, " (codec)");
- err = snd_wss_timer(wss, 2, NULL);
+ err = snd_wss_timer(wss, 2);
if (err < 0)
return err;
return err;
if (pcm_channels[dev] > 0) {
- err = snd_gf1_pcm_new(gus, 1, 1, NULL);
+ err = snd_gf1_pcm_new(gus, 1, 1);
if (err < 0)
return err;
}
#endif
gus->uart_enable = midi[dev];
- if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
+ if ((err = snd_gf1_rawmidi_new(gus, 0)) < 0)
return err;
#ifndef SNDRV_STB
};
-int snd_msnd_pcm(struct snd_card *card, int device,
- struct snd_pcm **rpcm)
+int snd_msnd_pcm(struct snd_card *card, int device)
{
struct snd_msnd *chip = card->private_data;
struct snd_pcm *pcm;
pcm->private_data = chip;
strcpy(pcm->name, "Hurricane");
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
EXPORT_SYMBOL(snd_msnd_pcm);
void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
int snd_msnd_DARQ(struct snd_msnd *chip, int start);
-int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+int snd_msnd_pcm(struct snd_card *card, int device);
int snd_msndmidi_new(struct snd_card *card, int device);
void snd_msndmidi_input_read(void *mpu);
if (err < 0)
goto err_release_region;
- err = snd_msnd_pcm(card, 0, NULL);
+ err = snd_msnd_pcm(card, 0);
if (err < 0) {
printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
goto err_release_region;
return 0;
err_release_region:
- if (chip->mappedbase)
- iounmap(chip->mappedbase);
+ iounmap(chip->mappedbase);
release_mem_region(chip->base, BUFFSIZE);
release_region(chip->io, DSP_NUMIO);
free_irq(chip->irq, chip);
#include <linux/pm.h>
#include <linux/pnp.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <asm/io.h>
-
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Yamaha OPL3SA2+");
MODULE_LICENSE("GPL");
return err;
}
chip->wss = wss;
- err = snd_wss_pcm(wss, 0, NULL);
+ err = snd_wss_pcm(wss, 0);
if (err < 0)
return err;
err = snd_wss_mixer(wss);
err = snd_opl3sa2_mixer(card);
if (err < 0)
return err;
- err = snd_wss_timer(wss, 0, NULL);
+ err = snd_wss_timer(wss, 0);
if (err < 0)
return err;
if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) {
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/wss.h>
int error;
struct snd_miro *miro = card->private_data;
struct snd_wss *codec;
- struct snd_timer *timer;
- struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
if (!miro->res_mc_base) {
if (error < 0)
return error;
- error = snd_wss_pcm(codec, 0, &pcm);
+ error = snd_wss_pcm(codec, 0);
if (error < 0)
return error;
if (error < 0)
return error;
- error = snd_wss_timer(codec, 0, &timer);
+ error = snd_wss_timer(codec, 0);
if (error < 0)
return error;
- miro->pcm = pcm;
+ miro->pcm = codec->pcm;
error = snd_miro_mixer(card, miro);
if (error < 0)
strcpy(card->driver, "miro");
sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, miro->name, pcm->name, miro->wss_base + 4,
- miro->irq, miro->dma1, miro->dma2);
+ card->shortname, miro->name, codec->pcm->name,
+ miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
rmidi = NULL;
#include <linux/delay.h>
#include <linux/pnp.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/tlv.h>
int xdma2;
struct snd_opti9xx *chip = card->private_data;
struct snd_wss *codec;
-#ifdef CS4231
- struct snd_timer *timer;
-#endif
- struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
struct snd_hwdep *synth;
if (error < 0)
return error;
chip->codec = codec;
- error = snd_wss_pcm(codec, 0, &pcm);
+ error = snd_wss_pcm(codec, 0);
if (error < 0)
return error;
error = snd_wss_mixer(codec);
return error;
#endif
#ifdef CS4231
- error = snd_wss_timer(codec, 0, &timer);
+ error = snd_wss_timer(codec, 0);
if (error < 0)
return error;
#endif
sprintf(card->shortname, "OPTi %s", card->driver);
#if defined(CS4231) || defined(OPTi93X)
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, pcm->name,
+ card->shortname, codec->pcm->name,
chip->wss_base + 4, irq, dma1, xdma2);
#else
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
- card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
+ card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
+ dma1);
#endif /* CS4231 || OPTi93X */
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
#include <linux/ioport.h>
#include <linux/export.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/emu8000.h>
#include <sound/emu8000_reg.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/init.h>
#include <sound/control.h>
#include <sound/initval.h>
static void
size_dram(struct snd_emu8000 *emu)
{
- int i, size, detected_size;
+ int i, size;
if (emu->dram_checked)
return;
size = 0;
- detected_size = 0;
/* write out a magic number */
snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
+ snd_emu8000_write_wait(emu);
- while (size < EMU8000_MAX_DRAM) {
+ /*
+ * Detect first 512 KiB. If a write succeeds at the beginning of a
+ * 512 KiB page we assume that the whole page is there.
+ */
+ EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
+ EMU8000_SMLD_READ(emu); /* discard stale data */
+ if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
+ goto skip_detect; /* No RAM */
+ snd_emu8000_read_wait(emu);
- size += 512 * 1024; /* increment 512kbytes */
+ for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) {
/* Write a unique data on the test address.
* if the address is out of range, the data is written on
snd_emu8000_read_wait(emu);
/* Otherwise, it's valid memory. */
- detected_size = size + 512 * 1024;
- }
-
- /* Distinguish 512 KiB from 0. */
- if (detected_size == 0) {
- snd_emu8000_read_wait(emu);
- EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
- EMU8000_SMLD_READ(emu); /* discard stale data */
- if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1)
- detected_size = 512 * 1024;
}
+skip_detect:
/* wait until FULL bit in SMAxW register is false */
for (i = 0; i < 10000; i++) {
if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
- snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
- emu->port1, detected_size/1024);
+ pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n",
+ emu->port1, size/1024);
- emu->mem_size = detected_size;
+ emu->mem_size = size;
emu->dram_checked = 1;
}
*/
#include "emu8000_local.h"
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/moduleparam.h>
static int emu8000_reset_addr;
rec->last_ptr = ptr;
/* reprogram timer */
- rec->timer.expires = jiffies + 1;
- add_timer(&rec->timer);
+ mod_timer(&rec->timer, jiffies + 1);
/* update period */
if (rec->period_pos >= (int)rec->period_size) {
runtime->private_data = rec;
spin_lock_init(&rec->timer_lock);
- init_timer(&rec->timer);
- rec->timer.function = emu8k_pcm_timer_func;
- rec->timer.data = (unsigned long)rec;
+ setup_timer(&rec->timer, emu8k_pcm_timer_func, (unsigned long)rec);
runtime->hw = emu8k_pcm_hw;
runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3;
/* start timer */
spin_lock_irqsave(&rec->timer_lock, flags);
if (! rec->timer_running) {
- rec->timer.expires = jiffies + 1;
- add_timer(&rec->timer);
+ mod_timer(&rec->timer, jiffies + 1);
rec->timer_running = 1;
}
spin_unlock_irqrestore(&rec->timer_lock, flags);
hw = dev->driver_data;
if (hw->pcm)
snd_device_free(dev->card, hw->pcm);
- if (hw->emu)
- snd_emux_free(hw->emu);
+ snd_emux_free(hw->emu);
snd_util_memhdr_free(hw->memhdr);
hw->emu = NULL;
hw->memhdr = NULL;
"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
port[dev], xirq, xdma8, xdma16);
- err = snd_sb8dsp_pcm(chip, 0, NULL);
+ err = snd_sb8dsp_pcm(chip, 0);
if (err < 0)
goto err_free;
err = snd_sbmixer_new(chip);
if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0)
return err;
- if ((err = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0)
+ if ((err = snd_sb16dsp_pcm(chip, 0)) < 0)
return err;
strcpy(card->driver,
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/time.h>
.pointer = snd_sb16_capture_pointer,
};
-int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm)
+int snd_sb16dsp_pcm(struct snd_sb *chip, int device)
{
struct snd_card *card = chip->card;
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0)
return err;
sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
pcm->private_data = chip;
+ chip->pcm = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
64*1024, 128*1024);
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
goto _err;
}
- if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0)
+ if ((err = snd_sb8dsp_pcm(chip, 0)) < 0)
goto _err;
if ((err = snd_sbmixer_new(chip)) < 0)
goto _err;
}
- if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0)
+ if ((err = snd_sb8dsp_midi(chip, 0)) < 0)
goto _err;
strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
* Cleaned up and rewrote lowlevel routines.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/time.h>
.pointer = snd_sb8_capture_pointer,
};
-int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
+int snd_sb8dsp_pcm(struct snd_sb *chip, int device)
{
struct snd_card *card = chip->card;
struct snd_pcm *pcm;
int err;
size_t max_prealloc = 64 * 1024;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0)
return err;
sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
snd_dma_isa_data(),
64*1024, max_prealloc);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
* Added full duplex UART mode for DSP version 2.0 and later.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/sb.h>
unsigned long flags;
spin_lock_irqsave(&chip->open_lock, flags);
- chip->midi_timer.expires = 1 + jiffies;
- add_timer(&chip->midi_timer);
+ mod_timer(&chip->midi_timer, 1 + jiffies);
spin_unlock_irqrestore(&chip->open_lock, flags);
snd_sb8dsp_midi_output_write(substream);
}
spin_lock_irqsave(&chip->open_lock, flags);
if (up) {
if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
- init_timer(&chip->midi_timer);
- chip->midi_timer.function = snd_sb8dsp_midi_output_timer;
- chip->midi_timer.data = (unsigned long) substream;
- chip->midi_timer.expires = 1 + jiffies;
- add_timer(&chip->midi_timer);
+ setup_timer(&chip->midi_timer,
+ snd_sb8dsp_midi_output_timer,
+ (unsigned long) substream);
+ mod_timer(&chip->midi_timer, 1 + jiffies);
chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
}
} else {
.trigger = snd_sb8dsp_midi_input_trigger,
};
-int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi)
+int snd_sb8dsp_midi(struct snd_sb *chip, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, "SB8 MIDI");
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = chip;
chip->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return 0;
}
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <asm/dma.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <sound/core.h>
if (err < 0)
goto err_unmap2;
- err = snd_wss_pcm(chip, 0, NULL);
+ err = snd_wss_pcm(chip, 0);
if (err < 0) {
snd_printk(KERN_ERR PFX
"error creating new WSS PCM device\n");
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/isa.h>
#include <linux/delay.h>
#include <linux/firmware.h>
codec_type, WSS_HWSHARE_DMA1, &chip);
if (!err) {
unsigned long flags;
- struct snd_pcm *pcm;
if (sscape->type != SSCAPE_VIVO) {
/*
}
- err = snd_wss_pcm(chip, 0, &pcm);
+ err = snd_wss_pcm(chip, 0);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No PCM device "
"for AD1845 chip\n");
goto _error;
}
if (chip->hardware != WSS_HW_AD1848) {
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No timer device "
"for AD1845 chip\n");
return err;
}
- err = snd_wss_pcm(chip, 0, NULL);
+ err = snd_wss_pcm(chip, 0);
if (err < 0)
return err;
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0)
return err;
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
unsigned long flags;
spin_lock_irqsave (&midi->virtual, flags);
- midi->timer.expires = 1 + jiffies;
- add_timer(&midi->timer);
+ mod_timer(&midi->timer, 1 + jiffies);
spin_unlock_irqrestore (&midi->virtual, flags);
snd_wavefront_midi_output_write(card);
}
if (up) {
if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
if (!midi->istimer) {
- init_timer(&midi->timer);
- midi->timer.function = snd_wavefront_midi_output_timer;
- midi->timer.data = (unsigned long) substream->rmidi->card->private_data;
- midi->timer.expires = 1 + jiffies;
- add_timer(&midi->timer);
+ setup_timer(&midi->timer,
+ snd_wavefront_midi_output_timer,
+ (unsigned long) substream->rmidi->card->private_data);
+ mod_timer(&midi->timer, 1 + jiffies);
}
midi->istimer++;
midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/wss.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
.pointer = snd_wss_capture_pointer,
};
-int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+int snd_wss_pcm(struct snd_wss *chip, int device)
{
struct snd_pcm *pcm;
int err;
64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
chip->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
return 0;
}
EXPORT_SYMBOL(snd_wss_pcm);
chip->timer = NULL;
}
-int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
+int snd_wss_timer(struct snd_wss *chip, int device)
{
struct snd_timer *timer;
struct snd_timer_id tid;
timer->private_free = snd_wss_timer_free;
timer->hw = snd_wss_timer_table;
chip->timer = timer;
- if (rtimer)
- *rtimer = timer;
return 0;
}
EXPORT_SYMBOL(snd_wss_timer);
timeout);
clear_bit(F_WRITEFLUSH, &dev.flags);
if (!signal_pending(current)) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE));
}
clear_bit(F_WRITING, &dev.flags);
& ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 3);
return 0;
}
{
if(!pss_no_sound)
{
- if(fw_load && pss_synth)
+ if (fw_load)
vfree(pss_synth);
if(pssmss)
unload_pss_mss(&cfg2);
s->dma_dac.hwptr = s->dma_dac.swptr = hwptr;
spin_unlock_irqrestore(&s->lock, flags);
remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
return 0;
}
static void __exit cleanup_trix(void)
{
- if (fw_load && trix_boot)
+ if (fw_load)
vfree(trix_boot);
if (sb)
unload_trix_sb(&cfg2);
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/info.h>
-#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/parisc-device.h>
if (h->irq >= 0)
free_irq(h->irq, h);
- if (h->iobase)
- iounmap(h->iobase);
-
+ iounmap(h->iobase);
kfree(h);
return 0;
}
To compile this driver as a module, choose M here: the module
will be called snd-rme9652.
+config SND_SE6X
+ tristate "Studio Evolution SE6X"
+ depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict
+ select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
+ help
+ Say Y or M here only if you actually have this sound card.
+
config SND_SIS7019
tristate "SiS 7019 Audio Accelerator"
depends on X86_32
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/ac97_codec.h>
-#include <asm/io.h>
-
#include "ad1889.h"
#include "ac97/ac97_id.h"
}
static int
-snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
+snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device)
{
int err;
struct snd_pcm *pcm;
- if (rpcm)
- *rpcm = NULL;
-
err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm);
if (err < 0)
return err;
return err;
}
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
free_irq(chip->irq, chip);
skip_hw:
- if (chip->iobase)
- iounmap(chip->iobase);
-
+ iounmap(chip->iobase);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
-
kfree(chip);
return 0;
}
if (err < 0)
goto free_and_ret;
- err = snd_ad1889_pcm_init(chip, 0, NULL);
+ err = snd_ad1889_pcm_init(chip, 0);
if (err < 0)
goto free_and_ret;
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#ifdef CONFIG_PM_SLEEP
static int ali_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ali *chip = card->private_data;
struct snd_ali_image *im;
outl(0xffffffff, ALI_REG(chip, ALI_STOP));
spin_unlock_irq(&chip->reg_lock);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int ali_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ali *chip = card->private_data;
struct snd_ali_image *im;
if (!im)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
spin_lock_irq(&chip->reg_lock);
for (i = 0; i < ALI_CHANNELS; i++) {
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#ifdef CONFIG_PM_SLEEP
static int snd_als300_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_als300 *chip = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_als300_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_als300 *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_als300_init(chip);
snd_ac97_resume(chip->ac97);
* - power management? (card can do voice wakeup according to datasheet!!)
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gameport.h>
#ifdef CONFIG_PM_SLEEP
static int snd_als4000_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_card_als4000 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
snd_pcm_suspend_all(chip->pcm);
snd_sbmixer_suspend(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_als4000_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_card_als4000 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_als4000_configure(chip);
snd_sbdsp_reset(chip);
snd_sbmixer_resume(chip);
expiry = HZ / 200;
expiry = max(expiry, 1); /* don't let it be zero! */
- dpcm->timer.expires = jiffies + expiry;
+ mod_timer(&dpcm->timer, jiffies + expiry);
dpcm->respawn_timer = 1;
- add_timer(&dpcm->timer);
}
static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
If internal and other stream playing, can't switch
*/
- init_timer(&dpcm->timer);
- dpcm->timer.data = (unsigned long) dpcm;
- dpcm->timer.function = snd_card_asihpi_timer_function;
+ setup_timer(&dpcm->timer, snd_card_asihpi_timer_function,
+ (unsigned long) dpcm);
dpcm->substream = substream;
runtime->private_data = dpcm;
runtime->private_free = snd_card_asihpi_runtime_free;
if (err)
return -EIO;
- init_timer(&dpcm->timer);
- dpcm->timer.data = (unsigned long) dpcm;
- dpcm->timer.function = snd_card_asihpi_timer_function;
+ setup_timer(&dpcm->timer, snd_card_asihpi_timer_function,
+ (unsigned long) dpcm);
dpcm->substream = substream;
runtime->private_data = dpcm;
runtime->private_free = snd_card_asihpi_runtime_free;
/* results in /dev/snd/hwC#D0 file for each card with index #
also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
*/
-static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
- int device, struct snd_hwdep **rhwdep)
+static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device)
{
struct snd_hwdep *hw;
int err;
- if (rhwdep)
- *rhwdep = NULL;
err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
if (err < 0)
return err;
hw->ops.ioctl = snd_asihpi_hpi_ioctl;
hw->ops.release = snd_asihpi_hpi_release;
hw->private_data = asihpi;
- if (rhwdep)
- *rhwdep = hw;
return 0;
}
/* always create, can be enabled or disabled dynamically
by enable_hwdep module param*/
- snd_asihpi_hpi_new(asihpi, 0, NULL);
+ snd_asihpi_hpi_new(asihpi, 0);
strcpy(card->driver, "ASIHPI");
/* operational/messaging errors */
#define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901
-
+#define HPI6000_ERROR_RESP_GET_LEN 902
#define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903
#define HPI6000_ERROR_MSG_GET_ADR 904
#define HPI6000_ERROR_RESP_GET_ADR 905
length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
} while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
if (!timeout)
- length = sizeof(struct hpi_response);
+ return HPI6000_ERROR_RESP_GET_LEN;
+
+ if (length > phr->size)
+ return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
/* get the response */
p_data = (u32 *)phr;
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/pci.h>
#include <linux/stringify.h>
#include <linux/module.h>
goto out;
}
+ res_max_size = min_t(size_t, res_max_size, sizeof(*hr));
+
switch (hm->h.function) {
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_ADAPTER_DELETE:
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
/* unmap PCI memory space, mapped during device init. */
- for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
- if (pci.ap_mem_base[idx])
- iounmap(pci.ap_mem_base[idx]);
- }
+ for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx)
+ iounmap(pci.ap_mem_base[idx]);
if (pa->irq)
free_irq(pa->irq, pa);
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int snd_atiixp_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp *chip = card->private_data;
int i;
snd_ac97_suspend(chip->ac97[i]);
snd_atiixp_aclink_down(chip);
snd_atiixp_chip_stop(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_atiixp_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_atiixp_aclink_reset(chip);
snd_atiixp_chip_start(chip);
__hw_end:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
+ iounmap(chip->remap_addr);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int snd_atiixp_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp_modem *chip = card->private_data;
int i;
snd_ac97_suspend(chip->ac97[i]);
snd_atiixp_aclink_down(chip);
snd_atiixp_chip_stop(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_atiixp_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp_modem *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_atiixp_aclink_reset(chip);
snd_atiixp_chip_start(chip);
__hw_end:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
+ iounmap(chip->remap_addr);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
#ifndef __SOUND_AU88X0_H
#define __SOUND_AU88X0_H
-#ifdef __KERNEL__
#include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <sound/hwdep.h>
#include <sound/ac97_codec.h>
#include <sound/tlv.h>
-#endif
#ifndef CHIP_AU8820
#include "au88x0_eq.h"
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
/* release the i/o ports & memory */
- if (chip->iobase_virt)
- iounmap(chip->iobase_virt);
-
+ iounmap(chip->iobase_virt);
pci_release_regions(chip->pci);
/* disable the PCI entry */
pci_disable_device(chip->pci);
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
* - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/bug.h> /* WARN_ONCE */
#include <linux/pci.h>
static int
snd_azf3328_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_azf3328 *chip = card->private_data;
u16 *saved_regs_ctrl_u16;
ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu);
snd_azf3328_suspend_regs(chip, chip->opl3_io,
ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int
snd_azf3328_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
const struct snd_azf3328 *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io,
ARRAY_SIZE(chip->saved_regs_game));
snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io,
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/bitops.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
snd_bt87x_stop(chip);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->mmio)
- iounmap(chip->mmio);
+ iounmap(chip->mmio);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
#ifdef CONFIG_PM_SLEEP
static int snd_ca0106_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ca0106 *chip = card->private_data;
int i;
snd_ca0106_mixer_suspend(chip);
ca0106_stop_chip(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_ca0106_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ca0106 *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- snd_card_disconnect(card);
- return -EIO;
- }
-
- pci_set_master(pci);
-
ca0106_init_chip(chip, 1);
if (chip->details->ac97)
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/tlv.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "ca0106.h"
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/asoundef.h>
-#include <asm/io.h>
#include "ca0106.h"
/* Does not work. Warning may block system in capture mode */
/* #define USE_VAR48KRATE */
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
static int snd_cmipci_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cmipci *cm = card->private_data;
int i;
/* disable ints */
snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_cmipci_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cmipci *cm = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
/* reset / initialize to a sane state */
snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
snd_cmipci_ch_reset(cm, CM_CH_PLAY);
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
.pointer = snd_cs4281_pointer,
};
-static int snd_cs4281_pcm(struct cs4281 *chip, int device,
- struct snd_pcm **rpcm)
+static int snd_cs4281_pcm(struct cs4281 *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(chip->card, "CS4281", device, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 512*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->ba0)
- iounmap(chip->ba0);
- if (chip->ba1)
- iounmap(chip->ba1);
+ iounmap(chip->ba0);
+ iounmap(chip->ba1);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
.trigger = snd_cs4281_midi_input_trigger,
};
-static int snd_cs4281_midi(struct cs4281 *chip, int device,
- struct snd_rawmidi **rrawmidi)
+static int snd_cs4281_midi(struct cs4281 *chip, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, "CS4281");
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = chip;
chip->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return 0;
}
snd_card_free(card);
return err;
}
- if ((err = snd_cs4281_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs4281_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_cs4281_midi(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs4281_midi(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
static int cs4281_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs4281 *chip = card->private_data;
u32 ulCLK;
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK &= ~CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int cs4281_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs4281 *chip = card->private_data;
unsigned int i;
u32 ulCLK;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK |= CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
}
card->private_data = chip;
chip->accept_valid = mmap_valid[dev];
- if ((err = snd_cs46xx_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm_rear(chip, 1)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm_iec958(chip, 2)) < 0) {
snd_card_free(card);
return err;
}
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (chip->nr_ac97_codecs ==2) {
- if ((err = snd_cs46xx_pcm_center_lfe(chip,3,NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm_center_lfe(chip, 3)) < 0) {
snd_card_free(card);
return err;
}
}
#endif
- if ((err = snd_cs46xx_midi(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs46xx_midi(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
struct snd_cs46xx **rcodec);
extern const struct dev_pm_ops snd_cs46xx_pm;
-int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device);
int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device);
-int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rmidi);
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device);
int snd_cs46xx_start_dsp(struct snd_cs46xx *chip);
int snd_cs46xx_gameport(struct snd_cs46xx *chip);
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include "cs46xx.h"
-#include <asm/io.h>
-
#include "cs46xx_lib.h"
#include "dsp_spos.h"
#define MAX_PLAYBACK_CHANNELS 1
#endif
-int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm)
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device,
- struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
-int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device,
- struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
-int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device,
- struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
#endif
.trigger = snd_cs46xx_midi_input_trigger,
};
-int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi)
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, "CS46XX");
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = chip;
chip->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = NULL;
return 0;
}
for (idx = 0; idx < 5; idx++) {
struct snd_cs46xx_region *region = &chip->region.idx[idx];
- if (region->remap_addr)
- iounmap(region->remap_addr);
+
+ iounmap(region->remap_addr);
release_and_free_resource(region->resource);
}
static int snd_cs46xx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_cs46xx *chip = card->private_data;
int i, amp_saved;
/* disable CLKRUN */
chip->active_ctrl(chip, -chip->amplifier);
chip->amplifier = amp_saved; /* restore the status */
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_cs46xx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_cs46xx *chip = card->private_data;
int amp_saved;
#endif
unsigned int tmp;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
amp_saved = chip->amplifier;
chip->amplifier = 0;
chip->active_ctrl(chip, 1); /* force to on */
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/init.h>
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/init.h>
return err;
}
- err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+ err = snd_sb16dsp_pcm(chip->sb, 0);
if (err < 0) {
dev_err(card->dev, "Could not create PCM\n");
snd_cs5530_free(chip);
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
static int snd_cs5535audio_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
int i;
}
/* save important regs, then disable aclink in hw */
snd_cs5535audio_stop_hardware(cs5535au);
-
- if (pci_save_state(pci)) {
- dev_err(dev, "pci_save_state failed!\n");
- return -EIO;
- }
- pci_disable_device(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_cs5535audio_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
u32 tmp;
int timeout;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
/* set LNK_WRM_RST to reset AC link */
cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST);
free_irq(hw->irq, hw);
hw->irq = -1;
-
- if (hw->mem_base)
- iounmap(hw->mem_base);
-
+ iounmap(hw->mem_base);
hw->mem_base = NULL;
if (hw->io_base)
pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
-
return 0;
}
static int hw_resume(struct hw *hw, struct card_conf *info)
{
- struct pci_dev *pci = hw->pci;
-
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
/* Re-initialize card hardware. */
return hw_card_init(hw, info);
}
free_irq(hw->irq, hw);
hw->irq = -1;
-
- if (hw->mem_base)
- iounmap(hw->mem_base);
-
+ iounmap(hw->mem_base);
hw->mem_base = NULL;
if (hw->io_base)
#ifdef CONFIG_PM_SLEEP
static int hw_suspend(struct hw *hw)
{
- struct pci_dev *pci = hw->pci;
-
hw_card_stop(hw);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
-
return 0;
}
static int hw_resume(struct hw *hw, struct card_conf *info)
{
- struct pci_dev *pci = hw->pci;
-
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
/* Re-initialize card hardware. */
return hw_card_init(hw, info);
}
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
if (chip->comm_page)
snd_dma_free_pages(&chip->commpage_dma_buf);
- if (chip->dsp_registers)
- iounmap(chip->dsp_registers);
-
+ iounmap(chip->dsp_registers);
release_and_free_resource(chip->iores);
-
-
pci_disable_device(chip->pci);
/* release chip data */
static int snd_echo_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct echoaudio *chip = dev_get_drvdata(dev);
snd_pcm_suspend_all(chip->analog_pcm);
chip->dsp_code = NULL;
free_irq(chip->irq, chip);
chip->irq = -1;
- pci_save_state(pci);
- pci_disable_device(pci);
-
return 0;
}
u32 pipe_alloc_mask;
int err;
- pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
if (commpage_bak == NULL)
return -ENOMEM;
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
spin_lock_irq(&chip->lock);
if (up) {
if (!chip->tinuse) {
- init_timer(&chip->timer);
- chip->timer.function = snd_echo_midi_output_write;
- chip->timer.data = (unsigned long)chip;
+ setup_timer(&chip->timer, snd_echo_midi_output_write,
+ (unsigned long)chip);
chip->tinuse = 1;
}
} else {
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
goto error;
card->private_data = emu;
emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
- if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm(emu, 0)) < 0)
goto error;
- if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0)
goto error;
- if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0)
goto error;
/* This stores the periods table. */
if (emu->card_capabilities->ca0151_chip) { /* P16V */
if ((err = snd_emu10k1_timer(emu, 0)) < 0)
goto error;
- if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0)
goto error;
if (emu->card_capabilities->ca0151_chip) { /* P16V */
- if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0)
+ if ((err = snd_p16v_pcm(emu, 4)) < 0)
goto error;
}
if (emu->audigy) {
if ((err = snd_emu10k1_midi(emu)) < 0)
goto error;
}
- if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0)
+ if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0)
goto error;
#ifdef ENABLE_SYNTH
if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
#ifdef CONFIG_PM_SLEEP
static int snd_emu10k1_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_emu10k1 *emu = card->private_data;
snd_p16v_suspend(emu);
snd_emu10k1_done(emu);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_emu10k1_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_emu10k1 *emu = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_emu10k1_resume_init(emu);
snd_emu10k1_efx_resume(emu);
snd_ac97_resume(emu->ac97);
{ }
};
-static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)
+static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device)
{
struct snd_pcm *pcm;
const struct snd_pcm_chmap_elem *map = NULL;
int err;
int capture = 0;
- if (rpcm)
- *rpcm = NULL;
if (device == 0)
capture = 1;
snd_dma_pci_data(emu->pci),
32*1024, 32*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
1 << 2, NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
-
- return 0;
}
static int snd_emu10k1x_create(struct snd_card *card,
return err;
}
- if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) {
+ if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) {
+ if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) {
snd_card_free(card);
return err;
}
return 0;
}
-int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device,
- struct snd_hwdep **rhwdep)
+int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
{
struct snd_hwdep *hw;
int err;
- if (rhwdep)
- *rhwdep = NULL;
if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
return err;
strcpy(hw->name, "EMU10K1 (FX8010)");
hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
hw->ops.release = snd_emu10k1_fx8010_release;
hw->private_data = emu;
- if (rhwdep)
- *rhwdep = hw;
return 0;
}
.page = snd_pcm_sgbuf_ops_page,
};
-int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
+int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0)
return err;
for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
-int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device,
- struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0)
return err;
if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0)
return err;
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
.pointer = snd_emu10k1_capture_pointer,
};
-int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device,
- struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
.ack = snd_emu10k1_fx8010_playback_transfer,
};
-int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device,
- struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_kcontrol *kctl;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0)
return err;
pcm->info_flags = 0;
strcpy(pcm->name, "Multichannel Capture/PT Playback");
emu->pcm_efx = pcm;
- if (rpcm)
- *rpcm = pcm;
/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs
* to these
static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime)
{
struct snd_emu10k1_pcm *epcm = runtime->private_data;
-
- if (epcm) {
- /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */
- kfree(epcm);
- }
+
+ kfree(epcm);
}
/* open_playback callback */
return 0;
}
-int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
+int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
/* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */
emu->p16v_device_offset = device;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0)
return err;
*/
}
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
* by Kurt J. Bosch
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
{ }
};
-static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device,
- struct snd_pcm **rpcm)
+static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);
if (err < 0)
return err;
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps, 2, 0, NULL);
#endif
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
+ return err;
}
-static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device,
- struct snd_pcm **rpcm)
+static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);
if (err < 0)
return err;
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
surround_map, 2, 0, NULL);
#endif
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
+ return err;
}
/*
#ifdef CONFIG_PM_SLEEP
static int snd_ensoniq_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct ensoniq *ensoniq = card->private_data;
udelay(100);
snd_ak4531_suspend(ensoniq->u.es1370.ak4531);
#endif
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_ensoniq_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct ensoniq *ensoniq = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_ensoniq_chip_init(ensoniq);
#ifdef CHIP1371
.trigger = snd_ensoniq_midi_input_trigger,
};
-static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device,
- struct snd_rawmidi **rrawmidi)
+static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, CHIP_NAME);
SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = ensoniq;
ensoniq->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return 0;
}
return err;
}
#endif
- if ((err = snd_ensoniq_pcm(ensoniq, 0, NULL)) < 0) {
+ if ((err = snd_ensoniq_pcm(ensoniq, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_ensoniq_pcm2(ensoniq, 1, NULL)) < 0) {
+ if ((err = snd_ensoniq_pcm2(ensoniq, 1)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_ensoniq_midi(ensoniq, 0, NULL)) < 0) {
+ if ((err = snd_ensoniq_midi(ensoniq, 0)) < 0) {
snd_card_free(card);
return err;
}
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <asm/io.h>
-
MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>");
MODULE_DESCRIPTION("ESS Solo-1");
MODULE_LICENSE("GPL");
static int es1938_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct es1938 *chip = card->private_data;
unsigned char *s, *d;
free_irq(chip->irq, chip);
chip->irq = -1;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
struct es1938 *chip = card->private_data;
unsigned char *s, *d;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
-
if (request_irq(pci->irq, snd_es1938_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
dev_err(dev, "unable to grab IRQ %d, disabling device\n",
* places.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int es1968_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct es1968 *chip = card->private_data;
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
snd_es1968_bob_stop(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int es1968_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct es1968 *chip = card->private_data;
struct esschan *es;
if (! chip->do_pm)
return 0;
- /* restore all our config */
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_es1968_chip_init(chip);
/* need to restore the base pointers.. */
* The driver for the ForteMedia FM801 based soundcards
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
- * Support FM only card by Andy Shevchenko <andy@smile.org.ua>
- *
* 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
* 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
- *
*/
#include <linux/delay.h>
.pointer = snd_fm801_capture_pointer,
};
-static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm)
+static int snd_fm801_pcm(struct fm801 *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0)
return err;
snd_dma_pci_data(chip->pci),
chip->multichannel ? 128*1024 : 64*1024, 128*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_alt_chmaps,
chip->multichannel ? 6 : 2, 0,
NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
}
/*
v4l2_device_unregister(&chip->v4l2_dev);
}
#endif
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
- pci_release_regions(chip->pci);
- pci_disable_device(chip->pci);
-
- kfree(chip);
return 0;
}
};
*rchip = NULL;
- if ((err = pci_enable_device(pci)) < 0)
+ if ((err = pcim_enable_device(pci)) < 0)
return err;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL) {
- pci_disable_device(pci);
+ chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
return -ENOMEM;
- }
spin_lock_init(&chip->reg_lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->tea575x_tuner = tea575x_tuner;
- if ((err = pci_request_regions(pci, "FM801")) < 0) {
- kfree(chip);
- pci_disable_device(pci);
+ if ((err = pci_request_regions(pci, "FM801")) < 0)
return err;
- }
chip->port = pci_resource_start(pci, 0);
if ((tea575x_tuner & TUNER_ONLY) == 0) {
- if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
- KBUILD_MODNAME, chip)) {
- dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
+ if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_fm801_free(chip);
return -EBUSY;
}
/* init might set tuner access method */
tea575x_tuner = chip->tea575x_tuner;
- if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
- pci_clear_master(pci);
- free_irq(chip->irq, chip);
- chip->irq = -1;
- }
-
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_fm801_free(chip);
return err;
if (chip->tea575x_tuner & TUNER_ONLY)
goto __fm801_tuner_only;
- if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_fm801_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
static int snd_fm801_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct fm801 *chip = card->private_data;
int i;
for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
chip->saved_regs[i] = inw(chip->port + saved_regs[i]);
/* FIXME: tea575x suspend */
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_fm801_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct fm801 *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_fm801_chip_init(chip, 1);
snd_ac97_resume(chip->ac97);
snd_ac97_resume(chip->ac97_sec);
config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
select SND_HDA_GENERIC
+ select INPUT
help
Say Y or M here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
/*
* debug prints of the parsed results
*/
- codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
- cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
- cfg->line_out_pins[2], cfg->line_out_pins[3],
- cfg->line_out_pins[4],
+ codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+ codec->chip_name, cfg->line_outs, cfg->line_out_pins[0],
+ cfg->line_out_pins[1], cfg->line_out_pins[2],
+ cfg->line_out_pins[3], cfg->line_out_pins[4],
cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
(cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
"speaker" : "line"));
codec->fixup_id = pq->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
codec->fixup_name = pq->name;
+ codec_dbg(codec, "%s: picked fixup %s (pin match)\n",
+ codec->chip_name, codec->fixup_name);
#endif
codec->fixup_list = fixlist;
return;
codec->fixup_list = NULL;
codec->fixup_name = NULL;
codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP;
+ codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n",
+ codec->chip_name);
return;
}
codec->fixup_id = models->id;
codec->fixup_name = models->name;
codec->fixup_list = fixlist;
+ codec_dbg(codec, "%s: picked fixup %s (model specified)\n",
+ codec->chip_name, codec->fixup_name);
return;
}
models++;
id = q->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name = q->name;
+ codec_dbg(codec, "%s: picked fixup %s (PCI SSID%s)\n",
+ codec->chip_name, name, q->subdevice_mask ? "" : " - vendor generic");
#endif
}
}
id = q->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name = q->name;
+ codec_dbg(codec, "%s: picked fixup %s (codec SSID)\n",
+ codec->chip_name, name);
#endif
break;
}
EXPORT_SYMBOL_GPL(azx_notifier_unregister);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Common HDA driver funcitons");
+MODULE_DESCRIPTION("Common HDA driver functions");
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/component.h>
+#include <drm/i915_component.h>
#include <sound/core.h>
-#include <drm/i915_powerwell.h>
#include "hda_priv.h"
-#include "hda_i915.h"
+#include "hda_intel.h"
/* Intel HSW/BDW display HDA controller Extended Mode registers.
* EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
#define AZX_REG_EM4 0x100c
#define AZX_REG_EM5 0x1010
-static int (*get_power)(void);
-static int (*put_power)(void);
-static int (*get_cdclk)(void);
-
-int hda_display_power(bool enable)
+int hda_display_power(struct hda_intel *hda, bool enable)
{
- if (!get_power || !put_power)
+ struct i915_audio_component *acomp = &hda->audio_component;
+
+ if (!acomp->ops)
return -ENODEV;
- pr_debug("HDA display power %s \n",
- enable ? "Enable" : "Disable");
+ dev_dbg(&hda->chip.pci->dev, "display power %s\n",
+ enable ? "enable" : "disable");
if (enable)
- return get_power();
+ acomp->ops->get_power(acomp->dev);
else
- return put_power();
+ acomp->ops->put_power(acomp->dev);
+
+ return 0;
}
-void haswell_set_bclk(struct azx *chip)
+void haswell_set_bclk(struct hda_intel *hda)
{
int cdclk_freq;
unsigned int bclk_m, bclk_n;
+ struct i915_audio_component *acomp = &hda->audio_component;
- if (!get_cdclk)
+ if (!acomp->ops)
return;
- cdclk_freq = get_cdclk();
+ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
switch (cdclk_freq) {
case 337500:
bclk_m = 16;
break;
}
- azx_writew(chip, EM4, bclk_m);
- azx_writew(chip, EM5, bclk_n);
+ azx_writew(&hda->chip, EM4, bclk_m);
+ azx_writew(&hda->chip, EM5, bclk_n);
}
-
-int hda_i915_init(void)
+static int hda_component_master_bind(struct device *dev)
{
- int err = 0;
-
- get_power = symbol_request(i915_request_power_well);
- if (!get_power) {
- pr_warn("hda-i915: get_power symbol get fail\n");
- return -ENODEV;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct i915_audio_component *acomp = &hda->audio_component;
+ int ret;
+
+ ret = component_bind_all(dev, acomp);
+ if (ret < 0)
+ return ret;
+
+ if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
+ acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
+ ret = -EINVAL;
+ goto out_unbind;
}
- put_power = symbol_request(i915_release_power_well);
- if (!put_power) {
- symbol_put(i915_request_power_well);
- get_power = NULL;
- return -ENODEV;
+ /*
+ * Atm, we don't support dynamic unbinding initiated by the child
+ * component, so pin its containing module until we unbind.
+ */
+ if (!try_module_get(acomp->ops->owner)) {
+ ret = -ENODEV;
+ goto out_unbind;
}
- get_cdclk = symbol_request(i915_get_cdclk_freq);
- if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
- pr_warn("hda-i915: get_cdclk symbol get fail\n");
+ return 0;
- pr_debug("HDA driver get symbol successfully from i915 module\n");
+out_unbind:
+ component_unbind_all(dev, acomp);
- return err;
+ return ret;
}
-int hda_i915_exit(void)
+static void hda_component_master_unbind(struct device *dev)
{
- if (get_power) {
- symbol_put(i915_request_power_well);
- get_power = NULL;
- }
- if (put_power) {
- symbol_put(i915_release_power_well);
- put_power = NULL;
- }
- if (get_cdclk) {
- symbol_put(i915_get_cdclk_freq);
- get_cdclk = NULL;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct i915_audio_component *acomp = &hda->audio_component;
+
+ module_put(acomp->ops->owner);
+ component_unbind_all(dev, acomp);
+ WARN_ON(acomp->ops || acomp->dev);
+}
+
+static const struct component_master_ops hda_component_master_ops = {
+ .bind = hda_component_master_bind,
+ .unbind = hda_component_master_unbind,
+};
+
+static int hda_component_master_match(struct device *dev, void *data)
+{
+ /* i915 is the only supported component */
+ return !strcmp(dev->driver->name, "i915");
+}
+
+int hda_i915_init(struct hda_intel *hda)
+{
+ struct component_match *match = NULL;
+ struct device *dev = &hda->chip.pci->dev;
+ struct i915_audio_component *acomp = &hda->audio_component;
+ int ret;
+
+ component_match_add(dev, &match, hda_component_master_match, hda);
+ ret = component_master_add_with_match(dev, &hda_component_master_ops,
+ match);
+ if (ret < 0)
+ goto out_err;
+
+ /*
+ * Atm, we don't support deferring the component binding, so make sure
+ * i915 is loaded and that the binding successfully completes.
+ */
+ request_module("i915");
+
+ if (!acomp->ops) {
+ ret = -ENODEV;
+ goto out_master_del;
}
+ dev_dbg(dev, "bound to i915 component master\n");
+
+ return 0;
+out_master_del:
+ component_master_del(dev, &hda_component_master_ops);
+out_err:
+ dev_err(dev, "failed to add i915 component master (%d)\n", ret);
+
+ return ret;
+}
+
+int hda_i915_exit(struct hda_intel *hda)
+{
+ struct device *dev = &hda->chip.pci->dev;
+
+ component_master_del(dev, &hda_component_master_ops);
+
return 0;
}
+++ /dev/null
-/*
- * 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.
- */
-#ifndef __SOUND_HDA_I915_H
-#define __SOUND_HDA_I915_H
-
-#ifdef CONFIG_SND_HDA_I915
-int hda_display_power(bool enable);
-void haswell_set_bclk(struct azx *chip);
-int hda_i915_init(void);
-int hda_i915_exit(void);
-#else
-static inline int hda_display_power(bool enable) { return 0; }
-static inline void haswell_set_bclk(struct azx *chip) { return; }
-static inline int hda_i915_init(void)
-{
- return -ENODEV;
-}
-static inline int hda_i915_exit(void)
-{
- return 0;
-}
-#endif
-
-#endif
#include "hda_codec.h"
#include "hda_controller.h"
#include "hda_priv.h"
-#include "hda_i915.h"
+#include "hda_intel.h"
/* position fix mode */
enum {
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
-struct hda_intel {
- struct azx chip;
-
- /* for pending irqs */
- struct work_struct irq_pending_work;
-
- /* sync probing */
- struct completion probe_wait;
- struct work_struct probe_work;
-
- /* card list (for power_save trigger) */
- struct list_head list;
-
- /* extra flags */
- unsigned int irq_pending_warned:1;
-
- /* VGA-switcheroo setup */
- unsigned int use_vga_switcheroo:1;
- unsigned int vga_switcheroo_registered:1;
- unsigned int init_failed:1; /* delayed init failed */
-
- /* secondary power domain for hdmi audio under vga device */
- struct dev_pm_domain hdmi_pm_domain;
-};
-
#ifdef CONFIG_X86
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
{
*/
static int azx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
struct hda_intel *hda;
if (chip->msi)
pci_disable_msi(chip->pci);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- hda_display_power(false);
+ hda_display_power(hda, false);
return 0;
}
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- hda_display_power(true);
- haswell_set_bclk(chip);
+ hda_display_power(hda, true);
+ haswell_set_bclk(hda);
}
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(chip->card->dev,
- "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
if (chip->msi)
if (pci_enable_msi(pci) < 0)
chip->msi = 0;
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- hda_display_power(false);
+ hda_display_power(hda, false);
return 0;
}
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- hda_display_power(true);
- haswell_set_bclk(chip);
+ hda_display_power(hda, true);
+ haswell_set_bclk(hda);
}
/* Read STATESTS before controller reset */
free_irq(chip->irq, (void*)chip);
if (chip->msi)
pci_disable_msi(chip->pci);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
+ iounmap(chip->remap_addr);
azx_free_stream_pages(chip);
if (chip->region_requested)
release_firmware(chip->fw);
#endif
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- hda_display_power(false);
- hda_i915_exit();
+ hda_display_power(hda, false);
+ hda_i915_exit(hda);
}
kfree(hda);
/* initialize chip */
azx_init_pci(chip);
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- haswell_set_bclk(chip);
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+ struct hda_intel *hda;
+
+ hda = container_of(chip, struct hda_intel, chip);
+ haswell_set_bclk(hda);
+ }
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
/* Request power well for Haswell HDA controller and codec */
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
#ifdef CONFIG_SND_HDA_I915
- err = hda_i915_init();
- if (err < 0) {
- dev_err(chip->card->dev,
- "Error request power-well from i915\n");
+ err = hda_i915_init(hda);
+ if (err < 0)
goto out_free;
- }
- err = hda_display_power(true);
+ err = hda_display_power(hda, true);
if (err < 0) {
dev_err(chip->card->dev,
"Cannot turn on display power on i915\n");
--- /dev/null
+/*
+ * 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.
+ */
+#ifndef __SOUND_HDA_INTEL_H
+#define __SOUND_HDA_INTEL_H
+
+#include <drm/i915_component.h>
+#include "hda_priv.h"
+
+struct hda_intel {
+ struct azx chip;
+
+ /* for pending irqs */
+ struct work_struct irq_pending_work;
+
+ /* sync probing */
+ struct completion probe_wait;
+ struct work_struct probe_work;
+
+ /* card list (for power_save trigger) */
+ struct list_head list;
+
+ /* extra flags */
+ unsigned int irq_pending_warned:1;
+
+ /* VGA-switcheroo setup */
+ unsigned int use_vga_switcheroo:1;
+ unsigned int vga_switcheroo_registered:1;
+ unsigned int init_failed:1; /* delayed init failed */
+
+ /* secondary power domain for hdmi audio under vga device */
+ struct dev_pm_domain hdmi_pm_domain;
+
+ /* i915 component interface */
+ struct i915_audio_component audio_component;
+};
+
+#ifdef CONFIG_SND_HDA_I915
+int hda_display_power(struct hda_intel *hda, bool enable);
+void haswell_set_bclk(struct hda_intel *hda);
+int hda_i915_init(struct hda_intel *hda);
+int hda_i915_exit(struct hda_intel *hda);
+#else
+static inline int hda_display_power(struct hda_intel *hda, bool enable)
+{
+ return 0;
+}
+static inline void haswell_set_bclk(struct hda_intel *hda) { return; }
+static inline int hda_i915_init(struct hda_intel *hda)
+{
+ return -ENODEV;
+}
+static inline int hda_i915_exit(struct hda_intel *hda)
+{
+ return 0;
+}
+#endif
+
+#endif
* E/F quad mic array
*/
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad198x_spec *spec = codec->spec;
- return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
- spec->num_channel_mode);
-}
-
-static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad198x_spec *spec = codec->spec;
- return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
- spec->num_channel_mode, spec->multiout.max_channels);
-}
-
-static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad198x_spec *spec = codec->spec;
- int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
- spec->num_channel_mode,
- &spec->multiout.max_channels);
- if (err >= 0 && spec->need_dac_fix)
- spec->multiout.num_dacs = spec->multiout.max_channels / 2;
- return err;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
#include <linux/pci.h>
#include <linux/dmi.h>
#include <linux/module.h>
+#include <linux/input.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
hda_nid_t pll_nid;
unsigned int pll_coef_idx, pll_coef_bit;
unsigned int coef0;
+ struct input_dev *kb_dev;
};
/*
}
}
+static void gpio2_mic_hotkey_event(struct hda_codec *codec,
+ struct hda_jack_callback *event)
+{
+ struct alc_spec *spec = codec->spec;
+
+ /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
+ send both key on and key off event for every interrupt. */
+ input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
+ input_sync(spec->kb_dev);
+ input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
+ input_sync(spec->kb_dev);
+}
+
+static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /* GPIO1 = set according to SKU external amp
+ GPIO2 = mic mute hotkey
+ GPIO3 = mute LED
+ GPIO4 = mic mute LED */
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
+ { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
+ {}
+ };
+
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->kb_dev = input_allocate_device();
+ if (!spec->kb_dev) {
+ codec_err(codec, "Out of memory (input_allocate_device)\n");
+ return;
+ }
+ spec->kb_dev->name = "Microphone Mute Button";
+ spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+ spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
+ if (input_register_device(spec->kb_dev)) {
+ codec_err(codec, "input_register_device failed\n");
+ input_free_device(spec->kb_dev);
+ spec->kb_dev = NULL;
+ return;
+ }
+
+ snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_codec_write_cache(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
+ snd_hda_jack_detect_enable_callback(codec, codec->afg,
+ gpio2_mic_hotkey_event);
+
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+ spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
+ spec->gpio_mic_led_mask = 0x10;
+ return;
+ }
+
+ if (!spec->kb_dev)
+ return;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PROBE:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
+ case HDA_FIXUP_ACT_FREE:
+ input_unregister_device(spec->kb_dev);
+ spec->kb_dev = NULL;
+ }
+}
+
static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
ALC282_FIXUP_ASPIRE_V5_PINS,
ALC280_FIXUP_HP_GPIO4,
ALC286_FIXUP_HP_GPIO_LED,
+ ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
+ ALC280_FIXUP_HP_DOCK_PINS,
};
static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc286_fixup_hp_gpio_led,
},
+ [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc280_fixup_hp_gpio2_mic_hotkey,
+ },
+ [ALC280_FIXUP_HP_DOCK_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x21011020 }, /* line-out */
+ { 0x1a, 0x01a1903c }, /* headset mic */
+ { 0x18, 0x2181103f }, /* line-in */
+ { },
+ },
+ .chained = true,
+ .chain_id = ALC280_FIXUP_HP_GPIO4
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
/* ALC282 */
SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS),
SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
.pointer = snd_ice1712_capture_pointer,
};
-static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
- if (rpcm)
- *rpcm = pcm;
-
dev_warn(ice->card->dev,
"Consumer PCM code does not work well at the moment --jk\n");
return 0;
}
-static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm);
if (err < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
.pointer = snd_ice1712_capture_pro_pointer,
};
-static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm);
if (err < 0)
return err;
snd_dma_pci_data(ice->pci), 256*1024, 256*1024);
ice->pcm_pro = pcm;
- if (rpcm)
- *rpcm = pcm;
if (ice->cs8427) {
/* assign channels to iec958 */
c = &no_matched;
__found:
- err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL);
+ err = snd_ice1712_pcm_profi(ice, pcm_dev++);
if (err < 0) {
snd_card_free(card);
return err;
}
if (ice_has_con_ac97(ice)) {
- err = snd_ice1712_pcm(ice, pcm_dev++, NULL);
+ err = snd_ice1712_pcm(ice, pcm_dev++);
if (err < 0) {
snd_card_free(card);
return err;
}
if (ice_has_con_ac97(ice)) {
- err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL);
+ err = snd_ice1712_pcm_ds(ice, pcm_dev++);
if (err < 0) {
snd_card_free(card);
return err;
#ifdef CONFIG_PM_SLEEP
static int snd_ice1712_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
if (ice->pm_suspend)
ice->pm_suspend(ice);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_ice1712_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
int rate;
if (!ice->pm_suspend_enabled)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- snd_card_disconnect(card);
- return -EIO;
- }
-
- pci_set_master(pci);
-
if (ice->cur_rate)
rate = ice->cur_rate;
else
#ifdef CONFIG_PM_SLEEP
static int snd_vt1724_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
if (ice->pm_suspend)
ice->pm_suspend(ice);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_vt1724_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
if (!ice->pm_suspend_enabled)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- snd_card_disconnect(card);
- return -EIO;
- }
-
- pci_set_master(pci);
-
snd_vt1724_chip_reset(ice);
if (snd_vt1724_chip_init(ice) < 0) {
snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac);
}
-void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode)
-{
- u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK;
-
- mode &= WM8766_DAC3_MSTR_MASK;
- snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode);
-}
-
-void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power)
-{
- u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK;
-
- power &= WM8766_DAC3_POWER_MASK;
- snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power);
-}
-
void snd_wm8766_volume_restore(struct snd_wm8766 *wm)
{
u16 val = wm->regs[WM8766_REG_DACR1];
void snd_wm8766_init(struct snd_wm8766 *wm);
void snd_wm8766_resume(struct snd_wm8766 *wm);
void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac);
-void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode);
-void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power);
void snd_wm8766_volume_restore(struct snd_wm8766 *wm);
int snd_wm8766_build_controls(struct snd_wm8766 *wm);
snd_wm8776_write(wm, i, wm->regs[i]);
}
-void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac)
-{
- snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac);
-}
-
-void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc)
-{
- snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc);
-}
-
-void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode)
-{
- snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode);
-}
-
void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power)
{
snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power);
void snd_wm8776_init(struct snd_wm8776 *wm);
void snd_wm8776_resume(struct snd_wm8776 *wm);
-void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac);
-void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc);
-void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode);
void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power);
void snd_wm8776_volume_restore(struct snd_wm8776 *wm);
int snd_wm8776_build_controls(struct snd_wm8776 *wm);
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int intel8x0_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0 *chip = card->private_data;
int i;
free_irq(chip->irq, chip);
chip->irq = -1;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- /* The call below may disable built-in speaker on some laptops
- * after S2RAM. So, don't touch it.
- */
- /* pci_set_power_state(pci, PCI_D3hot); */
return 0;
}
struct intel8x0 *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
snd_intel8x0_chip_init(chip, 0);
if (request_irq(pci->irq, snd_intel8x0_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int intel8x0m_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0m *chip = card->private_data;
int i;
free_irq(chip->irq, chip);
chip->irq = -1;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0m *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
if (request_irq(pci->irq, snd_intel8x0m_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
dev_err(dev, "unable to grab IRQ %d, disabling device\n",
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/firmware.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
// ----------------------------------------------------------------------------
// Debug Stuff
// ----------------------------------------------------------------------------
korg1212->sharedBufferPtr->cardCommand = 0xffffffff;
/* program the timer */
korg1212->stop_pending_cnt = HZ;
- korg1212->timer.expires = jiffies + 1;
- add_timer(&korg1212->timer);
+ mod_timer(&korg1212->timer, jiffies + 1);
}
}
} else {
if (--korg1212->stop_pending_cnt > 0) {
/* reprogram timer */
- korg1212->timer.expires = jiffies + 1;
- add_timer(&korg1212->timer);
+ mod_timer(&korg1212->timer, jiffies + 1);
} else {
snd_printd("korg1212_timer_func timeout\n");
korg1212->sharedBufferPtr->cardCommand = 0;
init_waitqueue_head(&korg1212->wait);
spin_lock_init(&korg1212->lock);
mutex_init(&korg1212->open_mutex);
- init_timer(&korg1212->timer);
- korg1212->timer.function = snd_korg1212_timer_func;
- korg1212->timer.data = (unsigned long)korg1212;
+ setup_timer(&korg1212->timer, snd_korg1212_timer_func,
+ (unsigned long)korg1212);
korg1212->irq = -1;
korg1212->clkSource = K1212_CLKIDX_Local;
lola_free_mixer(chip);
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
- if (chip->bar[0].remap_addr)
- iounmap(chip->bar[0].remap_addr);
- if (chip->bar[1].remap_addr)
- iounmap(chip->bar[1].remap_addr);
+ iounmap(chip->bar[0].remap_addr);
+ iounmap(chip->bar[1].remap_addr);
if (chip->rb.area)
snd_dma_free_pages(&chip->rb);
pci_release_regions(chip->pci);
#define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2"
#define DRIVER_NAME "Maestro3"
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#ifdef CONFIG_PM_SLEEP
static int m3_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_m3 *chip = card->private_data;
int i, dsp_index;
for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
chip->suspend_mem[dsp_index++] =
snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int m3_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_m3 *chip = card->private_data;
int i, dsp_index;
if (chip->suspend_mem == NULL)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
/* first lets just bring everything back. .*/
snd_m3_outw(chip, 0, 0x54);
snd_m3_outw(chip, 0, 0x56);
}
/* release the i/o ports */
- for (i = 0; i < 2; i++) {
- if (mgr->mem[i].virt)
- iounmap(mgr->mem[i].virt);
- }
+ for (i = 0; i < 2; ++i)
+ iounmap(mgr->mem[i].virt);
+
pci_release_regions(mgr->pci);
/* free flowarray */
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/pci.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <sound/core.h>
#include "mixart.h"
#include "mixart_hwdep.h"
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include "mixart.h"
#include "mixart_mixer.h"
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int nm256_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct nm256 *chip = card->private_data;
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
chip->coeffs_current = 0;
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int nm256_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct nm256 *chip = card->private_data;
int i;
/* Perform a full reset on the hardware */
chip->in_resume = 1;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_nm256_init_chip(chip);
/* restore ac97 */
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->cport)
- iounmap(chip->cport);
- if (chip->buffer)
- iounmap(chip->buffer);
+ iounmap(chip->cport);
+ iounmap(chip->buffer);
release_and_free_resource(chip->res_cport);
release_and_free_resource(chip->res_buffer);
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
+snd-se6x-objs := se6x.o
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
+obj-$(CONFIG_SND_SE6X) += snd-se6x.o
obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
#define CAPTURE_1_FROM_SPDIF 0x0080
#define CAPTURE_2_FROM_I2S_2 0x0100
#define CAPTURE_2_FROM_AC97_1 0x0200
- /* CAPTURE_3_FROM_I2S_3 not implemented */
+#define CAPTURE_3_FROM_I2S_3 0x0400
#define MIDI_OUTPUT 0x0800
#define MIDI_INPUT 0x1000
#define AC97_CD_INPUT 0x2000
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/export.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/mpu401.h>
-#include <asm/io.h>
#include "oxygen.h"
u8 oxygen_read8(struct oxygen *chip, unsigned int reg)
static void configure_pcie_bridge(struct pci_dev *pci)
{
- enum { PEX811X, PI7C9X110 };
+ enum { PEX811X, PI7C9X110, XIO2001 };
static const struct pci_device_id bridge_ids[] = {
{ PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
{ PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
{ PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+ { PCI_VDEVICE(TI, 0x8240), .driver_data = XIO2001 },
{ }
};
struct pci_dev *bridge;
tmp |= 1; /* park the PCI arbiter to the sound chip */
pci_write_config_dword(bridge, 0x40, tmp);
break;
+
+ case XIO2001: /* Texas Instruments XIO2001 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0xe8, &tmp);
+ tmp &= ~0xf; /* request length limit: 64 bytes */
+ tmp &= ~(0xf << 8);
+ tmp |= 1 << 8; /* request count limit: one buffer */
+ pci_write_config_dword(bridge, 0xe8, tmp);
+ break;
}
}
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
OXYGEN_I2S_MASTER |
OXYGEN_I2S_MUTE_MCLK);
- oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
- OXYGEN_I2S_MASTER |
- OXYGEN_I2S_MUTE_MCLK);
+ if (chip->model.device_config & CAPTURE_3_FROM_I2S_3)
+ oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+ OXYGEN_RATE_48000 |
+ chip->model.adc_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
+ else
+ oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE |
OXYGEN_SPDIF_LOOPBACK);
#ifdef CONFIG_PM_SLEEP
static int oxygen_pci_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct oxygen *chip = card->private_data;
unsigned int i, saved_interrupt_mask;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
for (i = 0; i < PCM_COUNT; ++i)
- if (chip->streams[i])
- snd_pcm_suspend(chip->streams[i]);
+ snd_pcm_suspend(chip->streams[i]);
if (chip->model.suspend)
chip->model.suspend(chip);
flush_work(&chip->spdif_input_bits_work);
flush_work(&chip->gpio_work);
chip->interrupt_mask = saved_interrupt_mask;
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int oxygen_pci_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct oxygen *chip = card->private_data;
unsigned int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "cannot reenable device");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
for (i = 0; i < OXYGEN_IO_SIZE; ++i)
.get = upmix_get,
.put = upmix_put,
},
+};
+
+static const struct snd_kcontrol_new spdif_output_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
},
},
},
+ {
+ .pcm_dev = CAPTURE_3_FROM_I2S_3,
+ .controls = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Input Monitor Playback Switch",
+ .index = 2,
+ .info = snd_ctl_boolean_mono_info,
+ .get = monitor_get,
+ .put = monitor_put,
+ .private_value = OXYGEN_ADC_MONITOR_C,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Input Monitor Playback Volume",
+ .index = 2,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = monitor_volume_info,
+ .get = monitor_get,
+ .put = monitor_put,
+ .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL
+ | (1 << 8),
+ .tlv = { .p = monitor_db_scale, },
+ },
+ },
+ },
{
.pcm_dev = CAPTURE_1_FROM_SPDIF,
.controls = {
err = add_controls(chip, controls, ARRAY_SIZE(controls));
if (err < 0)
return err;
+ if (chip->model.device_config & PLAYBACK_1_TO_SPDIF) {
+ err = add_controls(chip, spdif_output_controls,
+ ARRAY_SIZE(spdif_output_controls));
+ if (err < 0)
+ return err;
+ }
if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
err = add_controls(chip, spdif_input_controls,
ARRAY_SIZE(spdif_input_controls));
runtime->hw = *oxygen_hardware[channel];
switch (channel) {
case PCM_C:
- runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_64000);
- runtime->hw.rate_min = 44100;
+ if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
+ runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_64000);
+ runtime->hw.rate_min = 44100;
+ }
/* fall through */
case PCM_A:
case PCM_B:
struct snd_pcm_hw_params *hw_params)
{
struct oxygen *chip = snd_pcm_substream_chip(substream);
+ bool is_spdif;
int err;
err = oxygen_hw_params(substream, hw_params);
if (err < 0)
return err;
+ is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF;
+
spin_lock_irq(&chip->reg_lock);
oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT,
OXYGEN_REC_FORMAT_C_MASK);
+ if (!is_spdif)
+ oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT,
+ oxygen_rate(hw_params) |
+ chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_B, hw_params) |
+ oxygen_i2s_bits(hw_params),
+ OXYGEN_I2S_RATE_MASK |
+ OXYGEN_I2S_FORMAT_MASK |
+ OXYGEN_I2S_MCLK_MASK |
+ OXYGEN_I2S_BITS_MASK);
spin_unlock_irq(&chip->reg_lock);
+
+ if (!is_spdif) {
+ mutex_lock(&chip->mutex);
+ chip->model.set_adc_params(chip, hw_params);
+ mutex_unlock(&chip->mutex);
+ }
return 0;
}
.pointer = oxygen_pointer,
};
-static void oxygen_pcm_free(struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
int oxygen_pcm_init(struct oxygen *chip)
{
struct snd_pcm *pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_b_ops);
pcm->private_data = chip;
- pcm->private_free = oxygen_pcm_free;
strcpy(pcm->name, "Multichannel");
if (outs)
snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_c_ops);
pcm->private_data = chip;
- pcm->private_free = oxygen_pcm_free;
strcpy(pcm->name, "Digital");
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_b_ops);
pcm->private_data = chip;
- pcm->private_free = oxygen_pcm_free;
strcpy(pcm->name, outs ? "Front Panel" : "Analog 2");
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
DEFAULT_BUFFER_BYTES,
BUFFER_BYTES_MAX);
}
+
+ ins = !!(chip->model.device_config & CAPTURE_3_FROM_I2S_3);
+ if (ins) {
+ err = snd_pcm_new(chip->card, "Analog3", 3, 0, ins, &pcm);
+ if (err < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &oxygen_rec_c_ops);
+ oxygen_write8_masked(chip, OXYGEN_REC_ROUTING,
+ OXYGEN_REC_C_ROUTE_I2S_ADC_3,
+ OXYGEN_REC_C_ROUTE_MASK);
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Analog 3");
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(chip->pci),
+ DEFAULT_BUFFER_BYTES,
+ BUFFER_BYTES_MAX);
+ }
return 0;
}
--- /dev/null
+/*
+ * C-Media CMI8787 driver for the Studio Evolution SE6X
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * CMI8787:
+ *
+ * SPI -> microcontroller (not actually used)
+ * GPIO 0 -> do.
+ * GPIO 2 -> do.
+ *
+ * DAC0 -> both PCM1792A (L+R, each in mono mode)
+ * ADC1 <- 1st PCM1804
+ * ADC2 <- 2nd PCM1804
+ * ADC3 <- 3rd PCM1804
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include "oxygen.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("Studio Evolution SE6X driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{Studio Evolution,SE6X}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+
+static const struct pci_device_id se6x_ids[] = {
+ { OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, se6x_ids);
+
+static void se6x_init(struct oxygen *chip)
+{
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 0x005);
+
+ snd_component_add(chip->card, "PCM1792A");
+ snd_component_add(chip->card, "PCM1804");
+}
+
+static int se6x_control_filter(struct snd_kcontrol_new *template)
+{
+ /* no DAC volume/mute */
+ if (!strncmp(template->name, "Master Playback ", 16))
+ return 1;
+ return 0;
+}
+
+static void se6x_cleanup(struct oxygen *chip)
+{
+}
+
+static void set_pcm1792a_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ /* nothing to do (the microcontroller monitors DAC_LRCK) */
+}
+
+static void set_pcm1804_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+}
+
+static unsigned int se6x_adjust_dac_routing(struct oxygen *chip,
+ unsigned int play_routing)
+{
+ /* route the same stereo pair to DAC0 and DAC1 */
+ return ( play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+ ((play_routing << 2) & OXYGEN_PLAY_DAC1_SOURCE_MASK);
+}
+
+static const struct oxygen_model model_se6x = {
+ .shortname = "Studio Evolution SE6X",
+ .longname = "C-Media Oxygen HD Audio",
+ .chip = "CMI8787",
+ .init = se6x_init,
+ .control_filter = se6x_control_filter,
+ .cleanup = se6x_cleanup,
+ .set_dac_params = set_pcm1792a_params,
+ .set_adc_params = set_pcm1804_params,
+ .adjust_dac_routing = se6x_adjust_dac_routing,
+ .device_config = PLAYBACK_0_TO_I2S |
+ CAPTURE_0_FROM_I2S_1 |
+ CAPTURE_2_FROM_I2S_2 |
+ CAPTURE_3_FROM_I2S_3,
+ .dac_channels_pcm = 2,
+ .function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_I2S,
+};
+
+static int se6x_get_model(struct oxygen *chip,
+ const struct pci_device_id *pci_id)
+{
+ chip->model = model_se6x;
+ return 0;
+}
+
+static int se6x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ static int dev;
+ int err;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ ++dev;
+ return -ENOENT;
+ }
+ err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
+ se6x_ids, se6x_get_model);
+ if (err >= 0)
+ ++dev;
+ return err;
+}
+
+static struct pci_driver se6x_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = se6x_ids,
+ .probe = se6x_probe,
+ .remove = oxygen_pci_remove,
+#ifdef CONFIG_PM_SLEEP
+ .driver = {
+ .pm = &oxygen_pci_pm,
+ },
+#endif
+ .shutdown = oxygen_pci_shutdown,
+};
+
+module_pci_driver(se6x_driver);
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include "pcxhr.h"
#include "pcxhr_mixer.h"
#include <linux/firmware.h>
#include <linux/pci.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/hwdep.h>
#include "pcxhr.h"
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
#ifdef CONFIG_PM_SLEEP
static int riptide_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_riptide *chip = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int riptide_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_riptide *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "riptide: pci_enable_device failed, "
- "disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
snd_riptide_initialize(chip);
snd_ac97_resume(chip->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
.pointer = snd_riptide_pointer,
};
-static int
-snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
+static int snd_riptide_pcm(struct snd_riptide *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err =
snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1,
&pcm)) < 0)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
64 * 1024, 128 * 1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
if (err < 0)
goto error;
card->private_data = chip;
- err = snd_riptide_pcm(chip, 0, NULL);
+ err = snd_riptide_pcm(chip, 0);
if (err < 0)
goto error;
err = snd_riptide_mixer(chip);
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
}
}
-static int snd_rme32_setformat(struct rme32 * rme32, int format)
+static int snd_rme32_setformat(struct rme32 *rme32, snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
/* note, two last pcis should be equal, it is not a bug */
MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>");
}
static int
-snd_rme96_playback_setformat(struct rme96 *rme96,
- int format)
+snd_rme96_playback_setformat(struct rme96 *rme96, snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
}
static int
-snd_rme96_capture_setformat(struct rme96 *rme96,
- int format)
+snd_rme96_capture_setformat(struct rme96 *rme96, snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
static int rme96_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct rme96 *rme96 = card->private_data;
/* disable the DAC */
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
-
- pci_disable_device(pci);
- pci_save_state(pci);
-
return 0;
}
static int rme96_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct rme96 *rme96 = card->private_data;
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
-
/* reset playback and record buffer pointers */
writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
+ rme96->playback_pointer);
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/vmalloc.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <asm/byteorder.h>
#include <asm/current.h>
-#include <asm/io.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
leaving istimer wherever it was set before.
*/
- if (hmidi->istimer) {
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
- }
+ if (hmidi->istimer)
+ mod_timer(&hmidi->timer, 1 + jiffies);
spin_unlock_irqrestore (&hmidi->lock, flags);
}
spin_lock_irqsave (&hmidi->lock, flags);
if (up) {
if (!hmidi->istimer) {
- init_timer(&hmidi->timer);
- hmidi->timer.function = snd_hdsp_midi_output_timer;
- hmidi->timer.data = (unsigned long) hmidi;
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
+ setup_timer(&hmidi->timer, snd_hdsp_midi_output_timer,
+ (unsigned long) hmidi);
+ mod_timer(&hmidi->timer, 1 + jiffies);
hmidi->istimer++;
}
} else {
release_firmware(hdsp->firmware);
vfree(hdsp->fw_uploaded);
-
- if (hdsp->iobase)
- iounmap(hdsp->iobase);
+ iounmap(hdsp->iobase);
if (hdsp->port)
pci_release_regions(hdsp->pci);
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/math64.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
leaving istimer wherever it was set before.
*/
- if (hmidi->istimer) {
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
- }
+ if (hmidi->istimer)
+ mod_timer(&hmidi->timer, 1 + jiffies);
spin_unlock_irqrestore (&hmidi->lock, flags);
}
spin_lock_irqsave (&hmidi->lock, flags);
if (up) {
if (!hmidi->istimer) {
- init_timer(&hmidi->timer);
- hmidi->timer.function = snd_hdspm_midi_output_timer;
- hmidi->timer.data = (unsigned long) hmidi;
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
+ setup_timer(&hmidi->timer, snd_hdspm_midi_output_timer,
+ (unsigned long) hmidi);
+ mod_timer(&hmidi->timer, 1 + jiffies);
hmidi->istimer++;
}
} else {
free_irq(hdspm->irq, (void *) hdspm);
kfree(hdspm->mixer);
-
- if (hdspm->iobase)
- iounmap(hdspm->iobase);
+ iounmap(hdspm->iobase);
if (hdspm->port)
pci_release_regions(hdspm->pci);
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <asm/current.h>
-#include <asm/io.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
if (rme9652->irq >= 0)
free_irq(rme9652->irq, (void *)rme9652);
- if (rme9652->iobase)
- iounmap(rme9652->iobase);
+ iounmap(rme9652->iobase);
if (rme9652->port)
pci_release_regions(rme9652->pci);
if (sis->irq >= 0)
free_irq(sis->irq, sis);
- if (sis->ioaddr)
- iounmap(sis->ioaddr);
-
+ iounmap(sis->ioaddr);
pci_release_regions(sis->pci);
pci_disable_device(sis->pci);
-
sis_free_suspend(sis);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int sis_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct sis7019 *sis = card->private_data;
void __iomem *ioaddr = sis->ioaddr;
ioaddr += 4096;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
void __iomem *ioaddr = sis->ioaddr;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- dev_err(&pci->dev, "unable to re-enable device\n");
- goto error;
- }
-
if (sis_chip_init(sis)) {
dev_err(&pci->dev, "unable to re-init controller\n");
goto error;
memset(sis->suspend_state[0], 0, 4096);
sis->irq = pci->irq;
- pci_set_master(pci);
if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT)
snd_ac97_resume(sis->ac97[0]);
#include <linux/gameport.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/opl3.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("S3 SonicVibes PCI");
MODULE_LICENSE("GPL");
.pointer = snd_sonicvibes_capture_pointer,
};
-static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
- struct snd_pcm **rpcm)
+static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device)
{
struct snd_pcm *pcm;
int err;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(sonic->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
(unsigned long long)pci_resource_start(pci, 1),
sonic->irq);
- if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) {
+ if ((err = snd_sonicvibes_pcm(sonic, 0)) < 0) {
snd_card_free(card);
return err;
}
sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d",
card->shortname, trident->port, trident->irq);
- if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) {
+ if ((err = snd_trident_pcm(trident, pcm_dev++)) < 0) {
snd_card_free(card);
return err;
}
switch (trident->device) {
case TRIDENT_DEVICE_ID_DX:
case TRIDENT_DEVICE_ID_NX:
- if ((err = snd_trident_foldback_pcm(trident, pcm_dev++, NULL)) < 0) {
+ if ((err = snd_trident_foldback_pcm(trident, pcm_dev++)) < 0) {
snd_card_free(card);
return err;
}
break;
}
if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
- if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) {
+ if ((err = snd_trident_spdif_pcm(trident, pcm_dev++)) < 0) {
snd_card_free(card);
return err;
}
struct snd_trident ** rtrident);
int snd_trident_create_gameport(struct snd_trident *trident);
-int snd_trident_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
-int snd_trident_foldback_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
-int snd_trident_spdif_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
+int snd_trident_pcm(struct snd_trident *trident, int device);
+int snd_trident_foldback_pcm(struct snd_trident *trident, int device);
+int snd_trident_spdif_pcm(struct snd_trident *trident, int device);
int snd_trident_attach_synthesizer(struct snd_trident * trident);
struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type,
int client, int port);
#include <linux/gameport.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include "trident.h"
#include <sound/asoundef.h>
-#include <asm/io.h>
-
static int snd_trident_pcm_mixer_build(struct snd_trident *trident,
struct snd_trident_voice * voice,
struct snd_pcm_substream *substream);
---------------------------------------------------------------------------*/
-int snd_trident_pcm(struct snd_trident *trident,
- int device, struct snd_pcm **rpcm)
+int snd_trident_pcm(struct snd_trident *trident, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm)) < 0)
return err;
snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
}
- if (rpcm)
- *rpcm = pcm;
return 0;
}
---------------------------------------------------------------------------*/
-int snd_trident_foldback_pcm(struct snd_trident *trident,
- int device, struct snd_pcm **rpcm)
+int snd_trident_foldback_pcm(struct snd_trident *trident, int device)
{
struct snd_pcm *foldback;
int err;
int num_chan = 3;
struct snd_pcm_substream *substream;
- if (rpcm)
- *rpcm = NULL;
if (trident->device == TRIDENT_DEVICE_ID_NX)
num_chan = 4;
if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback)) < 0)
snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = foldback;
return 0;
}
---------------------------------------------------------------------------*/
-int snd_trident_spdif_pcm(struct snd_trident *trident,
- int device, struct snd_pcm **rpcm)
+int snd_trident_spdif_pcm(struct snd_trident *trident, int device)
{
struct snd_pcm *spdif;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif)) < 0)
return err;
snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = spdif;
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int snd_trident_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_trident *trident = card->private_data;
snd_ac97_suspend(trident->ac97);
snd_ac97_suspend(trident->ac97_sec);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_trident_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_trident *trident = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
switch (trident->device) {
case TRIDENT_DEVICE_ID_DX:
snd_trident_4d_dx_init(trident);
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/pci.h>
#include <linux/time.h>
#include <linux/mutex.h>
* - Optimize position calculation for the 823x chips.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int snd_via82xx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx *chip = card->private_data;
int i;
chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_via82xx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_via82xx_chip_init(chip);
if (chip->chip_type == TYPE_VIA686) {
* modems.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
*/
static int snd_via82xx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx_modem *chip = card->private_data;
int i;
snd_via82xx_channel_reset(chip, &chip->devs[i]);
synchronize_irq(chip->irq);
snd_ac97_suspend(chip->ac97);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_via82xx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx_modem *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_via82xx_chip_init(chip);
snd_ac97_resume(chip->ac97);
#ifdef CONFIG_PM_SLEEP
static int snd_vx222_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_vx222 *vx = card->private_data;
- int err;
- err = snd_vx_suspend(&vx->core);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
- return err;
+ return snd_vx_suspend(&vx->core);
}
static int snd_vx222_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_vx222 *vx = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
return snd_vx_resume(&vx->core);
}
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>
-#include <asm/io.h>
#include "vx222.h"
card->shortname,
chip->reg_area_phys,
chip->irq);
- if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_ymfpci_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_ymfpci_pcm_spdif(chip, 1, NULL)) < 0) {
+ if ((err = snd_ymfpci_pcm_spdif(chip, 1)) < 0) {
snd_card_free(card);
return err;
}
return err;
}
if (chip->ac97->ext_id & AC97_EI_SDAC) {
- err = snd_ymfpci_pcm_4ch(chip, 2, NULL);
+ err = snd_ymfpci_pcm_4ch(chip, 2);
if (err < 0) {
snd_card_free(card);
return err;
}
- err = snd_ymfpci_pcm2(chip, 3, NULL);
+ err = snd_ymfpci_pcm2(chip, 3);
if (err < 0) {
snd_card_free(card);
return err;
extern const struct dev_pm_ops snd_ymfpci_pm;
-int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
+int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device);
int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/asoundef.h>
#include <sound/mpu401.h>
-#include <asm/io.h>
#include <asm/byteorder.h>
/*
.pointer = snd_ymfpci_capture_pointer,
};
-int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
+int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0)
return err;
pcm->private_data = chip;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps, 2, 0, NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
}
static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
.pointer = snd_ymfpci_capture_pointer,
};
-int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
+int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0)
return err;
pcm->private_data = chip;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
.pointer = snd_ymfpci_playback_pointer,
};
-int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device,
- struct snd_pcm **rpcm)
+int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm)) < 0)
return err;
pcm->private_data = chip;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
{ }
};
-int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device,
- struct snd_pcm **rpcm)
+int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm)) < 0)
return err;
pcm->private_data = chip;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
surround_map, 2, 0, NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
}
static int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
release_and_free_resource(chip->mpu_res);
release_and_free_resource(chip->fm_res);
snd_ymfpci_free_gameport(chip);
- if (chip->reg_area_virt)
- iounmap(chip->reg_area_virt);
+ iounmap(chip->reg_area_virt);
if (chip->work_ptr.area)
snd_dma_free_pages(&chip->work_ptr);
static int snd_ymfpci_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ymfpci *chip = card->private_data;
unsigned int i;
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
snd_ymfpci_disable_dsp(chip);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
struct snd_ymfpci *chip = card->private_data;
unsigned int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
snd_ymfpci_aclink_reset(pci);
snd_ymfpci_codec_ready(chip, 0);
snd_ymfpci_download_image(chip);
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/nvram.h>
#include <linux/init.h>
#include <linux/delay.h>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/slab.h>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <sound/core.h>
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/delay.h>
snd_pmac_dbdma_free(chip, &chip->capture.cmd);
snd_pmac_dbdma_free(chip, &chip->extra_dma);
snd_pmac_dbdma_free(chip, &emergency_dbdma);
- if (chip->macio_base)
- iounmap(chip->macio_base);
- if (chip->latch_base)
- iounmap(chip->latch_base);
- if (chip->awacs)
- iounmap(chip->awacs);
- if (chip->playback.dma)
- iounmap(chip->playback.dma);
- if (chip->capture.dma)
- iounmap(chip->capture.dma);
+ iounmap(chip->macio_base);
+ iounmap(chip->latch_base);
+ iounmap(chip->awacs);
+ iounmap(chip->playback.dma);
+ iounmap(chip->capture.dma);
if (chip->node) {
int i;
if (!the_card.null_buffer_start_vaddr) {
pr_info("%s: nullbuffer alloc failed\n", __func__);
ret = -ENOMEM;
- goto clean_preallocate;
+ goto clean_card;
}
pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__,
the_card.null_buffer_start_vaddr,
PAGE_SIZE,
the_card.null_buffer_start_vaddr,
the_card.null_buffer_start_dma_addr);
-clean_preallocate:
- snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
clean_card:
snd_card_free(the_card.card);
clean_irq:
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/of_irq.h>
+#include <linux/io.h>
#include <sound/core.h>
-#include <asm/io.h>
#include <asm/irq.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/info.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <mach/sysasic.h>
#include "aica.h"
mod_timer(&dreamcastcard->timer, jiffies + 4);
return;
}
- init_timer(&(dreamcastcard->timer));
- dreamcastcard->timer.data = (unsigned long) substream;
- dreamcastcard->timer.function = aica_period_elapsed;
- dreamcastcard->timer.expires = jiffies + 4;
- add_timer(&(dreamcastcard->timer));
+ setup_timer(&dreamcastcard->timer, aica_period_elapsed,
+ (unsigned long) substream);
+ mod_timer(&dreamcastcard->timer, jiffies + 4);
}
static int snd_aicapcm_pcm_open(struct snd_pcm_substream
static const struct i2c_device_id pcm512x_i2c_id[] = {
{ "pcm5121", },
{ "pcm5122", },
+ { "pcm5141", },
+ { "pcm5142", },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5121", },
{ .compatible = "ti,pcm5122", },
+ { .compatible = "ti,pcm5141", },
+ { .compatible = "ti,pcm5142", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
static const struct spi_device_id pcm512x_spi_id[] = {
{ "pcm5121", },
{ "pcm5122", },
+ { "pcm5141", },
+ { "pcm5142", },
{ },
};
MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5121", },
{ .compatible = "ti,pcm5122", },
+ { .compatible = "ti,pcm5141", },
+ { .compatible = "ti,pcm5142", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
+#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src)
return 0;
+ if (rt5670->pdata.jd_mode) {
+ if (clk_id == RT5670_SCLK_S_PLL1)
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+ else
+ snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+ snd_soc_dapm_sync(&codec->dapm);
+ }
switch (clk_id) {
case RT5670_SCLK_S_MCLK:
reg_val |= RT5670_SCLK_SRC_MCLK;
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
#endif
+static const struct dmi_system_id dmi_platform_intel_braswell[] = {
+ {
+ .ident = "Intel Braswell",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
+ },
+ },
+ {}
+};
+
static int rt5670_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
if (pdata)
rt5670->pdata = *pdata;
+ if (dmi_check_system(dmi_platform_intel_braswell)) {
+ rt5670->pdata.dmic_en = true;
+ rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+ rt5670->pdata.jd_mode = 1;
+ }
+
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
if (IS_ERR(rt5670->regmap)) {
ret = PTR_ERR(rt5670->regmap);
}
if (rt5670->pdata.jd_mode) {
+ regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK,
+ RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK);
+ rt5670->sysclk = 0;
+ rt5670->sysclk_src = RT5670_SCLK_S_RCCLK;
regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
RT5670_PWR_MB, RT5670_PWR_MB);
regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2,
}
+ pm_runtime_enable(&i2c->dev);
+ pm_request_idle(&i2c->dev);
+
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670,
rt5670_dai, ARRAY_SIZE(rt5670_dai));
if (ret < 0)
goto err;
+ pm_runtime_put(&i2c->dev);
+
return 0;
err:
+ pm_runtime_disable(&i2c->dev);
+
return ret;
}
static int rt5670_i2c_remove(struct i2c_client *i2c)
{
+ pm_runtime_disable(&i2c->dev);
snd_soc_unregister_codec(&i2c->dev);
return 0;
return 0;
}
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg, shift, val;
+
+ if (source->reg == RT5677_ASRC_1) {
+ switch (source->shift) {
+ case 12:
+ reg = RT5677_ASRC_4;
+ shift = 0;
+ break;
+ case 13:
+ reg = RT5677_ASRC_4;
+ shift = 4;
+ break;
+ case 14:
+ reg = RT5677_ASRC_4;
+ shift = 8;
+ break;
+ case 15:
+ reg = RT5677_ASRC_4;
+ shift = 12;
+ break;
+ default:
+ return 0;
+ }
+ } else {
+ switch (source->shift) {
+ case 0:
+ reg = RT5677_ASRC_6;
+ shift = 8;
+ break;
+ case 1:
+ reg = RT5677_ASRC_6;
+ shift = 12;
+ break;
+ case 2:
+ reg = RT5677_ASRC_5;
+ shift = 0;
+ break;
+ case 3:
+ reg = RT5677_ASRC_5;
+ shift = 4;
+ break;
+ case 4:
+ reg = RT5677_ASRC_5;
+ shift = 8;
+ break;
+ case 5:
+ reg = RT5677_ASRC_5;
+ shift = 12;
+ break;
+ case 12:
+ reg = RT5677_ASRC_3;
+ shift = 0;
+ break;
+ case 13:
+ reg = RT5677_ASRC_3;
+ shift = 4;
+ break;
+ case 14:
+ reg = RT5677_ASRC_3;
+ shift = 12;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+ switch (val) {
+ case 1 ... 6:
+ return 1;
+ default:
+ return 0;
+ }
+
+}
+
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+ if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384)
+ return 1;
+
+ return 0;
+}
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
0, rt5677_set_pll2_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
+ /* ASRC */
+ SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5677_ASRC_1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5677_ASRC_1, 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5677_ASRC_1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S4 ASRC", 1, RT5677_ASRC_1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5677_ASRC_2, 14, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO2 L ASRC", 1, RT5677_ASRC_2, 13, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO2 R ASRC", 1, RT5677_ASRC_2, 12, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO3 L ASRC", 1, RT5677_ASRC_1, 15, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO3 R ASRC", 1, RT5677_ASRC_1, 14, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO4 L ASRC", 1, RT5677_ASRC_1, 13, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO4 R ASRC", 1, RT5677_ASRC_1, 12, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5677_ASRC_2, 11, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5677_ASRC_2, 10, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO3 ASRC", 1, RT5677_ASRC_2, 9, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO4 ASRC", 1, RT5677_ASRC_2, 8, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5677_ASRC_2, 7, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5677_ASRC_2, 6, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5677_ASRC_2, 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5677_ASRC_2, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO3 ASRC", 1, RT5677_ASRC_2, 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO4 ASRC", 1, RT5677_ASRC_2, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5677_ASRC_2, 1, 0, NULL,
+ 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5677_ASRC_2, 0, 0, NULL,
+ 0),
+
/* Input Side */
/* micbias */
SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5677_PWR_ANLG2, RT5677_PWR_MB1_BIT,
/* DAC Mixer */
SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2,
RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("dac mono left filter", RT5677_PWR_DIG2,
+ SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2,
RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("dac mono right filter", RT5677_PWR_DIG2,
+ SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2,
RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2,
+ RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2,
+ RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2,
+ RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2,
+ RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0),
SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)),
};
static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
+ { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
+ { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
+ { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
+ { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
+ { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
+ { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+ { "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+ { "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
+ { "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
+ { "I2S4", NULL, "I2S4 ASRC", can_use_asrc},
+
+ { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+ { "dac mono2 left filter", NULL, "DAC MONO2 L ASRC", is_using_asrc },
+ { "dac mono2 right filter", NULL, "DAC MONO2 R ASRC", is_using_asrc },
+ { "dac mono3 left filter", NULL, "DAC MONO3 L ASRC", is_using_asrc },
+ { "dac mono3 right filter", NULL, "DAC MONO3 R ASRC", is_using_asrc },
+ { "dac mono4 left filter", NULL, "DAC MONO4 L ASRC", is_using_asrc },
+ { "dac mono4 right filter", NULL, "DAC MONO4 R ASRC", is_using_asrc },
+ { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+ { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
+ { "adc stereo3 filter", NULL, "ADC STO3 ASRC", is_using_asrc },
+ { "adc stereo4 filter", NULL, "ADC STO4 ASRC", is_using_asrc },
+ { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+ { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+
{ "DMIC1", NULL, "DMIC L1" },
{ "DMIC1", NULL, "DMIC R1" },
{ "DMIC2", NULL, "DMIC L2" },
{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
- { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" },
{ "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" },
- { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
{ "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
{ "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" },
{ "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" },
{ "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" },
- { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
{ "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" },
{ "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" },
{ "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" },
{ "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" },
- { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
{ "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" },
{ "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" },
{ "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" },
{ "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" },
- { "DAC1 MIXL", NULL, "dac stereo1 filter" },
{ "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" },
{ "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" },
- { "DAC1 MIXR", NULL, "dac stereo1 filter" },
{ "DAC1 FS", NULL, "DAC1 MIXL" },
{ "DAC1 FS", NULL, "DAC1 MIXR" },
{ "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
{ "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" },
{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+ { "dac stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" },
{ "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
{ "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" },
{ "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" },
- { "Mono DAC MIXL", NULL, "dac mono left filter" },
+ { "Mono DAC MIXL", NULL, "dac mono2 left filter" },
+ { "dac mono2 left filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" },
{ "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" },
{ "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
{ "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" },
- { "Mono DAC MIXR", NULL, "dac mono right filter" },
+ { "Mono DAC MIXR", NULL, "dac mono2 right filter" },
+ { "dac mono2 right filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
{ "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
{ "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" },
{ "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" },
+ { "DD1 MIXL", NULL, "dac mono3 left filter" },
+ { "dac mono3 left filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
{ "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
{ "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" },
{ "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" },
+ { "DD1 MIXR", NULL, "dac mono3 right filter" },
+ { "dac mono3 right filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
{ "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
{ "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" },
{ "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" },
+ { "DD2 MIXL", NULL, "dac mono4 left filter" },
+ { "dac mono4 left filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
{ "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
{ "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" },
{ "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" },
+ { "DD2 MIXR", NULL, "dac mono4 right filter" },
+ { "dac mono4 right filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Stereo DAC MIX", NULL, "Stereo DAC MIXL" },
{ "Stereo DAC MIX", NULL, "Stereo DAC MIXR" },
{ "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" },
{ "DAC 1", NULL, "DAC12 SRC Mux" },
- { "DAC 1", NULL, "PLL1", is_sys_clk_from_pll },
{ "DAC 2", NULL, "DAC12 SRC Mux" },
- { "DAC 2", NULL, "PLL1", is_sys_clk_from_pll },
{ "DAC 3", NULL, "DAC3 SRC Mux" },
- { "DAC 3", NULL, "PLL1", is_sys_clk_from_pll },
{ "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" },
{ "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" },
SND_SOC_DAPM_OUTPUT("ROUT2"),
SND_SOC_DAPM_OUTPUT("MONO1"),
SND_SOC_DAPM_OUTPUT("OUT3"),
- SND_SOC_DAPM_OUTPUT("VREF"),
+ SND_SOC_DAPM_VMID("VREF"),
SND_SOC_DAPM_INPUT("LINPUT1"),
SND_SOC_DAPM_INPUT("LINPUT2"),
#define dw_i2s_resume NULL
#endif
+static void dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
+ struct snd_soc_dai_driver *dw_i2s_dai,
+ struct resource *res,
+ const struct i2s_platform_data *pdata)
+{
+ /* Set DMA slaves info */
+
+ dev->play_dma_data.data = pdata->play_dma_data;
+ dev->capture_dma_data.data = pdata->capture_dma_data;
+ dev->play_dma_data.addr = res->start + I2S_TXDMA;
+ dev->capture_dma_data.addr = res->start + I2S_RXDMA;
+ dev->play_dma_data.max_burst = 16;
+ dev->capture_dma_data.max_burst = 16;
+ dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ dev->play_dma_data.filter = pdata->filter;
+ dev->capture_dma_data.filter = pdata->filter;
+
+ if (pdata->cap & DWC_I2S_PLAY) {
+ dev_dbg(dev->dev, " designware: play supported\n");
+ dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
+ dw_i2s_dai->playback.channels_max = pdata->channel;
+ dw_i2s_dai->playback.formats = pdata->snd_fmts;
+ dw_i2s_dai->playback.rates = pdata->snd_rates;
+ }
+
+ if (pdata->cap & DWC_I2S_RECORD) {
+ dev_dbg(dev->dev, "designware: record supported\n");
+ dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
+ dw_i2s_dai->capture.channels_max = pdata->channel;
+ dw_i2s_dai->capture.formats = pdata->snd_fmts;
+ dw_i2s_dai->capture.rates = pdata->snd_rates;
+ }
+}
+
static int dw_i2s_probe(struct platform_device *pdev)
{
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
struct dw_i2s_dev *dev;
struct resource *res;
int ret;
- unsigned int cap;
struct snd_soc_dai_driver *dw_i2s_dai;
if (!pdata) {
}
dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
- if (!dw_i2s_dai) {
- dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
+ if (!dw_i2s_dai)
return -ENOMEM;
- }
dw_i2s_dai->ops = &dw_i2s_dai_ops;
dw_i2s_dai->suspend = dw_i2s_suspend;
dw_i2s_dai->resume = dw_i2s_resume;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no i2s resource defined\n");
- return -ENODEV;
- }
-
dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(dev->i2s_base)) {
- dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+ if (IS_ERR(dev->i2s_base))
return PTR_ERR(dev->i2s_base);
- }
-
- cap = pdata->cap;
- dev->capability = cap;
- dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
-
- /* Set DMA slaves info */
- dev->play_dma_data.data = pdata->play_dma_data;
- dev->capture_dma_data.data = pdata->capture_dma_data;
- dev->play_dma_data.addr = res->start + I2S_TXDMA;
- dev->capture_dma_data.addr = res->start + I2S_RXDMA;
- dev->play_dma_data.max_burst = 16;
- dev->capture_dma_data.max_burst = 16;
- dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- dev->play_dma_data.filter = pdata->filter;
- dev->capture_dma_data.filter = pdata->filter;
+ dev->dev = &pdev->dev;
+ dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
+ dev->capability = pdata->cap;
+ dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
if (ret < 0)
goto err_clk_put;
- if (cap & DWC_I2S_PLAY) {
- dev_dbg(&pdev->dev, " designware: play supported\n");
- dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
- dw_i2s_dai->playback.channels_max = pdata->channel;
- dw_i2s_dai->playback.formats = pdata->snd_fmts;
- dw_i2s_dai->playback.rates = pdata->snd_rates;
- }
-
- if (cap & DWC_I2S_RECORD) {
- dev_dbg(&pdev->dev, "designware: record supported\n");
- dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
- dw_i2s_dai->capture.channels_max = pdata->channel;
- dw_i2s_dai->capture.formats = pdata->snd_fmts;
- dw_i2s_dai->capture.rates = pdata->snd_rates;
- }
-
- dev->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, dev);
ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
dw_i2s_dai, 1);
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \
I2C_DESIGNWARE_PLATFORM
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM
select SND_SOC_INTEL_HASWELL
select SND_COMPRESS_OFFLOAD
static struct platform_driver snd_byt_mc_driver = {
.driver = {
- .owner = THIS_MODULE,
.name = "bytt100_rt5640",
.pm = &snd_soc_pm_ops,
},
static struct platform_driver snd_cht_mc_driver = {
.driver = {
- .owner = THIS_MODULE,
.name = "cht-bsw-rt5672",
.pm = &snd_soc_pm_ops,
},
sst_module->sst_fw = sst_fw;
sst_module->scratch_size = template->scratch_size;
sst_module->persistent_size = template->persistent_size;
+ sst_module->entry = template->entry;
INIT_LIST_HEAD(&sst_module->block_list);
INIT_LIST_HEAD(&sst_module->runtime_list);
return NULL;
}
-int sst_acpi_probe(struct platform_device *pdev)
+static int sst_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = 0;
* This function is called by OS when a device is unloaded
* This frees the interrupt etc
*/
-int sst_acpi_remove(struct platform_device *pdev)
+static int sst_acpi_remove(struct platform_device *pdev)
{
struct intel_sst_drv *ctx;
static struct platform_driver sst_acpi_driver = {
.driver = {
.name = "intel_sst_acpi",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(sst_acpi_ids),
.pm = &intel_sst_pm,
},
static struct platform_driver hdmi_audio_driver = {
.driver = {
.name = DRV_NAME,
- .owner = THIS_MODULE,
},
.probe = omap_hdmi_audio_probe,
.remove = omap_hdmi_audio_remove,
static struct platform_driver spitz_driver = {
.driver = {
.name = "spitz-audio",
- .owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
},
.probe = spitz_probe,
regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
+ regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
+ I2S_DMACR_TDL(16));
+ regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
+ I2S_DMACR_RDL(16));
return 0;
}
static struct platform_driver arndale_audio_driver = {
.driver = {
.name = "arndale-audio",
- .owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
},
}
}
- if (card->fully_routed)
- snd_soc_dapm_auto_nc_pins(card);
-
snd_soc_dapm_new_widgets(card);
ret = snd_card_register(card->snd_card);
switch (w->id) {
case snd_soc_dapm_input:
+ /* On a fully routed card a input is never a source */
+ if (w->dapm->card->fully_routed)
+ break;
w->is_source = 1;
list_for_each_entry(p, &w->sources, list_sink) {
if (p->source->id == snd_soc_dapm_micbias ||
}
break;
case snd_soc_dapm_output:
+ /* On a fully routed card a output is never a sink */
+ if (w->dapm->card->fully_routed)
+ break;
w->is_sink = 1;
list_for_each_entry(p, &w->sinks, list_source) {
if (p->sink->id == snd_soc_dapm_spk ||
switch (w->id) {
case snd_soc_dapm_mic:
- case snd_soc_dapm_input:
w->is_source = 1;
w->power_check = dapm_generic_check_power;
break;
+ case snd_soc_dapm_input:
+ if (!dapm->card->fully_routed)
+ w->is_source = 1;
+ w->power_check = dapm_generic_check_power;
+ break;
case snd_soc_dapm_spk:
case snd_soc_dapm_hp:
- case snd_soc_dapm_output:
w->is_sink = 1;
w->power_check = dapm_generic_check_power;
break;
+ case snd_soc_dapm_output:
+ if (!dapm->card->fully_routed)
+ w->is_sink = 1;
+ w->power_check = dapm_generic_check_power;
+ break;
case snd_soc_dapm_vmid:
case snd_soc_dapm_siggen:
w->is_source = 1;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
-/**
- * dapm_is_external_path() - Checks if a path is a external path
- * @card: The card the path belongs to
- * @path: The path to check
- *
- * Returns true if the path is either between two different DAPM contexts or
- * between two external pins of the same DAPM context. Otherwise returns
- * false.
- */
-static bool dapm_is_external_path(struct snd_soc_card *card,
- struct snd_soc_dapm_path *path)
-{
- dev_dbg(card->dev,
- "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
- path->source->name, path->source->id, path->source->dapm,
- path->sink->name, path->sink->id, path->sink->dapm);
-
- /* Connection between two different DAPM contexts */
- if (path->source->dapm != path->sink->dapm)
- return true;
-
- /* Loopback connection from external pin to external pin */
- if (path->sink->id == snd_soc_dapm_input) {
- switch (path->source->id) {
- case snd_soc_dapm_output:
- case snd_soc_dapm_micbias:
- return true;
- default:
- break;
- }
- }
-
- return false;
-}
-
-static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
- struct snd_soc_dapm_widget *w)
-{
- struct snd_soc_dapm_path *p;
-
- list_for_each_entry(p, &w->sources, list_sink) {
- if (dapm_is_external_path(card, p))
- return true;
- }
-
- list_for_each_entry(p, &w->sinks, list_source) {
- if (dapm_is_external_path(card, p))
- return true;
- }
-
- return false;
-}
-
-/**
- * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins
- * @card: The card whose pins should be processed
- *
- * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card
- * which are unused. Pins are used if they are connected externally to a
- * component, whether that be to some other device, or a loop-back connection to
- * the component itself.
- */
-void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card)
-{
- struct snd_soc_dapm_widget *w;
-
- dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm);
-
- list_for_each_entry(w, &card->widgets, list) {
- switch (w->id) {
- case snd_soc_dapm_input:
- case snd_soc_dapm_output:
- case snd_soc_dapm_micbias:
- dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n",
- w->name);
- if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
- dev_dbg(card->dev,
- "... Not in map; disabling\n");
- snd_soc_dapm_nc_pin(w->dapm, w->name);
- }
- break;
- default:
- break;
- }
- }
-}
-
/**
* snd_soc_dapm_free - free dapm resources
* @dapm: DAPM context
return symmetry;
}
-/*
- * List of sample sizes that might go over the bus for parameter
- * application. There ought to be a wildcard sample size for things
- * like the DAC/ADC resolution to use but there isn't right now.
- */
-static int sample_sizes[] = {
- 24, 32,
-};
-
static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- int ret, i;
+ int ret;
if (!bits)
return;
- for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
- if (bits >= sample_sizes[i])
- continue;
-
- ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
- sample_sizes[i], bits);
- if (ret != 0)
- dev_warn(rtd->dev,
- "ASoC: Failed to set MSB %d/%d: %d\n",
- bits, sample_sizes[i], ret);
- }
+ ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
+ if (ret != 0)
+ dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
+ bits, ret);
}
static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
codec_dai);
if (ret < 0) {
dev_err(codec_dai->dev,
- "ASoC: DAI prepare error: %d\n", ret);
+ "ASoC: codec DAI prepare error: %d\n",
+ ret);
goto out;
}
}
if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
if (ret < 0) {
- dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n",
- ret);
+ dev_err(cpu_dai->dev,
+ "ASoC: cpu DAI prepare error: %d\n", ret);
goto out;
}
}
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/control.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
emu->max_voices = 0;
emu->use_time = 0;
- init_timer(&emu->tlist);
- emu->tlist.function = snd_emux_timer_callback;
- emu->tlist.data = (unsigned long)emu;
+ setup_timer(&emu->tlist, snd_emux_timer_callback, (unsigned long)emu);
emu->timer_active = 0;
*remu = emu;
snd_emux_detach_seq_oss(emu);
#endif
snd_emux_detach_seq(emu);
-
snd_emux_delete_hwdep(emu);
-
- if (emu->sflist)
- snd_sf_free(emu->sflist);
-
+ snd_sf_free(emu->sflist);
kfree(emu->voices);
kfree(emu->name);
kfree(emu);
#include <sound/core.h>
#include <sound/hwdep.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "emux_voice.h"
#ifdef CONFIG_SND_SEQUENCER_OSS
#include <linux/export.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <sound/core.h>
#include "emux_voice.h"
#include <sound/asoundef.h>
*/
vp->state = SNDRV_EMUX_ST_PENDING;
if (! emu->timer_active) {
- emu->tlist.expires = jiffies + 1;
- add_timer(&emu->tlist);
+ mod_timer(&emu->tlist, jiffies + 1);
emu->timer_active = 1;
}
} else
}
}
if (do_again) {
- emu->tlist.expires = jiffies + 1;
- add_timer(&emu->tlist);
+ mod_timer(&emu->tlist, jiffies + 1);
emu->timer_active = 1;
} else
emu->timer_active = 0;
* of doing things so that the old sfxload utility can be used.
* Everything may change when there is an alsa way of doing things.
*/
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <sound/core.h>
To compile this driver as a module, choose M here: the module
will be called snd-bcd2000.
+source "sound/usb/line6/Kconfig"
+
endif # SND_USB
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
+obj-$(CONFIG_SND_USB_LINE6) += line6/
--- /dev/null
+config SND_USB_LINE6
+ tristate
+ select SND_RAWMIDI
+ select SND_PCM
+
+config SND_USB_POD
+ tristate "Line 6 POD USB support"
+ select SND_USB_LINE6
+ help
+ This is a driver for PODxt and other 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)
+
+config SND_USB_PODHD
+ tristate "Line 6 POD HD300/400/500 USB support"
+ select SND_USB_LINE6
+ help
+ This is a driver for POD HD300, 400 and 500 devices.
+
+config SND_USB_TONEPORT
+ tristate "TonePort GX, UX1 and UX2 USB support"
+ select SND_USB_LINE6
+ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ This is a driver for TonePort GX, UX1 and UX2 devices.
+
+config SND_USB_VARIAX
+ tristate "Variax Workbench USB support"
+ select SND_USB_LINE6
+ help
+ This is a driver for Variax Workbench device.
+
--- /dev/null
+snd-usb-line6-y := \
+ capture.o \
+ driver.o \
+ midi.o \
+ midibuf.o \
+ pcm.o \
+ playback.o
+
+snd-usb-pod-y := pod.o
+snd-usb-podhd-y := podhd.o
+snd-usb-toneport-y := toneport.o
+snd-usb-variax-y := variax.o
+
+obj-$(CONFIG_SND_USB_LINE6) += snd-usb-line6.o
+obj-$(CONFIG_SND_USB_POD) += snd-usb-pod.o
+obj-$(CONFIG_SND_USB_PODHD) += snd-usb-podhd.o
+obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o
+obj-$(CONFIG_SND_USB_VARIAX) += snd-usb-variax.o
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 "capture.h"
+#include "driver.h"
+#include "pcm.h"
+
+/*
+ Find a free URB and submit it.
+ must be called in line6pcm->in.lock context
+*/
+static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
+{
+ int index;
+ int i, urb_size;
+ int ret;
+ struct urb *urb_in;
+
+ index =
+ find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
+
+ if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+ dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+ return -EINVAL;
+ }
+
+ urb_in = line6pcm->in.urbs[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->in.buffer +
+ 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->in.active_urbs);
+ else
+ dev_err(line6pcm->line6->ifcdev,
+ "URB in #%d submission failed (%d)\n", index, ret);
+
+ return 0;
+}
+
+/*
+ Submit all currently available capture URBs.
+ must be called in line6pcm->in.lock context
+*/
+int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ ret = submit_audio_in_urb(line6pcm);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ 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->in.pos_done + frames > runtime->buffer_size) {
+ /*
+ The transferred area goes over buffer boundary,
+ copy two separate chunks.
+ */
+ int len;
+
+ len = runtime->buffer_size - line6pcm->in.pos_done;
+
+ if (len > 0) {
+ memcpy(runtime->dma_area +
+ line6pcm->in.pos_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->in.pos_done * bytes_per_frame, fbuf, fsize);
+ }
+
+ line6pcm->in.pos_done += frames;
+ if (line6pcm->in.pos_done >= runtime->buffer_size)
+ line6pcm->in.pos_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->in.bytes += length;
+ if (line6pcm->in.bytes >= line6pcm->in.period) {
+ line6pcm->in.bytes %= line6pcm->in.period;
+ spin_unlock(&line6pcm->in.lock);
+ snd_pcm_period_elapsed(substream);
+ spin_lock(&line6pcm->in.lock);
+ }
+}
+
+/*
+ * 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->in.last_frame = urb->start_frame;
+
+ /* find index of URB */
+ for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
+ if (urb == line6pcm->in.urbs[index])
+ break;
+
+ spin_lock_irqsave(&line6pcm->in.lock, 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;
+
+ if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
+ test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&
+ fsize > 0)
+ line6_capture_copy(line6pcm, fbuf, fsize);
+ }
+
+ clear_bit(index, &line6pcm->in.active_urbs);
+
+ if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
+ shutdown = 1;
+
+ if (!shutdown) {
+ submit_audio_in_urb(line6pcm);
+
+ if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
+ test_bit(LINE6_STREAM_PCM, &line6pcm->in.running))
+ line6_capture_check_period(line6pcm, length);
+ }
+
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
+}
+
+/* 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);
+
+ err = snd_pcm_hw_constraint_ratdens(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ (&line6pcm->
+ properties->snd_line6_rates));
+ if (err < 0)
+ return err;
+
+ runtime->hw = line6pcm->properties->snd_line6_capture_hw;
+ return 0;
+}
+
+/* close capture callback */
+static int snd_line6_capture_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/* capture operators */
+struct snd_pcm_ops snd_line6_capture_ops = {
+ .open = snd_line6_capture_open,
+ .close = snd_line6_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_line6_hw_params,
+ .hw_free = snd_line6_hw_free,
+ .prepare = snd_line6_prepare,
+ .trigger = snd_line6_trigger,
+ .pointer = snd_line6_pointer,
+};
+
+int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+ struct usb_line6 *line6 = line6pcm->line6;
+ int i;
+
+ /* create audio URBs and fill in constant values: */
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ struct urb *urb;
+
+ /* URB for audio in: */
+ urb = line6pcm->in.urbs[i] =
+ usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+
+ if (urb == NULL)
+ return -ENOMEM;
+
+ urb->dev = line6->usbdev;
+ urb->pipe =
+ usb_rcvisocpipe(line6->usbdev,
+ line6->properties->ep_audio_r &
+ USB_ENDPOINT_NUMBER_MASK);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->start_frame = -1;
+ urb->number_of_packets = LINE6_ISO_PACKETS;
+ urb->interval = LINE6_ISO_INTERVAL;
+ urb->error_count = 0;
+ urb->complete = audio_in_callback;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 CAPTURE_H
+#define CAPTURE_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+
+extern struct snd_pcm_ops snd_line6_capture_ops;
+
+extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
+ int fsize);
+extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
+ int length);
+extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "midi.h"
+#include "playback.h"
+#include "revision.h"
+#include "usbdefs.h"
+
+#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>"
+#define DRIVER_DESC "Line 6 USB Driver"
+
+/*
+ This is Line 6's MIDI manufacturer ID.
+*/
+const unsigned char line6_midi_id[] = {
+ 0x00, 0x01, 0x0c
+};
+EXPORT_SYMBOL_GPL(line6_midi_id);
+
+/*
+ Code to request version of POD, Variax interface
+ (and maybe other devices).
+*/
+static const char line6_request_version[] = {
+ 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
+};
+
+/**
+ Class for asynchronous messages.
+*/
+struct message {
+ struct usb_line6 *line6;
+ const char *buffer;
+ int size;
+ int done;
+};
+
+/*
+ Forward declarations.
+*/
+static void line6_data_received(struct urb *urb);
+static int line6_send_raw_message_async_part(struct message *msg,
+ struct urb *urb);
+
+/*
+ Start to listen on endpoint.
+*/
+static int line6_start_listen(struct usb_line6 *line6)
+{
+ int err;
+
+ usb_fill_int_urb(line6->urb_listen, line6->usbdev,
+ usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
+ line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
+ line6_data_received, line6, line6->interval);
+ line6->urb_listen->actual_length = 0;
+ err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
+ return err;
+}
+
+/*
+ Stop listening on endpoint.
+*/
+static void line6_stop_listen(struct usb_line6 *line6)
+{
+ usb_kill_urb(line6->urb_listen);
+}
+
+/*
+ Send raw message in pieces of wMaxPacketSize bytes.
+*/
+static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
+ int size)
+{
+ int i, done = 0;
+
+ for (i = 0; i < size; i += line6->max_packet_size) {
+ int partial;
+ const char *frag_buf = buffer + i;
+ int frag_size = min(line6->max_packet_size, size - i);
+ int retval;
+
+ retval = usb_interrupt_msg(line6->usbdev,
+ usb_sndintpipe(line6->usbdev,
+ line6->properties->ep_ctrl_w),
+ (char *)frag_buf, frag_size,
+ &partial, LINE6_TIMEOUT * HZ);
+
+ if (retval) {
+ dev_err(line6->ifcdev,
+ "usb_interrupt_msg failed (%d)\n", retval);
+ break;
+ }
+
+ done += frag_size;
+ }
+
+ return done;
+}
+
+/*
+ Notification of completion of asynchronous request transmission.
+*/
+static void line6_async_request_sent(struct urb *urb)
+{
+ struct message *msg = (struct message *)urb->context;
+
+ if (msg->done >= msg->size) {
+ usb_free_urb(urb);
+ kfree(msg);
+ } else
+ line6_send_raw_message_async_part(msg, urb);
+}
+
+/*
+ Asynchronously send part of a raw message.
+*/
+static int line6_send_raw_message_async_part(struct message *msg,
+ struct urb *urb)
+{
+ int retval;
+ struct usb_line6 *line6 = msg->line6;
+ int done = msg->done;
+ int bytes = min(msg->size - done, line6->max_packet_size);
+
+ usb_fill_int_urb(urb, line6->usbdev,
+ usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
+ (char *)msg->buffer + done, bytes,
+ line6_async_request_sent, msg, line6->interval);
+
+ msg->done += bytes;
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (retval < 0) {
+ dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
+ __func__, retval);
+ usb_free_urb(urb);
+ kfree(msg);
+ return retval;
+ }
+
+ return 0;
+}
+
+/*
+ Setup and start timer.
+*/
+void line6_start_timer(struct timer_list *timer, unsigned int msecs,
+ void (*function)(unsigned long), unsigned long data)
+{
+ setup_timer(timer, function, data);
+ mod_timer(timer, jiffies + msecs * HZ / 1000);
+}
+EXPORT_SYMBOL_GPL(line6_start_timer);
+
+/*
+ Asynchronously send raw message.
+*/
+int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
+ int size)
+{
+ struct message *msg;
+ struct urb *urb;
+
+ /* create message: */
+ msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
+ if (msg == NULL)
+ return -ENOMEM;
+
+ /* create URB: */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (urb == NULL) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+
+ /* set message data: */
+ msg->line6 = line6;
+ msg->buffer = buffer;
+ msg->size = size;
+ msg->done = 0;
+
+ /* start sending: */
+ return line6_send_raw_message_async_part(msg, urb);
+}
+EXPORT_SYMBOL_GPL(line6_send_raw_message_async);
+
+/*
+ Send asynchronous device version request.
+*/
+int line6_version_request_async(struct usb_line6 *line6)
+{
+ char *buffer;
+ int retval;
+
+ buffer = kmemdup(line6_request_version,
+ sizeof(line6_request_version), GFP_ATOMIC);
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ retval = line6_send_raw_message_async(line6, buffer,
+ sizeof(line6_request_version));
+ kfree(buffer);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(line6_version_request_async);
+
+/*
+ Send sysex message in pieces of wMaxPacketSize bytes.
+*/
+int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
+ int size)
+{
+ return line6_send_raw_message(line6, buffer,
+ size + SYSEX_EXTRA_SIZE) -
+ SYSEX_EXTRA_SIZE;
+}
+EXPORT_SYMBOL_GPL(line6_send_sysex_message);
+
+/*
+ Allocate buffer for sysex message and prepare header.
+ @param code sysex message code
+ @param size number of bytes between code and sysex end
+*/
+char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
+ int size)
+{
+ char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
+
+ if (!buffer)
+ return NULL;
+
+ buffer[0] = LINE6_SYSEX_BEGIN;
+ memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
+ buffer[sizeof(line6_midi_id) + 1] = code1;
+ buffer[sizeof(line6_midi_id) + 2] = code2;
+ buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
+ return buffer;
+}
+EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer);
+
+/*
+ Notification of data received from the Line 6 device.
+*/
+static void line6_data_received(struct urb *urb)
+{
+ struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+ struct midi_buffer *mb = &line6->line6midi->midibuf_in;
+ int done;
+
+ if (urb->status == -ESHUTDOWN)
+ return;
+
+ done =
+ line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
+
+ if (done < urb->actual_length) {
+ line6_midibuf_ignore(mb, done);
+ dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
+ done, urb->actual_length);
+ }
+
+ for (;;) {
+ done =
+ line6_midibuf_read(mb, line6->buffer_message,
+ LINE6_MESSAGE_MAXLEN);
+
+ if (done == 0)
+ break;
+
+ line6->message_length = done;
+ line6_midi_receive(line6, line6->buffer_message, done);
+
+ if (line6->process_message)
+ line6->process_message(line6);
+ }
+
+ line6_start_listen(line6);
+}
+
+/*
+ Read data from device.
+*/
+int line6_read_data(struct usb_line6 *line6, int address, void *data,
+ size_t datalen)
+{
+ struct usb_device *usbdev = line6->usbdev;
+ int ret;
+ unsigned char len;
+
+ /* query the serial number: */
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ (datalen << 8) | 0x21, address,
+ NULL, 0, LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
+ return ret;
+ }
+
+ /* Wait for data length. We'll get 0xff until length arrives. */
+ do {
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+ USB_DIR_IN,
+ 0x0012, 0x0000, &len, 1,
+ LINE6_TIMEOUT * HZ);
+ if (ret < 0) {
+ dev_err(line6->ifcdev,
+ "receive length failed (error %d)\n", ret);
+ return ret;
+ }
+ } while (len == 0xff);
+
+ if (len != datalen) {
+ /* should be equal or something went wrong */
+ dev_err(line6->ifcdev,
+ "length mismatch (expected %d, got %d)\n",
+ (int)datalen, (int)len);
+ return -EINVAL;
+ }
+
+ /* receive the result: */
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x0013, 0x0000, data, datalen,
+ LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_read_data);
+
+/*
+ Write data to device.
+*/
+int line6_write_data(struct usb_line6 *line6, int address, void *data,
+ size_t datalen)
+{
+ struct usb_device *usbdev = line6->usbdev;
+ int ret;
+ unsigned char status;
+
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x0022, address, data, datalen,
+ LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev,
+ "write request failed (error %d)\n", ret);
+ return ret;
+ }
+
+ do {
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+ 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+ USB_DIR_IN,
+ 0x0012, 0x0000,
+ &status, 1, LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev,
+ "receiving status failed (error %d)\n", ret);
+ return ret;
+ }
+ } while (status == 0xff);
+
+ if (status != 0) {
+ dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_write_data);
+
+/*
+ Read Line 6 device serial number.
+ (POD, TonePort, GuitarPort)
+*/
+int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
+{
+ return line6_read_data(line6, 0x80d0, serial_number,
+ sizeof(*serial_number));
+}
+EXPORT_SYMBOL_GPL(line6_read_serial_number);
+
+/*
+ Card destructor.
+*/
+static void line6_destruct(struct snd_card *card)
+{
+ struct usb_line6 *line6 = card->private_data;
+ struct usb_device *usbdev = line6->usbdev;
+
+ /* free buffer memory first: */
+ kfree(line6->buffer_message);
+ kfree(line6->buffer_listen);
+
+ /* then free URBs: */
+ usb_free_urb(line6->urb_listen);
+
+ /* decrement reference counters: */
+ usb_put_dev(usbdev);
+}
+
+/* get data from endpoint descriptor (see usb_maxpacket): */
+static void line6_get_interval(struct usb_line6 *line6)
+{
+ struct usb_device *usbdev = line6->usbdev;
+ struct usb_host_endpoint *ep;
+ unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r);
+ unsigned epnum = usb_pipeendpoint(pipe);
+
+ ep = usbdev->ep_in[epnum];
+ if (ep) {
+ line6->interval = ep->desc.bInterval;
+ line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+ } else {
+ dev_err(line6->ifcdev,
+ "endpoint not available, using fallback values");
+ line6->interval = LINE6_FALLBACK_INTERVAL;
+ line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
+ }
+}
+
+static int line6_init_cap_control(struct usb_line6 *line6)
+{
+ int ret;
+
+ /* initialize USB buffers: */
+ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
+ if (!line6->buffer_listen)
+ return -ENOMEM;
+
+ line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
+ if (!line6->buffer_message)
+ return -ENOMEM;
+
+ line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
+ if (!line6->urb_listen)
+ return -ENOMEM;
+
+ ret = line6_start_listen(line6);
+ if (ret < 0) {
+ dev_err(line6->ifcdev, "cannot start listening: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ Probe USB device.
+*/
+int line6_probe(struct usb_interface *interface,
+ const struct usb_device_id *id,
+ const struct line6_properties *properties,
+ int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
+ size_t data_size)
+{
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+ struct snd_card *card;
+ struct usb_line6 *line6;
+ int interface_number;
+ int ret;
+
+ if (WARN_ON(data_size < sizeof(*line6)))
+ return -EINVAL;
+
+ /* we don't handle multiple configurations */
+ if (usbdev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+
+ ret = snd_card_new(&interface->dev,
+ SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, data_size, &card);
+ if (ret < 0)
+ return ret;
+
+ /* store basic data: */
+ line6 = card->private_data;
+ line6->card = card;
+ line6->properties = properties;
+ line6->usbdev = usbdev;
+ line6->ifcdev = &interface->dev;
+
+ strcpy(card->id, properties->id);
+ strcpy(card->driver, DRIVER_NAME);
+ strcpy(card->shortname, properties->name);
+ sprintf(card->longname, "Line 6 %s at USB %s", properties->name,
+ dev_name(line6->ifcdev));
+ card->private_free = line6_destruct;
+
+ usb_set_intfdata(interface, line6);
+
+ /* increment reference counters: */
+ usb_get_dev(usbdev);
+
+ /* initialize device info: */
+ dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
+
+ /* query interface number */
+ interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
+
+ ret = usb_set_interface(usbdev, interface_number,
+ properties->altsetting);
+ if (ret < 0) {
+ dev_err(&interface->dev, "set_interface failed\n");
+ goto error;
+ }
+
+ line6_get_interval(line6);
+
+ if (properties->capabilities & LINE6_CAP_CONTROL) {
+ ret = line6_init_cap_control(line6);
+ if (ret < 0)
+ goto error;
+ }
+
+ /* initialize device data based on device: */
+ ret = private_init(line6, id);
+ if (ret < 0)
+ goto error;
+
+ /* creation of additional special files should go here */
+
+ dev_info(&interface->dev, "Line 6 %s now attached\n",
+ properties->name);
+
+ return 0;
+
+ error:
+ if (line6->disconnect)
+ line6->disconnect(line6);
+ snd_card_free(card);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(line6_probe);
+
+/*
+ Line 6 device disconnected.
+*/
+void line6_disconnect(struct usb_interface *interface)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+ if (!line6)
+ return;
+
+ if (WARN_ON(usbdev != line6->usbdev))
+ return;
+
+ if (line6->urb_listen != NULL)
+ line6_stop_listen(line6);
+
+ snd_card_disconnect(line6->card);
+ if (line6->line6pcm)
+ line6_pcm_disconnect(line6->line6pcm);
+ if (line6->disconnect)
+ line6->disconnect(line6);
+
+ dev_info(&interface->dev, "Line 6 %s now disconnected\n",
+ line6->properties->name);
+
+ /* make sure the device isn't destructed twice: */
+ usb_set_intfdata(interface, NULL);
+
+ snd_card_free_when_closed(line6->card);
+}
+EXPORT_SYMBOL_GPL(line6_disconnect);
+
+#ifdef CONFIG_PM
+
+/*
+ Suspend Line 6 device.
+*/
+int line6_suspend(struct usb_interface *interface, pm_message_t message)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+ struct snd_line6_pcm *line6pcm = line6->line6pcm;
+
+ snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
+
+ if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+ line6_stop_listen(line6);
+
+ if (line6pcm != NULL) {
+ snd_pcm_suspend_all(line6pcm->pcm);
+ line6pcm->flags = 0;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_suspend);
+
+/*
+ Resume Line 6 device.
+*/
+int line6_resume(struct usb_interface *interface)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+
+ if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+ line6_start_listen(line6);
+
+ snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_resume);
+
+#endif /* CONFIG_PM */
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 DRIVER_H
+#define DRIVER_H
+
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+
+#include "midi.h"
+
+#define DRIVER_NAME "line6usb"
+
+#define LINE6_TIMEOUT 1
+#define LINE6_BUFSIZE_LISTEN 32
+#define LINE6_MESSAGE_MAXLEN 256
+
+/*
+ Line 6 MIDI control commands
+*/
+#define LINE6_PARAM_CHANGE 0xb0
+#define LINE6_PROGRAM_CHANGE 0xc0
+#define LINE6_SYSEX_BEGIN 0xf0
+#define LINE6_SYSEX_END 0xf7
+#define LINE6_RESET 0xff
+
+/*
+ MIDI channel for messages initiated by the host
+ (and eventually echoed back by the device)
+*/
+#define LINE6_CHANNEL_HOST 0x00
+
+/*
+ MIDI channel for messages initiated by the device
+*/
+#define LINE6_CHANNEL_DEVICE 0x02
+
+#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */
+
+#define LINE6_CHANNEL_MASK 0x0f
+
+#define CHECK_STARTUP_PROGRESS(x, n) \
+do { \
+ if ((x) >= (n)) \
+ return; \
+ x = (n); \
+} while (0)
+
+extern const unsigned char line6_midi_id[3];
+
+static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
+static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
+
+/**
+ Common properties of Line 6 devices.
+*/
+struct line6_properties {
+ /**
+ Card id string (maximum 16 characters).
+ This can be used to address the device in ALSA programs as
+ "default:CARD=<id>"
+ */
+ const char *id;
+
+ /**
+ Card short name (maximum 32 characters).
+ */
+ const char *name;
+
+ /**
+ Bit vector defining this device's capabilities in the
+ line6usb driver.
+ */
+ int capabilities;
+
+ int altsetting;
+
+ unsigned ep_ctrl_r;
+ unsigned ep_ctrl_w;
+ unsigned ep_audio_r;
+ unsigned ep_audio_w;
+};
+
+/**
+ Common data shared by all Line 6 devices.
+ Corresponds to a pair of USB endpoints.
+*/
+struct usb_line6 {
+ /**
+ USB device.
+ */
+ struct usb_device *usbdev;
+
+ /**
+ Properties.
+ */
+ const struct line6_properties *properties;
+
+ /**
+ Interval (ms).
+ */
+ int interval;
+
+ /**
+ Maximum size of USB packet.
+ */
+ int max_packet_size;
+
+ /**
+ Device representing the USB interface.
+ */
+ struct device *ifcdev;
+
+ /**
+ Line 6 sound card data structure.
+ Each device has at least MIDI or PCM.
+ */
+ struct snd_card *card;
+
+ /**
+ Line 6 PCM device data structure.
+ */
+ struct snd_line6_pcm *line6pcm;
+
+ /**
+ Line 6 MIDI device data structure.
+ */
+ struct snd_line6_midi *line6midi;
+
+ /**
+ URB for listening to PODxt Pro control endpoint.
+ */
+ struct urb *urb_listen;
+
+ /**
+ Buffer for listening to PODxt Pro control endpoint.
+ */
+ unsigned char *buffer_listen;
+
+ /**
+ Buffer for message to be processed.
+ */
+ unsigned char *buffer_message;
+
+ /**
+ Length of message to be processed.
+ */
+ int message_length;
+
+ void (*process_message)(struct usb_line6 *);
+ void (*disconnect)(struct usb_line6 *line6);
+};
+
+extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
+ int code2, int size);
+extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
+ size_t datalen);
+extern int line6_read_serial_number(struct usb_line6 *line6,
+ int *serial_number);
+extern int line6_send_raw_message_async(struct usb_line6 *line6,
+ const char *buffer, int size);
+extern int line6_send_sysex_message(struct usb_line6 *line6,
+ const char *buffer, int size);
+extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
+ void (*function)(unsigned long),
+ unsigned long data);
+extern int line6_version_request_async(struct usb_line6 *line6);
+extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
+ size_t datalen);
+
+int line6_probe(struct usb_interface *interface,
+ const struct usb_device_id *id,
+ const struct line6_properties *properties,
+ int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
+ size_t data_size);
+
+void line6_disconnect(struct usb_interface *interface);
+
+#ifdef CONFIG_PM
+int line6_suspend(struct usb_interface *interface, pm_message_t message);
+int line6_resume(struct usb_interface *interface);
+#endif
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 <linux/usb.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "driver.h"
+#include "midi.h"
+#include "usbdefs.h"
+
+#define line6_rawmidi_substream_midi(substream) \
+ ((struct snd_line6_midi *)((substream)->rmidi->private_data))
+
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+ int length);
+
+/*
+ Pass data received via USB to MIDI.
+*/
+void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+ int length)
+{
+ if (line6->line6midi->substream_receive)
+ snd_rawmidi_receive(line6->line6midi->substream_receive,
+ data, length);
+}
+
+/*
+ Read data from MIDI buffer and transmit them via USB.
+*/
+static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
+{
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+ struct snd_line6_midi *line6midi = line6->line6midi;
+ struct midi_buffer *mb = &line6midi->midibuf_out;
+ unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
+ int req, done;
+
+ for (;;) {
+ req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
+ done = snd_rawmidi_transmit_peek(substream, chunk, req);
+
+ if (done == 0)
+ break;
+
+ line6_midibuf_write(mb, chunk, done);
+ snd_rawmidi_transmit_ack(substream, done);
+ }
+
+ for (;;) {
+ done = line6_midibuf_read(mb, chunk,
+ LINE6_FALLBACK_MAXPACKETSIZE);
+
+ if (done == 0)
+ break;
+
+ send_midi_async(line6, chunk, done);
+ }
+}
+
+/*
+ Notification of completion of MIDI transmission.
+*/
+static void midi_sent(struct urb *urb)
+{
+ unsigned long flags;
+ int status;
+ int num;
+ struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+
+ status = urb->status;
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+
+ if (status == -ESHUTDOWN)
+ return;
+
+ spin_lock_irqsave(&line6->line6midi->lock, flags);
+ num = --line6->line6midi->num_active_send_urbs;
+
+ if (num == 0) {
+ line6_midi_transmit(line6->line6midi->substream_transmit);
+ num = line6->line6midi->num_active_send_urbs;
+ }
+
+ if (num == 0)
+ wake_up(&line6->line6midi->send_wait);
+
+ spin_unlock_irqrestore(&line6->line6midi->lock, flags);
+}
+
+/*
+ Send an asynchronous MIDI message.
+ Assumes that line6->line6midi->lock is held
+ (i.e., this function is serialized).
+*/
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+ int length)
+{
+ struct urb *urb;
+ int retval;
+ unsigned char *transfer_buffer;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (urb == NULL)
+ return -ENOMEM;
+
+ transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
+
+ if (transfer_buffer == NULL) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ usb_fill_int_urb(urb, line6->usbdev,
+ usb_sndbulkpipe(line6->usbdev,
+ line6->properties->ep_ctrl_w),
+ transfer_buffer, length, midi_sent, line6,
+ line6->interval);
+ urb->actual_length = 0;
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (retval < 0) {
+ dev_err(line6->ifcdev, "usb_submit_urb failed\n");
+ usb_free_urb(urb);
+ return retval;
+ }
+
+ ++line6->line6midi->num_active_send_urbs;
+ return 0;
+}
+
+static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ unsigned long flags;
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+
+ line6->line6midi->substream_transmit = substream;
+ spin_lock_irqsave(&line6->line6midi->lock, flags);
+
+ if (line6->line6midi->num_active_send_urbs == 0)
+ line6_midi_transmit(substream);
+
+ spin_unlock_irqrestore(&line6->line6midi->lock, flags);
+}
+
+static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
+{
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+ struct snd_line6_midi *midi = line6->line6midi;
+
+ wait_event_interruptible(midi->send_wait,
+ midi->num_active_send_urbs == 0);
+}
+
+static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+
+ if (up)
+ line6->line6midi->substream_receive = substream;
+ else
+ line6->line6midi->substream_receive = NULL;
+}
+
+static struct snd_rawmidi_ops line6_midi_output_ops = {
+ .open = line6_midi_output_open,
+ .close = line6_midi_output_close,
+ .trigger = line6_midi_output_trigger,
+ .drain = line6_midi_output_drain,
+};
+
+static struct snd_rawmidi_ops line6_midi_input_ops = {
+ .open = line6_midi_input_open,
+ .close = line6_midi_input_close,
+ .trigger = line6_midi_input_trigger,
+};
+
+/* Create a MIDI device */
+static int snd_line6_new_midi(struct usb_line6 *line6,
+ struct snd_rawmidi **rmidi_ret)
+{
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret);
+ if (err < 0)
+ return err;
+
+ rmidi = *rmidi_ret;
+ strcpy(rmidi->id, line6->properties->id);
+ strcpy(rmidi->name, line6->properties->name);
+
+ rmidi->info_flags =
+ SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &line6_midi_output_ops);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &line6_midi_input_ops);
+ return 0;
+}
+
+/* MIDI device destructor */
+static void snd_line6_midi_free(struct snd_rawmidi *rmidi)
+{
+ struct snd_line6_midi *line6midi = rmidi->private_data;
+
+ line6_midibuf_destroy(&line6midi->midibuf_in);
+ line6_midibuf_destroy(&line6midi->midibuf_out);
+ kfree(line6midi);
+}
+
+/*
+ Initialize the Line 6 MIDI subsystem.
+*/
+int line6_init_midi(struct usb_line6 *line6)
+{
+ int err;
+ struct snd_rawmidi *rmidi;
+ struct snd_line6_midi *line6midi;
+
+ if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
+ /* skip MIDI initialization and report success */
+ return 0;
+ }
+
+ err = snd_line6_new_midi(line6, &rmidi);
+ if (err < 0)
+ return err;
+
+ line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
+ if (!line6midi)
+ return -ENOMEM;
+
+ rmidi->private_data = line6midi;
+ rmidi->private_free = snd_line6_midi_free;
+
+ init_waitqueue_head(&line6midi->send_wait);
+ spin_lock_init(&line6midi->lock);
+ line6midi->line6 = line6;
+
+ err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
+ if (err < 0)
+ return err;
+
+ err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
+ if (err < 0)
+ return err;
+
+ line6->line6midi = line6midi;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_init_midi);
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 MIDI_H
+#define MIDI_H
+
+#include <sound/rawmidi.h>
+
+#include "midibuf.h"
+
+#define MIDI_BUFFER_SIZE 1024
+
+struct snd_line6_midi {
+ /**
+ Pointer back to the Line 6 driver data structure.
+ */
+ struct usb_line6 *line6;
+
+ /**
+ MIDI substream for receiving (or NULL if not active).
+ */
+ struct snd_rawmidi_substream *substream_receive;
+
+ /**
+ MIDI substream for transmitting (or NULL if not active).
+ */
+ struct snd_rawmidi_substream *substream_transmit;
+
+ /**
+ Number of currently active MIDI send URBs.
+ */
+ int num_active_send_urbs;
+
+ /**
+ Spin lock to protect MIDI buffer handling.
+ */
+ spinlock_t lock;
+
+ /**
+ Wait queue for MIDI transmission.
+ */
+ wait_queue_head_t send_wait;
+
+ /**
+ Buffer for incoming MIDI stream.
+ */
+ struct midi_buffer midibuf_in;
+
+ /**
+ Buffer for outgoing MIDI stream.
+ */
+ struct midi_buffer midibuf_out;
+};
+
+extern int line6_init_midi(struct usb_line6 *line6);
+extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+ int length);
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 "midibuf.h"
+
+static int midibuf_message_length(unsigned char code)
+{
+ int message_length;
+
+ if (code < 0x80)
+ message_length = -1;
+ else if (code < 0xf0) {
+ static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
+
+ message_length = length[(code >> 4) - 8];
+ } else {
+ /*
+ Note that according to the MIDI specification 0xf2 is
+ the "Song Position Pointer", but this is used by Line 6
+ to send sysex messages to the host.
+ */
+ static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
+ 1, 1, 1, -1, 1, 1
+ };
+ message_length = length[code & 0x0f];
+ }
+
+ return message_length;
+}
+
+static int midibuf_is_empty(struct midi_buffer *this)
+{
+ return (this->pos_read == this->pos_write) && !this->full;
+}
+
+static int midibuf_is_full(struct midi_buffer *this)
+{
+ return this->full;
+}
+
+void line6_midibuf_reset(struct midi_buffer *this)
+{
+ this->pos_read = this->pos_write = this->full = 0;
+ this->command_prev = -1;
+}
+
+int line6_midibuf_init(struct midi_buffer *this, int size, int split)
+{
+ this->buf = kmalloc(size, GFP_KERNEL);
+
+ if (this->buf == NULL)
+ return -ENOMEM;
+
+ this->size = size;
+ this->split = split;
+ line6_midibuf_reset(this);
+ return 0;
+}
+
+void line6_midibuf_status(struct midi_buffer *this)
+{
+ pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
+ this->size, this->split, this->pos_read, this->pos_write,
+ this->full, this->command_prev);
+}
+
+int line6_midibuf_bytes_free(struct midi_buffer *this)
+{
+ return
+ midibuf_is_full(this) ?
+ 0 :
+ (this->pos_read - this->pos_write + this->size - 1) % this->size +
+ 1;
+}
+
+int line6_midibuf_bytes_used(struct midi_buffer *this)
+{
+ return
+ midibuf_is_empty(this) ?
+ 0 :
+ (this->pos_write - this->pos_read + this->size - 1) % this->size +
+ 1;
+}
+
+int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
+ int length)
+{
+ int bytes_free;
+ int length1, length2;
+ int skip_active_sense = 0;
+
+ if (midibuf_is_full(this) || (length <= 0))
+ return 0;
+
+ /* skip trailing active sense */
+ if (data[length - 1] == 0xfe) {
+ --length;
+ skip_active_sense = 1;
+ }
+
+ bytes_free = line6_midibuf_bytes_free(this);
+
+ if (length > bytes_free)
+ length = bytes_free;
+
+ if (length > 0) {
+ length1 = this->size - this->pos_write;
+
+ if (length < length1) {
+ /* no buffer wraparound */
+ memcpy(this->buf + this->pos_write, data, length);
+ this->pos_write += length;
+ } else {
+ /* buffer wraparound */
+ length2 = length - length1;
+ memcpy(this->buf + this->pos_write, data, length1);
+ memcpy(this->buf, data + length1, length2);
+ this->pos_write = length2;
+ }
+
+ if (this->pos_write == this->pos_read)
+ this->full = 1;
+ }
+
+ return length + skip_active_sense;
+}
+
+int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
+ int length)
+{
+ int bytes_used;
+ int length1, length2;
+ int command;
+ int midi_length;
+ int repeat = 0;
+ int i;
+
+ /* we need to be able to store at least a 3 byte MIDI message */
+ if (length < 3)
+ return -EINVAL;
+
+ if (midibuf_is_empty(this))
+ return 0;
+
+ bytes_used = line6_midibuf_bytes_used(this);
+
+ if (length > bytes_used)
+ length = bytes_used;
+
+ length1 = this->size - this->pos_read;
+
+ /* check MIDI command length */
+ command = this->buf[this->pos_read];
+
+ if (command & 0x80) {
+ midi_length = midibuf_message_length(command);
+ this->command_prev = command;
+ } else {
+ if (this->command_prev > 0) {
+ int midi_length_prev =
+ midibuf_message_length(this->command_prev);
+
+ if (midi_length_prev > 0) {
+ midi_length = midi_length_prev - 1;
+ repeat = 1;
+ } else
+ midi_length = -1;
+ } else
+ midi_length = -1;
+ }
+
+ if (midi_length < 0) {
+ /* search for end of message */
+ if (length < length1) {
+ /* no buffer wraparound */
+ for (i = 1; i < length; ++i)
+ if (this->buf[this->pos_read + i] & 0x80)
+ break;
+
+ midi_length = i;
+ } else {
+ /* buffer wraparound */
+ length2 = length - length1;
+
+ for (i = 1; i < length1; ++i)
+ if (this->buf[this->pos_read + i] & 0x80)
+ break;
+
+ if (i < length1)
+ midi_length = i;
+ else {
+ for (i = 0; i < length2; ++i)
+ if (this->buf[i] & 0x80)
+ break;
+
+ midi_length = length1 + i;
+ }
+ }
+
+ if (midi_length == length)
+ midi_length = -1; /* end of message not found */
+ }
+
+ if (midi_length < 0) {
+ if (!this->split)
+ return 0; /* command is not yet complete */
+ } else {
+ if (length < midi_length)
+ return 0; /* command is not yet complete */
+
+ length = midi_length;
+ }
+
+ if (length < length1) {
+ /* no buffer wraparound */
+ memcpy(data + repeat, this->buf + this->pos_read, length);
+ this->pos_read += length;
+ } else {
+ /* buffer wraparound */
+ length2 = length - length1;
+ memcpy(data + repeat, this->buf + this->pos_read, length1);
+ memcpy(data + repeat + length1, this->buf, length2);
+ this->pos_read = length2;
+ }
+
+ if (repeat)
+ data[0] = this->command_prev;
+
+ this->full = 0;
+ return length + repeat;
+}
+
+int line6_midibuf_ignore(struct midi_buffer *this, int length)
+{
+ int bytes_used = line6_midibuf_bytes_used(this);
+
+ if (length > bytes_used)
+ length = bytes_used;
+
+ this->pos_read = (this->pos_read + length) % this->size;
+ this->full = 0;
+ return length;
+}
+
+int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
+{
+ int cmd = this->command_prev;
+
+ if ((cmd >= 0x80) && (cmd < 0xf0))
+ if ((mask & (1 << (cmd & 0x0f))) == 0)
+ return 1;
+
+ return 0;
+}
+
+void line6_midibuf_destroy(struct midi_buffer *this)
+{
+ kfree(this->buf);
+ this->buf = NULL;
+}
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 MIDIBUF_H
+#define MIDIBUF_H
+
+struct midi_buffer {
+ unsigned char *buf;
+ int size;
+ int split;
+ int pos_read, pos_write;
+ int full;
+ int command_prev;
+};
+
+extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
+extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
+extern void line6_midibuf_destroy(struct midi_buffer *mb);
+extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
+extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
+extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
+ int length);
+extern void line6_midibuf_reset(struct midi_buffer *mb);
+extern int line6_midibuf_skip_message(struct midi_buffer *mb,
+ unsigned short mask);
+extern void line6_midibuf_status(struct midi_buffer *mb);
+extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
+ int length);
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+/* impulse response volume controls */
+static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 255;
+ return 0;
+}
+
+static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
+ return 0;
+}
+
+static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ int value = ucontrol->value.integer.value[0];
+ int err;
+
+ if (line6pcm->impulse_volume == value)
+ return 0;
+
+ line6pcm->impulse_volume = value;
+ if (value > 0) {
+ err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE);
+ if (err < 0) {
+ line6pcm->impulse_volume = 0;
+ line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
+ return err;
+ }
+ } else {
+ line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
+ }
+ return 1;
+}
+
+/* impulse response period controls */
+static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 2000;
+ return 0;
+}
+
+static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = line6pcm->impulse_period;
+ return 0;
+}
+
+static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ int value = ucontrol->value.integer.value[0];
+
+ if (line6pcm->impulse_period == value)
+ return 0;
+
+ line6pcm->impulse_period = value;
+ return 1;
+}
+
+/*
+ Unlink all currently active URBs.
+*/
+static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pcms)
+{
+ int i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+ if (test_bit(i, &pcms->active_urbs)) {
+ if (!test_and_set_bit(i, &pcms->unlink_urbs))
+ usb_unlink_urb(pcms->urbs[i]);
+ }
+ }
+}
+
+/*
+ Wait until unlinking of all currently active URBs has been finished.
+*/
+static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pcms)
+{
+ int timeout = HZ;
+ int i;
+ int alive;
+
+ do {
+ alive = 0;
+ for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+ if (test_bit(i, &pcms->active_urbs))
+ alive++;
+ }
+ if (!alive)
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ } while (--timeout > 0);
+ if (alive)
+ dev_err(line6pcm->line6->ifcdev,
+ "timeout: still %d active urbs..\n", alive);
+}
+
+static inline struct line6_pcm_stream *
+get_stream(struct snd_line6_pcm *line6pcm, int direction)
+{
+ return (direction == SNDRV_PCM_STREAM_PLAYBACK) ?
+ &line6pcm->out : &line6pcm->in;
+}
+
+/* allocate a buffer if not opened yet;
+ * call this in line6pcm.state_change mutex
+ */
+static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pstr, int type)
+{
+ /* Invoked multiple times in a row so allocate once only */
+ if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) {
+ pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+ line6pcm->max_packet_size, GFP_KERNEL);
+ if (!pstr->buffer)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* free a buffer if all streams are closed;
+ * call this in line6pcm.state_change mutex
+ */
+static void line6_buffer_release(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pstr, int type)
+{
+
+ clear_bit(type, &pstr->opened);
+ if (!pstr->opened) {
+ line6_wait_clear_audio_urbs(line6pcm, pstr);
+ kfree(pstr->buffer);
+ pstr->buffer = NULL;
+ }
+}
+
+/* start a PCM stream */
+static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
+ int type)
+{
+ unsigned long flags;
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
+ int ret = 0;
+
+ spin_lock_irqsave(&pstr->lock, flags);
+ if (!test_and_set_bit(type, &pstr->running)) {
+ if (pstr->active_urbs || pstr->unlink_urbs) {
+ ret = -EBUSY;
+ goto error;
+ }
+
+ pstr->count = 0;
+ /* Submit all currently available URBs */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = line6_submit_audio_out_all_urbs(line6pcm);
+ else
+ ret = line6_submit_audio_in_all_urbs(line6pcm);
+ }
+ error:
+ if (ret < 0)
+ clear_bit(type, &pstr->running);
+ spin_unlock_irqrestore(&pstr->lock, flags);
+ return ret;
+}
+
+/* stop a PCM stream; this doesn't sync with the unlinked URBs */
+static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
+ int type)
+{
+ unsigned long flags;
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
+
+ spin_lock_irqsave(&pstr->lock, flags);
+ clear_bit(type, &pstr->running);
+ if (!pstr->running) {
+ line6_unlink_audio_urbs(line6pcm, pstr);
+ if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+ line6pcm->prev_fbuf = NULL;
+ line6pcm->prev_fsize = 0;
+ }
+ }
+ spin_unlock_irqrestore(&pstr->lock, flags);
+}
+
+/* common PCM trigger callback */
+int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+ int err;
+
+ clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ err = line6_stream_start(line6pcm, s->stream,
+ LINE6_STREAM_PCM);
+ if (err < 0)
+ return err;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ line6_stream_stop(line6pcm, s->stream,
+ LINE6_STREAM_PCM);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* common PCM pointer callback */
+snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ return pstr->pos_done;
+}
+
+/* Acquire and start duplex streams:
+ * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
+ */
+int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type)
+{
+ struct line6_pcm_stream *pstr;
+ int ret = 0, dir;
+
+ mutex_lock(&line6pcm->state_mutex);
+ for (dir = 0; dir < 2; dir++) {
+ pstr = get_stream(line6pcm, dir);
+ ret = line6_buffer_acquire(line6pcm, pstr, type);
+ if (ret < 0)
+ goto error;
+ if (!pstr->running)
+ line6_wait_clear_audio_urbs(line6pcm, pstr);
+ }
+ for (dir = 0; dir < 2; dir++) {
+ ret = line6_stream_start(line6pcm, dir, type);
+ if (ret < 0)
+ goto error;
+ }
+ error:
+ mutex_unlock(&line6pcm->state_mutex);
+ if (ret < 0)
+ line6_pcm_release(line6pcm, type);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(line6_pcm_acquire);
+
+/* Stop and release duplex streams */
+void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
+{
+ struct line6_pcm_stream *pstr;
+ int dir;
+
+ mutex_lock(&line6pcm->state_mutex);
+ for (dir = 0; dir < 2; dir++)
+ line6_stream_stop(line6pcm, dir, type);
+ for (dir = 0; dir < 2; dir++) {
+ pstr = get_stream(line6pcm, dir);
+ line6_buffer_release(line6pcm, pstr, type);
+ }
+ mutex_unlock(&line6pcm->state_mutex);
+}
+EXPORT_SYMBOL_GPL(line6_pcm_release);
+
+/* common PCM hw_params callback */
+int snd_line6_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int ret;
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ mutex_lock(&line6pcm->state_mutex);
+ ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM);
+ if (ret < 0)
+ goto error;
+
+ ret = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (ret < 0) {
+ line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
+ goto error;
+ }
+
+ pstr->period = params_period_bytes(hw_params);
+ error:
+ mutex_unlock(&line6pcm->state_mutex);
+ return ret;
+}
+
+/* common PCM hw_free callback */
+int snd_line6_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ mutex_lock(&line6pcm->state_mutex);
+ line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
+ mutex_unlock(&line6pcm->state_mutex);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+
+/* control info callback */
+static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 256;
+ return 0;
+}
+
+/* control get callback */
+static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ for (i = 0; i < 2; i++)
+ ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
+
+ return 0;
+}
+
+/* control put callback */
+static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i, changed = 0;
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ for (i = 0; i < 2; i++)
+ if (line6pcm->volume_playback[i] !=
+ ucontrol->value.integer.value[i]) {
+ line6pcm->volume_playback[i] =
+ ucontrol->value.integer.value[i];
+ changed = 1;
+ }
+
+ return changed;
+}
+
+/* control definition */
+static struct snd_kcontrol_new line6_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .info = snd_line6_control_playback_info,
+ .get = snd_line6_control_playback_get,
+ .put = snd_line6_control_playback_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Impulse Response Volume",
+ .info = snd_line6_impulse_volume_info,
+ .get = snd_line6_impulse_volume_get,
+ .put = snd_line6_impulse_volume_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Impulse Response Period",
+ .info = snd_line6_impulse_period_info,
+ .get = snd_line6_impulse_period_get,
+ .put = snd_line6_impulse_period_put
+ },
+};
+
+/*
+ Cleanup the PCM device.
+*/
+static void cleanup_urbs(struct line6_pcm_stream *pcms)
+{
+ int i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+ if (pcms->urbs[i]) {
+ usb_kill_urb(pcms->urbs[i]);
+ usb_free_urb(pcms->urbs[i]);
+ }
+ }
+}
+
+static void line6_cleanup_pcm(struct snd_pcm *pcm)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
+
+ cleanup_urbs(&line6pcm->out);
+ cleanup_urbs(&line6pcm->in);
+ kfree(line6pcm);
+}
+
+/* create a PCM device */
+static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(line6->card, (char *)line6->properties->name,
+ 0, 1, 1, pcm_ret);
+ if (err < 0)
+ return err;
+ pcm = *pcm_ret;
+ strcpy(pcm->name, line6->properties->name);
+
+ /* set operators */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_line6_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
+
+ /* pre-allocation of buffers */
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL), 64 * 1024,
+ 128 * 1024);
+ return 0;
+}
+
+/*
+ Sync with PCM stream stops.
+*/
+void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
+{
+ line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
+ line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
+ line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
+ line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
+}
+
+/*
+ Create and register the PCM device and mixer entries.
+ Create URBs for playback and capture.
+*/
+int line6_init_pcm(struct usb_line6 *line6,
+ struct line6_pcm_properties *properties)
+{
+ int i, err;
+ unsigned ep_read = line6->properties->ep_audio_r;
+ unsigned ep_write = line6->properties->ep_audio_w;
+ struct snd_pcm *pcm;
+ struct snd_line6_pcm *line6pcm;
+
+ if (!(line6->properties->capabilities & LINE6_CAP_PCM))
+ return 0; /* skip PCM initialization and report success */
+
+ err = snd_line6_new_pcm(line6, &pcm);
+ if (err < 0)
+ return err;
+
+ line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
+ if (!line6pcm)
+ return -ENOMEM;
+
+ mutex_init(&line6pcm->state_mutex);
+ line6pcm->pcm = pcm;
+ line6pcm->properties = properties;
+ line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
+ line6pcm->volume_monitor = 255;
+ line6pcm->line6 = line6;
+
+ /* Read and write buffers are sized identically, so choose minimum */
+ line6pcm->max_packet_size = min(
+ usb_maxpacket(line6->usbdev,
+ usb_rcvisocpipe(line6->usbdev, ep_read), 0),
+ usb_maxpacket(line6->usbdev,
+ usb_sndisocpipe(line6->usbdev, ep_write), 1));
+
+ spin_lock_init(&line6pcm->out.lock);
+ spin_lock_init(&line6pcm->in.lock);
+ line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
+
+ line6->line6pcm = line6pcm;
+
+ pcm->private_data = line6pcm;
+ pcm->private_free = line6_cleanup_pcm;
+
+ err = line6_create_audio_out_urbs(line6pcm);
+ if (err < 0)
+ return err;
+
+ err = line6_create_audio_in_urbs(line6pcm);
+ if (err < 0)
+ return err;
+
+ /* mixer: */
+ for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&line6_controls[i], line6pcm));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_init_pcm);
+
+/* prepare pcm callback */
+int snd_line6_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ mutex_lock(&line6pcm->state_mutex);
+ if (!pstr->running)
+ line6_wait_clear_audio_urbs(line6pcm, pstr);
+
+ if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {
+ line6pcm->out.count = 0;
+ line6pcm->out.pos = 0;
+ line6pcm->out.pos_done = 0;
+ line6pcm->out.bytes = 0;
+ line6pcm->in.count = 0;
+ line6pcm->in.pos_done = 0;
+ line6pcm->in.bytes = 0;
+ }
+
+ mutex_unlock(&line6pcm->state_mutex);
+ return 0;
+}
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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.
+ *
+ */
+
+/*
+ PCM interface to POD series devices.
+*/
+
+#ifndef PCM_H
+#define PCM_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "usbdefs.h"
+
+/* number of URBs */
+#define LINE6_ISO_BUFFERS 2
+
+/*
+ number of USB frames per URB
+ The Line 6 Windows driver always transmits two frames per packet, but
+ the Linux driver performs significantly better (i.e., lower latency)
+ with only one frame per packet.
+*/
+#define LINE6_ISO_PACKETS 1
+
+/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
+#define LINE6_ISO_INTERVAL 1
+
+#define LINE6_IMPULSE_DEFAULT_PERIOD 100
+
+/*
+ Get substream from Line 6 PCM data structure
+*/
+#define get_substream(line6pcm, stream) \
+ (line6pcm->pcm->streams[stream].substream)
+
+/*
+ PCM mode bits.
+
+ There are several features of the Line 6 USB driver which require PCM
+ data to be exchanged with the device:
+ *) PCM playback and capture via ALSA
+ *) software monitoring (for devices without hardware monitoring)
+ *) optional impulse response measurement
+ However, from the device's point of view, there is just a single
+ capture and playback stream, which must be shared between these
+ subsystems. It is therefore necessary to maintain the state of the
+ subsystems with respect to PCM usage.
+
+ We define two bit flags, "opened" and "running", for each playback
+ or capture stream. Both can contain the bit flag corresponding to
+ LINE6_STREAM_* type,
+ LINE6_STREAM_PCM = ALSA PCM playback or capture
+ LINE6_STREAM_MONITOR = software monitoring
+ IMPULSE = optional impulse response measurement
+ The opened flag indicates whether the buffer is allocated while
+ the running flag indicates whether the stream is running.
+
+ For monitor or impulse operations, the driver needs to call
+ snd_line6_duplex_acquire() or snd_line6_duplex_release() with the
+ appropriate LINE6_STREAM_* flag.
+*/
+
+/* stream types */
+enum {
+ LINE6_STREAM_PCM,
+ LINE6_STREAM_MONITOR,
+ LINE6_STREAM_IMPULSE,
+};
+
+/* misc bit flags for PCM operation */
+enum {
+ LINE6_FLAG_PAUSE_PLAYBACK,
+ LINE6_FLAG_PREPARED,
+};
+
+struct line6_pcm_properties {
+ struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
+ struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
+ int bytes_per_frame;
+};
+
+struct line6_pcm_stream {
+ /* allocated URBs */
+ struct urb *urbs[LINE6_ISO_BUFFERS];
+
+ /* Temporary buffer;
+ * Since the packet size is not known in advance, this buffer is
+ * large enough to store maximum size packets.
+ */
+ unsigned char *buffer;
+
+ /* Free frame position in the buffer. */
+ snd_pcm_uframes_t pos;
+
+ /* Count processed bytes;
+ * This is modulo period size (to determine when a period is finished).
+ */
+ unsigned bytes;
+
+ /* Counter to create desired sample rate */
+ unsigned count;
+
+ /* period size in bytes */
+ unsigned period;
+
+ /* Processed frame position in the buffer;
+ * The contents of the ring buffer have been consumed by the USB
+ * subsystem (i.e., sent to the USB device) up to this position.
+ */
+ snd_pcm_uframes_t pos_done;
+
+ /* Bit mask of active URBs */
+ unsigned long active_urbs;
+
+ /* Bit mask of URBs currently being unlinked */
+ unsigned long unlink_urbs;
+
+ /* Spin lock to protect updates of the buffer positions (not contents)
+ */
+ spinlock_t lock;
+
+ /* Bit flags for operational stream types */
+ unsigned long opened;
+
+ /* Bit flags for running stream types */
+ unsigned long running;
+
+ int last_frame;
+};
+
+struct snd_line6_pcm {
+ /**
+ Pointer back to the Line 6 driver data structure.
+ */
+ struct usb_line6 *line6;
+
+ /**
+ Properties.
+ */
+ struct line6_pcm_properties *properties;
+
+ /**
+ ALSA pcm stream
+ */
+ struct snd_pcm *pcm;
+
+ /* protection to state changes of in/out streams */
+ struct mutex state_mutex;
+
+ /* Capture and playback streams */
+ struct line6_pcm_stream in;
+ struct line6_pcm_stream out;
+
+ /**
+ Previously captured frame (for software monitoring).
+ */
+ unsigned char *prev_fbuf;
+
+ /**
+ Size of previously captured frame (for software monitoring).
+ */
+ int prev_fsize;
+
+ /**
+ Maximum size of USB packet.
+ */
+ int max_packet_size;
+
+ /**
+ PCM playback volume (left and right).
+ */
+ int volume_playback[2];
+
+ /**
+ PCM monitor volume.
+ */
+ int volume_monitor;
+
+ /**
+ Volume of impulse response test signal (if zero, test is disabled).
+ */
+ int impulse_volume;
+
+ /**
+ Period of impulse response test signal.
+ */
+ int impulse_period;
+
+ /**
+ Counter for impulse response test signal.
+ */
+ int impulse_count;
+
+ /**
+ Several status bits (see LINE6_FLAG_*).
+ */
+ unsigned long flags;
+};
+
+extern int line6_init_pcm(struct usb_line6 *line6,
+ struct line6_pcm_properties *properties);
+extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
+extern int snd_line6_prepare(struct snd_pcm_substream *substream);
+extern int snd_line6_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params);
+extern int snd_line6_hw_free(struct snd_pcm_substream *substream);
+extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream);
+extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
+extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type);
+extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type);
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 "capture.h"
+#include "driver.h"
+#include "pcm.h"
+#include "playback.h"
+
+/*
+ Software stereo volume control.
+*/
+static void change_volume(struct urb *urb_out, int volume[],
+ int bytes_per_frame)
+{
+ int chn = 0;
+
+ if (volume[0] == 256 && volume[1] == 256)
+ return; /* maximum volume - no change */
+
+ if (bytes_per_frame == 4) {
+ short *p, *buf_end;
+
+ p = (short *)urb_out->transfer_buffer;
+ buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
+
+ for (; p < buf_end; ++p) {
+ int val = (*p * volume[chn & 1]) >> 8;
+ *p = clamp(val, 0x7fff, -0x8000);
+ ++chn;
+ }
+ } else if (bytes_per_frame == 6) {
+ unsigned char *p, *buf_end;
+
+ p = (unsigned char *)urb_out->transfer_buffer;
+ buf_end = p + urb_out->transfer_buffer_length;
+
+ for (; p < buf_end; p += 3) {
+ int val;
+
+ val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
+ val = (val * volume[chn & 1]) >> 8;
+ val = clamp(val, 0x7fffff, -0x800000);
+ p[0] = val;
+ p[1] = val >> 8;
+ p[2] = val >> 16;
+ ++chn;
+ }
+ }
+}
+
+/*
+ Create signal for impulse response test.
+*/
+static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
+ struct urb *urb_out, int bytes_per_frame)
+{
+ int frames = urb_out->transfer_buffer_length / bytes_per_frame;
+
+ if (bytes_per_frame == 4) {
+ int i;
+ short *pi = (short *)line6pcm->prev_fbuf;
+ short *po = (short *)urb_out->transfer_buffer;
+
+ for (i = 0; i < frames; ++i) {
+ po[0] = pi[0];
+ po[1] = 0;
+ pi += 2;
+ po += 2;
+ }
+ } else if (bytes_per_frame == 6) {
+ int i, j;
+ unsigned char *pi = line6pcm->prev_fbuf;
+ unsigned char *po = urb_out->transfer_buffer;
+
+ for (i = 0; i < frames; ++i) {
+ for (j = 0; j < bytes_per_frame / 2; ++j)
+ po[j] = pi[j];
+
+ for (; j < bytes_per_frame; ++j)
+ po[j] = 0;
+
+ pi += bytes_per_frame;
+ po += bytes_per_frame;
+ }
+ }
+ if (--line6pcm->impulse_count <= 0) {
+ ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
+ 1] =
+ line6pcm->impulse_volume;
+ line6pcm->impulse_count = line6pcm->impulse_period;
+ }
+}
+
+/*
+ Add signal to buffer for software monitoring.
+*/
+static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
+ int volume, int bytes_per_frame)
+{
+ if (volume == 0)
+ return; /* zero volume - no change */
+
+ if (bytes_per_frame == 4) {
+ short *pi, *po, *buf_end;
+
+ pi = (short *)signal;
+ po = (short *)urb_out->transfer_buffer;
+ buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
+
+ for (; po < buf_end; ++pi, ++po) {
+ int val = *po + ((*pi * volume) >> 8);
+ *po = clamp(val, 0x7fff, -0x8000);
+ }
+ }
+
+ /*
+ We don't need to handle devices with 6 bytes per frame here
+ since they all support hardware monitoring.
+ */
+}
+
+/*
+ Find a free URB, prepare audio data, and submit URB.
+ must be called in line6pcm->out.lock context
+*/
+static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
+{
+ int index;
+ int i, urb_size, urb_frames;
+ int ret;
+ const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+ const int frame_increment =
+ line6pcm->properties->snd_line6_rates.rats[0].num_min;
+ const int frame_factor =
+ line6pcm->properties->snd_line6_rates.rats[0].den *
+ (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
+ struct urb *urb_out;
+
+ index =
+ find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS);
+
+ if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+ dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+ return -EINVAL;
+ }
+
+ urb_out = line6pcm->out.urbs[index];
+ urb_size = 0;
+
+ for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+ /* compute frame size for given sampling rate */
+ int fsize = 0;
+ struct usb_iso_packet_descriptor *fout =
+ &urb_out->iso_frame_desc[i];
+
+ fsize = line6pcm->prev_fsize;
+ if (fsize == 0) {
+ int n;
+
+ line6pcm->out.count += frame_increment;
+ n = line6pcm->out.count / frame_factor;
+ line6pcm->out.count -= n * frame_factor;
+ fsize = n * bytes_per_frame;
+ }
+
+ fout->offset = urb_size;
+ fout->length = fsize;
+ urb_size += fsize;
+ }
+
+ if (urb_size == 0) {
+ /* can't determine URB size */
+ dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
+ return -EINVAL;
+ }
+
+ urb_frames = urb_size / bytes_per_frame;
+ urb_out->transfer_buffer =
+ line6pcm->out.buffer +
+ index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+ urb_out->transfer_buffer_length = urb_size;
+ urb_out->context = line6pcm;
+
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) &&
+ !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) {
+ struct snd_pcm_runtime *runtime =
+ get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
+
+ if (line6pcm->out.pos + urb_frames > runtime->buffer_size) {
+ /*
+ The transferred area goes over buffer boundary,
+ copy the data to the temp buffer.
+ */
+ int len;
+
+ len = runtime->buffer_size - line6pcm->out.pos;
+
+ if (len > 0) {
+ memcpy(urb_out->transfer_buffer,
+ runtime->dma_area +
+ line6pcm->out.pos * bytes_per_frame,
+ len * bytes_per_frame);
+ memcpy(urb_out->transfer_buffer +
+ len * bytes_per_frame, runtime->dma_area,
+ (urb_frames - len) * bytes_per_frame);
+ } else
+ dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
+ len);
+ } else {
+ memcpy(urb_out->transfer_buffer,
+ runtime->dma_area +
+ line6pcm->out.pos * bytes_per_frame,
+ urb_out->transfer_buffer_length);
+ }
+
+ line6pcm->out.pos += urb_frames;
+ if (line6pcm->out.pos >= runtime->buffer_size)
+ line6pcm->out.pos -= runtime->buffer_size;
+
+ change_volume(urb_out, line6pcm->volume_playback,
+ bytes_per_frame);
+ } else {
+ memset(urb_out->transfer_buffer, 0,
+ urb_out->transfer_buffer_length);
+ }
+
+ spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING);
+ if (line6pcm->prev_fbuf) {
+ if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) {
+ create_impulse_test_signal(line6pcm, urb_out,
+ bytes_per_frame);
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) {
+ line6_capture_copy(line6pcm,
+ urb_out->transfer_buffer,
+ urb_out->
+ transfer_buffer_length);
+ line6_capture_check_period(line6pcm,
+ urb_out->transfer_buffer_length);
+ }
+ } else {
+ if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON)
+ && line6pcm->out.running && line6pcm->in.running)
+ add_monitor_signal(urb_out, line6pcm->prev_fbuf,
+ line6pcm->volume_monitor,
+ bytes_per_frame);
+ }
+ line6pcm->prev_fbuf = NULL;
+ line6pcm->prev_fsize = 0;
+ }
+ spin_unlock(&line6pcm->in.lock);
+
+ ret = usb_submit_urb(urb_out, GFP_ATOMIC);
+
+ if (ret == 0)
+ set_bit(index, &line6pcm->out.active_urbs);
+ else
+ dev_err(line6pcm->line6->ifcdev,
+ "URB out #%d submission failed (%d)\n", index, ret);
+
+ return 0;
+}
+
+/*
+ Submit all currently available playback URBs.
+ must be called in line6pcm->out.lock context
+ */
+int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ ret = submit_audio_out_urb(line6pcm);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ Callback for completed playback URB.
+*/
+static void audio_out_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;
+ struct snd_pcm_substream *substream =
+ get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
+
+#if USE_CLEAR_BUFFER_WORKAROUND
+ memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+#endif
+
+ line6pcm->out.last_frame = urb->start_frame;
+
+ /* find index of URB */
+ for (index = 0; index < LINE6_ISO_BUFFERS; index++)
+ if (urb == line6pcm->out.urbs[index])
+ break;
+
+ if (index >= LINE6_ISO_BUFFERS)
+ return; /* URB has been unlinked asynchronously */
+
+ for (i = 0; i < LINE6_ISO_PACKETS; i++)
+ length += urb->iso_frame_desc[i].length;
+
+ spin_lock_irqsave(&line6pcm->out.lock, flags);
+
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ line6pcm->out.pos_done +=
+ length / line6pcm->properties->bytes_per_frame;
+
+ if (line6pcm->out.pos_done >= runtime->buffer_size)
+ line6pcm->out.pos_done -= runtime->buffer_size;
+ }
+
+ clear_bit(index, &line6pcm->out.active_urbs);
+
+ for (i = 0; i < LINE6_ISO_PACKETS; i++)
+ if (urb->iso_frame_desc[i].status == -EXDEV) {
+ shutdown = 1;
+ break;
+ }
+
+ if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs))
+ shutdown = 1;
+
+ if (!shutdown) {
+ submit_audio_out_urb(line6pcm);
+
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) {
+ line6pcm->out.bytes += length;
+ if (line6pcm->out.bytes >= line6pcm->out.period) {
+ line6pcm->out.bytes %= line6pcm->out.period;
+ spin_unlock(&line6pcm->out.lock);
+ snd_pcm_period_elapsed(substream);
+ spin_lock(&line6pcm->out.lock);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
+}
+
+/* open playback callback */
+static int snd_line6_playback_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);
+
+ err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ (&line6pcm->
+ properties->snd_line6_rates));
+ if (err < 0)
+ return err;
+
+ runtime->hw = line6pcm->properties->snd_line6_playback_hw;
+ return 0;
+}
+
+/* close playback callback */
+static int snd_line6_playback_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/* playback operators */
+struct snd_pcm_ops snd_line6_playback_ops = {
+ .open = snd_line6_playback_open,
+ .close = snd_line6_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_line6_hw_params,
+ .hw_free = snd_line6_hw_free,
+ .prepare = snd_line6_prepare,
+ .trigger = snd_line6_trigger,
+ .pointer = snd_line6_pointer,
+};
+
+int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+ struct usb_line6 *line6 = line6pcm->line6;
+ int i;
+
+ /* create audio URBs and fill in constant values: */
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ struct urb *urb;
+
+ /* URB for audio out: */
+ urb = line6pcm->out.urbs[i] =
+ usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+
+ if (urb == NULL)
+ return -ENOMEM;
+
+ urb->dev = line6->usbdev;
+ urb->pipe =
+ usb_sndisocpipe(line6->usbdev,
+ line6->properties->ep_audio_w &
+ USB_ENDPOINT_NUMBER_MASK);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->start_frame = -1;
+ urb->number_of_packets = LINE6_ISO_PACKETS;
+ urb->interval = LINE6_ISO_INTERVAL;
+ urb->error_count = 0;
+ urb->complete = audio_out_callback;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 PLAYBACK_H
+#define PLAYBACK_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+
+/*
+ * When the TonePort is used with jack in full duplex mode and the outputs are
+ * not connected, the software monitor produces an ugly noise since everything
+ * written to the output buffer (i.e., the input signal) will be repeated in
+ * the next period (sounds like a delay effect). As a workaround, the output
+ * buffer is cleared after the data have been read, but there must be a better
+ * solution. Until one is found, this workaround can be used to fix the
+ * problem.
+ */
+#define USE_CLEAR_BUFFER_WORKAROUND 1
+
+extern struct snd_pcm_ops snd_line6_playback_ops;
+
+extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+#include "usbdefs.h"
+
+/*
+ Locate name in binary program dump
+*/
+#define POD_NAME_OFFSET 0
+#define POD_NAME_LENGTH 16
+
+/*
+ Other constants
+*/
+#define POD_CONTROL_SIZE 0x80
+#define POD_BUFSIZE_DUMPREQ 7
+#define POD_STARTUP_DELAY 1000
+
+/*
+ Stages of POD startup procedure
+*/
+enum {
+ POD_STARTUP_INIT = 1,
+ POD_STARTUP_VERSIONREQ,
+ POD_STARTUP_WORKQUEUE,
+ POD_STARTUP_SETUP,
+ POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
+};
+
+enum {
+ LINE6_BASSPODXT,
+ LINE6_BASSPODXTLIVE,
+ LINE6_BASSPODXTPRO,
+ LINE6_POCKETPOD,
+ LINE6_PODXT,
+ LINE6_PODXTLIVE_POD,
+ LINE6_PODXTPRO,
+};
+
+struct usb_line6_pod {
+ /**
+ Generic Line 6 USB data.
+ */
+ struct usb_line6 line6;
+
+ /**
+ Instrument monitor level.
+ */
+ int monitor_level;
+
+ /**
+ Timer for device initializaton.
+ */
+ struct timer_list startup_timer;
+
+ /**
+ Work handler for device initializaton.
+ */
+ struct work_struct startup_work;
+
+ /**
+ Current progress in startup procedure.
+ */
+ int startup_progress;
+
+ /**
+ Serial number of device.
+ */
+ int serial_number;
+
+ /**
+ Firmware version (x 100).
+ */
+ int firmware_version;
+
+ /**
+ Device ID.
+ */
+ int device_id;
+};
+
+#define POD_SYSEX_CODE 3
+#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
+
+/* *INDENT-OFF* */
+
+enum {
+ POD_SYSEX_SAVE = 0x24,
+ POD_SYSEX_SYSTEM = 0x56,
+ POD_SYSEX_SYSTEMREQ = 0x57,
+ /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
+ POD_SYSEX_STORE = 0x71,
+ POD_SYSEX_FINISH = 0x72,
+ POD_SYSEX_DUMPMEM = 0x73,
+ POD_SYSEX_DUMP = 0x74,
+ POD_SYSEX_DUMPREQ = 0x75
+
+ /* dumps entire internal memory of PODxt Pro */
+ /* POD_SYSEX_DUMPMEM2 = 0x76 */
+};
+
+enum {
+ POD_MONITOR_LEVEL = 0x04,
+ POD_SYSTEM_INVALID = 0x10000
+};
+
+/* *INDENT-ON* */
+
+enum {
+ POD_DUMP_MEMORY = 2
+};
+
+enum {
+ POD_BUSY_READ,
+ POD_BUSY_WRITE,
+ POD_CHANNEL_DIRTY,
+ POD_SAVE_PRESSED,
+ POD_BUSY_MIDISEND
+};
+
+static struct snd_ratden pod_ratden = {
+ .num_min = 78125,
+ .num_max = 78125,
+ .num_step = 1,
+ .den = 2
+};
+
+static struct line6_pcm_properties pod_pcm_properties = {
+ .snd_line6_playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 39062,
+ .rate_max = 39063,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 39062,
+ .rate_max = 39063,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_rates = {
+ .nrats = 1,
+ .rats = &pod_ratden},
+ .bytes_per_frame = POD_BYTES_PER_FRAME
+};
+
+static const char pod_version_header[] = {
+ 0xf2, 0x7e, 0x7f, 0x06, 0x02
+};
+
+/* forward declarations: */
+static void pod_startup2(unsigned long data);
+static void pod_startup3(struct usb_line6_pod *pod);
+
+static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
+ int size)
+{
+ return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
+ size);
+}
+
+/*
+ Process a completely received message.
+*/
+static void line6_pod_process_message(struct usb_line6 *line6)
+{
+ struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+ const unsigned char *buf = pod->line6.buffer_message;
+
+ if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
+ pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
+ pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
+ (int) buf[10];
+ pod_startup3(pod);
+ return;
+ }
+
+ /* Only look for sysex messages from this device */
+ if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
+ buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
+ return;
+ }
+ if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
+ return;
+
+ if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
+ short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
+ ((int)buf[9] << 4) | (int)buf[10];
+ pod->monitor_level = value;
+ }
+}
+
+/*
+ Send system parameter (from integer).
+*/
+static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
+ int code)
+{
+ char *sysex;
+ static const int size = 5;
+
+ sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
+ if (!sysex)
+ return -ENOMEM;
+ sysex[SYSEX_DATA_OFS] = code;
+ sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
+ line6_send_sysex_message(&pod->line6, sysex, size);
+ kfree(sysex);
+ return 0;
+}
+
+/*
+ "read" request on "serial_number" special file.
+*/
+static ssize_t serial_number_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+ struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+ return sprintf(buf, "%d\n", pod->serial_number);
+}
+
+/*
+ "read" request on "firmware_version" special file.
+*/
+static ssize_t firmware_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+ struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+ return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
+ pod->firmware_version % 100);
+}
+
+/*
+ "read" request on "device_id" special file.
+*/
+static ssize_t device_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+ struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+ return sprintf(buf, "%d\n", pod->device_id);
+}
+
+/*
+ POD startup procedure.
+ This is a sequence of functions with special requirements (e.g., must
+ not run immediately after initialization, must not run in interrupt
+ context). After the last one has finished, the device is ready to use.
+*/
+
+static void pod_startup1(struct usb_line6_pod *pod)
+{
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
+
+ /* delay startup procedure: */
+ line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
+ (unsigned long)pod);
+}
+
+static void pod_startup2(unsigned long data)
+{
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
+ struct usb_line6 *line6 = &pod->line6;
+
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
+
+ /* request firmware version: */
+ line6_version_request_async(line6);
+}
+
+static void pod_startup3(struct usb_line6_pod *pod)
+{
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
+
+ /* schedule work for global work queue: */
+ schedule_work(&pod->startup_work);
+}
+
+static void pod_startup4(struct work_struct *work)
+{
+ struct usb_line6_pod *pod =
+ container_of(work, struct usb_line6_pod, startup_work);
+ struct usb_line6 *line6 = &pod->line6;
+
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
+
+ /* serial number: */
+ line6_read_serial_number(&pod->line6, &pod->serial_number);
+
+ /* ALSA audio interface: */
+ snd_card_register(line6->card);
+}
+
+/* POD special files: */
+static DEVICE_ATTR_RO(device_id);
+static DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(serial_number);
+
+/* control info callback */
+static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 65535;
+ return 0;
+}
+
+/* control get callback */
+static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+ ucontrol->value.integer.value[0] = pod->monitor_level;
+ return 0;
+}
+
+/* control put callback */
+static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+ if (ucontrol->value.integer.value[0] == pod->monitor_level)
+ return 0;
+
+ pod->monitor_level = ucontrol->value.integer.value[0];
+ pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
+ POD_MONITOR_LEVEL);
+ return 1;
+}
+
+/* control definition */
+static struct snd_kcontrol_new pod_control_monitor = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Monitor Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_pod_control_monitor_info,
+ .get = snd_pod_control_monitor_get,
+ .put = snd_pod_control_monitor_put
+};
+
+/*
+ POD device disconnected.
+*/
+static void line6_pod_disconnect(struct usb_line6 *line6)
+{
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)line6;
+ struct device *dev = line6->ifcdev;
+
+ /* remove sysfs entries: */
+ device_remove_file(dev, &dev_attr_device_id);
+ device_remove_file(dev, &dev_attr_firmware_version);
+ device_remove_file(dev, &dev_attr_serial_number);
+
+ del_timer_sync(&pod->startup_timer);
+ cancel_work_sync(&pod->startup_work);
+}
+
+/*
+ Create sysfs entries.
+*/
+static int pod_create_files2(struct device *dev)
+{
+ int err;
+
+ err = device_create_file(dev, &dev_attr_device_id);
+ if (err < 0)
+ return err;
+ err = device_create_file(dev, &dev_attr_firmware_version);
+ if (err < 0)
+ return err;
+ err = device_create_file(dev, &dev_attr_serial_number);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+/*
+ Try to init POD device.
+*/
+static int pod_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ int err;
+ struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+
+ line6->process_message = line6_pod_process_message;
+ line6->disconnect = line6_pod_disconnect;
+
+ init_timer(&pod->startup_timer);
+ INIT_WORK(&pod->startup_work, pod_startup4);
+
+ /* create sysfs entries: */
+ err = pod_create_files2(line6->ifcdev);
+ if (err < 0)
+ return err;
+
+ /* initialize MIDI subsystem: */
+ err = line6_init_midi(line6);
+ if (err < 0)
+ return err;
+
+ /* initialize PCM subsystem: */
+ err = line6_init_pcm(line6, &pod_pcm_properties);
+ if (err < 0)
+ return err;
+
+ /* register monitor control: */
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
+ if (err < 0)
+ return err;
+
+ /*
+ When the sound card is registered at this point, the PODxt Live
+ displays "Invalid Code Error 07", so we do it later in the event
+ handler.
+ */
+
+ if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
+ pod->monitor_level = POD_SYSTEM_INVALID;
+
+ /* initiate startup procedure: */
+ pod_startup1(pod);
+ }
+
+ return 0;
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id pod_id_table[] = {
+ { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT },
+ { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE },
+ { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO },
+ { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
+ { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT },
+ { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
+ { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, pod_id_table);
+
+static const struct line6_properties pod_properties_table[] = {
+ [LINE6_BASSPODXT] = {
+ .id = "BassPODxt",
+ .name = "BassPODxt",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_BASSPODXTLIVE] = {
+ .id = "BassPODxtLive",
+ .name = "BassPODxt Live",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_BASSPODXTPRO] = {
+ .id = "BassPODxtPro",
+ .name = "BassPODxt Pro",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_POCKETPOD] = {
+ .id = "PocketPOD",
+ .name = "Pocket POD",
+ .capabilities = LINE6_CAP_CONTROL,
+ .altsetting = 0,
+ .ep_ctrl_r = 0x82,
+ .ep_ctrl_w = 0x02,
+ /* no audio channel */
+ },
+ [LINE6_PODXT] = {
+ .id = "PODxt",
+ .name = "PODxt",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODXTLIVE_POD] = {
+ .id = "PODxtLive",
+ .name = "PODxt Live",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODXTPRO] = {
+ .id = "PODxtPro",
+ .name = "PODxt Pro",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+};
+
+/*
+ Probe USB device.
+*/
+static int pod_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id,
+ &pod_properties_table[id->driver_info],
+ pod_init, sizeof(struct usb_line6_pod));
+}
+
+static struct usb_driver pod_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = pod_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = line6_resume,
+#endif
+ .id_table = pod_id_table,
+};
+
+module_usb_driver(pod_driver);
+
+MODULE_DESCRIPTION("Line 6 POD USB driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Line 6 Pod HD
+ *
+ * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
+ *
+ * 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/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+#include "usbdefs.h"
+
+enum {
+ LINE6_PODHD300,
+ LINE6_PODHD400,
+ LINE6_PODHD500_0,
+ LINE6_PODHD500_1,
+};
+
+struct usb_line6_podhd {
+ /**
+ Generic Line 6 USB data.
+ */
+ struct usb_line6 line6;
+};
+
+#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
+
+static struct snd_ratden podhd_ratden = {
+ .num_min = 48000,
+ .num_max = 48000,
+ .num_step = 1,
+ .den = 1,
+};
+
+static struct line6_pcm_properties podhd_pcm_properties = {
+ .snd_line6_playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_rates = {
+ .nrats = 1,
+ .rats = &podhd_ratden},
+ .bytes_per_frame = PODHD_BYTES_PER_FRAME
+};
+
+/*
+ Try to init POD HD device.
+*/
+static int podhd_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ int err;
+
+ /* initialize MIDI subsystem: */
+ err = line6_init_midi(line6);
+ if (err < 0)
+ return err;
+
+ /* initialize PCM subsystem: */
+ err = line6_init_pcm(line6, &podhd_pcm_properties);
+ if (err < 0)
+ return err;
+
+ /* register USB audio system: */
+ return snd_card_register(line6->card);
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id podhd_id_table[] = {
+ { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 },
+ { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 },
+ { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
+ { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, podhd_id_table);
+
+static const struct line6_properties podhd_properties_table[] = {
+ [LINE6_PODHD300] = {
+ .id = "PODHD300",
+ .name = "POD HD300",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODHD400] = {
+ .id = "PODHD400",
+ .name = "POD HD400",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODHD500_0] = {
+ .id = "PODHD500",
+ .name = "POD HD500",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x81,
+ .ep_ctrl_w = 0x01,
+ .ep_audio_r = 0x86,
+ .ep_audio_w = 0x02,
+ },
+ [LINE6_PODHD500_1] = {
+ .id = "PODHD500",
+ .name = "POD HD500",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x81,
+ .ep_ctrl_w = 0x01,
+ .ep_audio_r = 0x86,
+ .ep_audio_w = 0x02,
+ },
+};
+
+/*
+ Probe USB device.
+*/
+static int podhd_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id,
+ &podhd_properties_table[id->driver_info],
+ podhd_init, sizeof(struct usb_line6_podhd));
+}
+
+static struct usb_driver podhd_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = podhd_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = line6_resume,
+#endif
+ .id_table = podhd_id_table,
+};
+
+module_usb_driver(podhd_driver);
+
+MODULE_DESCRIPTION("Line 6 PODHD USB driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef DRIVER_REVISION
+/* current subversion revision */
+#define DRIVER_REVISION " (904)"
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ * Emil Myhrman (emil.myhrman@gmail.com)
+ *
+ * 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/wait.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+#include "usbdefs.h"
+
+enum line6_device_type {
+ LINE6_GUITARPORT,
+ LINE6_PODSTUDIO_GX,
+ LINE6_PODSTUDIO_UX1,
+ LINE6_PODSTUDIO_UX2,
+ LINE6_TONEPORT_GX,
+ LINE6_TONEPORT_UX1,
+ LINE6_TONEPORT_UX2,
+};
+
+struct usb_line6_toneport;
+
+struct toneport_led {
+ struct led_classdev dev;
+ char name[64];
+ struct usb_line6_toneport *toneport;
+ bool registered;
+};
+
+struct usb_line6_toneport {
+ /**
+ Generic Line 6 USB data.
+ */
+ struct usb_line6 line6;
+
+ /**
+ Source selector.
+ */
+ int source;
+
+ /**
+ Serial number of device.
+ */
+ int serial_number;
+
+ /**
+ Firmware version (x 100).
+ */
+ int firmware_version;
+
+ /**
+ Timer for delayed PCM startup.
+ */
+ struct timer_list timer;
+
+ /**
+ Device type.
+ */
+ enum line6_device_type type;
+
+ /* LED instances */
+ struct toneport_led leds[2];
+};
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
+
+#define TONEPORT_PCM_DELAY 1
+
+static struct snd_ratden toneport_ratden = {
+ .num_min = 44100,
+ .num_max = 44100,
+ .num_step = 1,
+ .den = 1
+};
+
+static struct line6_pcm_properties toneport_pcm_properties = {
+ .snd_line6_playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_rates = {
+ .nrats = 1,
+ .rats = &toneport_ratden},
+ .bytes_per_frame = 4
+};
+
+static const struct {
+ const char *name;
+ int code;
+} toneport_source_info[] = {
+ {"Microphone", 0x0a01},
+ {"Line", 0x0801},
+ {"Instrument", 0x0b01},
+ {"Inst & Mic", 0x0901}
+};
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
+{
+ int ret;
+
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* monitor info callback */
+static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 256;
+ return 0;
+}
+
+/* monitor get callback */
+static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
+ return 0;
+}
+
+/* monitor put callback */
+static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ int err;
+
+ if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
+ return 0;
+
+ line6pcm->volume_monitor = ucontrol->value.integer.value[0];
+
+ if (line6pcm->volume_monitor > 0) {
+ err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR);
+ if (err < 0) {
+ line6pcm->volume_monitor = 0;
+ line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
+ return err;
+ }
+ } else {
+ line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
+ }
+
+ return 1;
+}
+
+/* source info callback */
+static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ const int size = ARRAY_SIZE(toneport_source_info);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = size;
+
+ if (uinfo->value.enumerated.item >= size)
+ uinfo->value.enumerated.item = size - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ toneport_source_info[uinfo->value.enumerated.item].name);
+
+ return 0;
+}
+
+/* source get callback */
+static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_toneport *toneport =
+ (struct usb_line6_toneport *)line6pcm->line6;
+ ucontrol->value.enumerated.item[0] = toneport->source;
+ return 0;
+}
+
+/* source put callback */
+static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_toneport *toneport =
+ (struct usb_line6_toneport *)line6pcm->line6;
+ unsigned int source;
+
+ source = ucontrol->value.enumerated.item[0];
+ if (source >= ARRAY_SIZE(toneport_source_info))
+ return -EINVAL;
+ if (source == toneport->source)
+ return 0;
+
+ toneport->source = source;
+ toneport_send_cmd(toneport->line6.usbdev,
+ toneport_source_info[source].code, 0x0000);
+ return 1;
+}
+
+static void toneport_start_pcm(unsigned long arg)
+{
+ struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
+ struct usb_line6 *line6 = &toneport->line6;
+
+ line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR);
+}
+
+/* control definition */
+static struct snd_kcontrol_new toneport_control_monitor = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Monitor Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_toneport_monitor_info,
+ .get = snd_toneport_monitor_get,
+ .put = snd_toneport_monitor_put
+};
+
+/* source selector definition */
+static struct snd_kcontrol_new toneport_control_source = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Source",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_toneport_source_info,
+ .get = snd_toneport_source_get,
+ .put = snd_toneport_source_put
+};
+
+/*
+ For the led on Guitarport.
+ Brightness goes from 0x00 to 0x26. Set a value above this to have led
+ blink.
+ (void cmd_0x02(byte red, byte green)
+*/
+
+static bool toneport_has_led(enum line6_device_type type)
+{
+ return
+ (type == LINE6_GUITARPORT) ||
+ (type == LINE6_TONEPORT_GX);
+ /* add your device here if you are missing support for the LEDs */
+}
+
+static const char * const led_colors[2] = { "red", "green" };
+static const int led_init_vals[2] = { 0x00, 0x26 };
+
+static void toneport_update_led(struct usb_line6_toneport *toneport)
+{
+ toneport_send_cmd(toneport->line6.usbdev,
+ (toneport->leds[0].dev.brightness << 8) | 0x0002,
+ toneport->leds[1].dev.brightness);
+}
+
+static void toneport_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct toneport_led *leds =
+ container_of(led_cdev, struct toneport_led, dev);
+ toneport_update_led(leds->toneport);
+}
+
+static int toneport_init_leds(struct usb_line6_toneport *toneport)
+{
+ struct device *dev = &toneport->line6.usbdev->dev;
+ int i, err;
+
+ for (i = 0; i < 2; i++) {
+ struct toneport_led *led = &toneport->leds[i];
+ struct led_classdev *leddev = &led->dev;
+
+ led->toneport = toneport;
+ snprintf(led->name, sizeof(led->name), "%s::%s",
+ dev_name(dev), led_colors[i]);
+ leddev->name = led->name;
+ leddev->brightness = led_init_vals[i];
+ leddev->max_brightness = 0x26;
+ leddev->brightness_set = toneport_led_brightness_set;
+ err = led_classdev_register(dev, leddev);
+ if (err)
+ return err;
+ led->registered = true;
+ }
+
+ return 0;
+}
+
+static void toneport_remove_leds(struct usb_line6_toneport *toneport)
+{
+ struct toneport_led *led;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ led = &toneport->leds[i];
+ if (!led->registered)
+ break;
+ led_classdev_unregister(&led->dev);
+ led->registered = false;
+ }
+}
+
+/*
+ Setup Toneport device.
+*/
+static void toneport_setup(struct usb_line6_toneport *toneport)
+{
+ int ticks;
+ struct usb_line6 *line6 = &toneport->line6;
+ struct usb_device *usbdev = line6->usbdev;
+
+ /* sync time on device with host: */
+ ticks = (int)get_seconds();
+ line6_write_data(line6, 0x80c6, &ticks, 4);
+
+ /* enable device: */
+ toneport_send_cmd(usbdev, 0x0301, 0x0000);
+
+ /* initialize source select: */
+ switch (toneport->type) {
+ case LINE6_TONEPORT_UX1:
+ case LINE6_TONEPORT_UX2:
+ case LINE6_PODSTUDIO_UX1:
+ case LINE6_PODSTUDIO_UX2:
+ toneport_send_cmd(usbdev,
+ toneport_source_info[toneport->source].code,
+ 0x0000);
+ default:
+ break;
+ }
+
+ if (toneport_has_led(toneport->type))
+ toneport_update_led(toneport);
+
+ mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
+}
+
+/*
+ Toneport device disconnected.
+*/
+static void line6_toneport_disconnect(struct usb_line6 *line6)
+{
+ struct usb_line6_toneport *toneport =
+ (struct usb_line6_toneport *)line6;
+
+ del_timer_sync(&toneport->timer);
+
+ if (toneport_has_led(toneport->type))
+ toneport_remove_leds(toneport);
+}
+
+
+/*
+ Try to init Toneport device.
+*/
+static int toneport_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ int err;
+ struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
+
+ toneport->type = id->driver_info;
+ setup_timer(&toneport->timer, toneport_start_pcm,
+ (unsigned long)toneport);
+
+ line6->disconnect = line6_toneport_disconnect;
+
+ /* initialize PCM subsystem: */
+ err = line6_init_pcm(line6, &toneport_pcm_properties);
+ if (err < 0)
+ return err;
+
+ /* register monitor control: */
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&toneport_control_monitor,
+ line6->line6pcm));
+ if (err < 0)
+ return err;
+
+ /* register source select control: */
+ switch (toneport->type) {
+ case LINE6_TONEPORT_UX1:
+ case LINE6_TONEPORT_UX2:
+ case LINE6_PODSTUDIO_UX1:
+ case LINE6_PODSTUDIO_UX2:
+ err =
+ snd_ctl_add(line6->card,
+ snd_ctl_new1(&toneport_control_source,
+ line6->line6pcm));
+ if (err < 0)
+ return err;
+
+ default:
+ break;
+ }
+
+ line6_read_serial_number(line6, &toneport->serial_number);
+ line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
+
+ if (toneport_has_led(toneport->type)) {
+ err = toneport_init_leds(toneport);
+ if (err < 0)
+ return err;
+ }
+
+ toneport_setup(toneport);
+
+ /* register audio system: */
+ return snd_card_register(line6->card);
+}
+
+#ifdef CONFIG_PM
+/*
+ Resume Toneport device after reset.
+*/
+static int toneport_reset_resume(struct usb_interface *interface)
+{
+ toneport_setup(usb_get_intfdata(interface));
+ return line6_resume(interface);
+}
+#endif
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id toneport_id_table[] = {
+ { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT },
+ { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX },
+ { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 },
+ { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
+ { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX },
+ { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 },
+ { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, toneport_id_table);
+
+static const struct line6_properties toneport_properties_table[] = {
+ [LINE6_GUITARPORT] = {
+ .id = "GuitarPort",
+ .name = "GuitarPort",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODSTUDIO_GX] = {
+ .id = "PODStudioGX",
+ .name = "POD Studio GX",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODSTUDIO_UX1] = {
+ .id = "PODStudioUX1",
+ .name = "POD Studio UX1",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODSTUDIO_UX2] = {
+ .id = "PODStudioUX2",
+ .name = "POD Studio UX2",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* defaults to 44.1kHz, 16-bit */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_TONEPORT_GX] = {
+ .id = "TonePortGX",
+ .name = "TonePort GX",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_TONEPORT_UX1] = {
+ .id = "TonePortUX1",
+ .name = "TonePort UX1",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_TONEPORT_UX2] = {
+ .id = "TonePortUX2",
+ .name = "TonePort UX2",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* defaults to 44.1kHz, 16-bit */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+};
+
+/*
+ Probe USB device.
+*/
+static int toneport_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id,
+ &toneport_properties_table[id->driver_info],
+ toneport_init, sizeof(struct usb_line6_toneport));
+}
+
+static struct usb_driver toneport_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = toneport_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = toneport_reset_resume,
+#endif
+ .id_table = toneport_id_table,
+};
+
+module_usb_driver(toneport_driver);
+
+MODULE_DESCRIPTION("TonePort USB driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2005-2008 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 USBDEFS_H
+#define USBDEFS_H
+
+#define USB_INTERVALS_PER_SECOND 1000
+
+/* device supports settings parameter via USB */
+#define LINE6_CAP_CONTROL (1 << 0)
+/* device supports PCM input/output via USB */
+#define LINE6_CAP_PCM (1 << 1)
+/* device support hardware monitoring */
+#define LINE6_CAP_HWMON (1 << 2)
+
+#define LINE6_FALLBACK_INTERVAL 10
+#define LINE6_FALLBACK_MAXPACKETSIZE 16
+
+#endif
--- /dev/null
+/*
+ * Line 6 Linux USB driver
+ *
+ * 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 <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <sound/core.h>
+
+#include "driver.h"
+#include "usbdefs.h"
+
+#define VARIAX_STARTUP_DELAY1 1000
+#define VARIAX_STARTUP_DELAY3 100
+#define VARIAX_STARTUP_DELAY4 100
+
+/*
+ Stages of Variax startup procedure
+*/
+enum {
+ VARIAX_STARTUP_INIT = 1,
+ VARIAX_STARTUP_VERSIONREQ,
+ VARIAX_STARTUP_WAIT,
+ VARIAX_STARTUP_ACTIVATE,
+ VARIAX_STARTUP_WORKQUEUE,
+ VARIAX_STARTUP_SETUP,
+ VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
+};
+
+enum {
+ LINE6_PODXTLIVE_VARIAX,
+ LINE6_VARIAX
+};
+
+struct usb_line6_variax {
+ /**
+ Generic Line 6 USB data.
+ */
+ struct usb_line6 line6;
+
+ /**
+ Buffer for activation code.
+ */
+ unsigned char *buffer_activate;
+
+ /**
+ Handler for device initializaton.
+ */
+ struct work_struct startup_work;
+
+ /**
+ Timers for device initializaton.
+ */
+ struct timer_list startup_timer1;
+ struct timer_list startup_timer2;
+
+ /**
+ Current progress in startup procedure.
+ */
+ int startup_progress;
+};
+
+#define VARIAX_OFFSET_ACTIVATE 7
+
+/*
+ This message is sent by the device during initialization and identifies
+ the connected guitar version.
+*/
+static const char variax_init_version[] = {
+ 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
+ 0x07, 0x00, 0x00, 0x00
+};
+
+/*
+ This message is the last one sent by the device during initialization.
+*/
+static const char variax_init_done[] = {
+ 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
+};
+
+static const char variax_activate[] = {
+ 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
+ 0xf7
+};
+
+/* forward declarations: */
+static void variax_startup2(unsigned long data);
+static void variax_startup4(unsigned long data);
+static void variax_startup5(unsigned long data);
+
+static void variax_activate_async(struct usb_line6_variax *variax, int a)
+{
+ variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
+ line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
+ sizeof(variax_activate));
+}
+
+/*
+ Variax startup procedure.
+ This is a sequence of functions with special requirements (e.g., must
+ not run immediately after initialization, must not run in interrupt
+ context). After the last one has finished, the device is ready to use.
+*/
+
+static void variax_startup1(struct usb_line6_variax *variax)
+{
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
+
+ /* delay startup procedure: */
+ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+ variax_startup2, (unsigned long)variax);
+}
+
+static void variax_startup2(unsigned long data)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+ struct usb_line6 *line6 = &variax->line6;
+
+ /* schedule another startup procedure until startup is complete: */
+ if (variax->startup_progress >= VARIAX_STARTUP_LAST)
+ return;
+
+ variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
+ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+ variax_startup2, (unsigned long)variax);
+
+ /* request firmware version: */
+ line6_version_request_async(line6);
+}
+
+static void variax_startup3(struct usb_line6_variax *variax)
+{
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
+
+ /* delay startup procedure: */
+ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
+ variax_startup4, (unsigned long)variax);
+}
+
+static void variax_startup4(unsigned long data)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+ CHECK_STARTUP_PROGRESS(variax->startup_progress,
+ VARIAX_STARTUP_ACTIVATE);
+
+ /* activate device: */
+ variax_activate_async(variax, 1);
+ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
+ variax_startup5, (unsigned long)variax);
+}
+
+static void variax_startup5(unsigned long data)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+ CHECK_STARTUP_PROGRESS(variax->startup_progress,
+ VARIAX_STARTUP_WORKQUEUE);
+
+ /* schedule work for global work queue: */
+ schedule_work(&variax->startup_work);
+}
+
+static void variax_startup6(struct work_struct *work)
+{
+ struct usb_line6_variax *variax =
+ container_of(work, struct usb_line6_variax, startup_work);
+
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
+
+ /* ALSA audio interface: */
+ snd_card_register(variax->line6.card);
+}
+
+/*
+ Process a completely received message.
+*/
+static void line6_variax_process_message(struct usb_line6 *line6)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+ const unsigned char *buf = variax->line6.buffer_message;
+
+ switch (buf[0]) {
+ case LINE6_RESET:
+ dev_info(variax->line6.ifcdev, "VARIAX reset\n");
+ break;
+
+ case LINE6_SYSEX_BEGIN:
+ if (memcmp(buf + 1, variax_init_version + 1,
+ sizeof(variax_init_version) - 1) == 0) {
+ variax_startup3(variax);
+ } else if (memcmp(buf + 1, variax_init_done + 1,
+ sizeof(variax_init_done) - 1) == 0) {
+ /* notify of complete initialization: */
+ variax_startup4((unsigned long)variax);
+ }
+ break;
+ }
+}
+
+/*
+ Variax destructor.
+*/
+static void line6_variax_disconnect(struct usb_line6 *line6)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
+
+ del_timer(&variax->startup_timer1);
+ del_timer(&variax->startup_timer2);
+ cancel_work_sync(&variax->startup_work);
+
+ kfree(variax->buffer_activate);
+}
+
+/*
+ Try to init workbench device.
+*/
+static int variax_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+ int err;
+
+ line6->process_message = line6_variax_process_message;
+ line6->disconnect = line6_variax_disconnect;
+
+ init_timer(&variax->startup_timer1);
+ init_timer(&variax->startup_timer2);
+ INIT_WORK(&variax->startup_work, variax_startup6);
+
+ /* initialize USB buffers: */
+ variax->buffer_activate = kmemdup(variax_activate,
+ sizeof(variax_activate), GFP_KERNEL);
+
+ if (variax->buffer_activate == NULL)
+ return -ENOMEM;
+
+ /* initialize MIDI subsystem: */
+ err = line6_init_midi(&variax->line6);
+ if (err < 0)
+ return err;
+
+ /* initiate startup procedure: */
+ variax_startup1(variax);
+ return 0;
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id variax_id_table[] = {
+ { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
+ { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, variax_id_table);
+
+static const struct line6_properties variax_properties_table[] = {
+ [LINE6_PODXTLIVE_VARIAX] = {
+ .id = "PODxtLive",
+ .name = "PODxt Live",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x86,
+ .ep_ctrl_w = 0x05,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_VARIAX] = {
+ .id = "Variax",
+ .name = "Variax Workbench",
+ .capabilities = LINE6_CAP_CONTROL,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x82,
+ .ep_ctrl_w = 0x01,
+ /* no audio channel */
+ }
+};
+
+/*
+ Probe USB device.
+*/
+static int variax_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id,
+ &variax_properties_table[id->driver_info],
+ variax_init, sizeof(struct usb_line6_variax));
+}
+
+static struct usb_driver variax_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = variax_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = line6_resume,
+#endif
+ .id_table = variax_id_table,
+};
+
+module_usb_driver(variax_driver);
+
+MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_LICENSE("GPL");
umidi->iface = iface;
umidi->quirk = quirk;
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
- init_timer(&umidi->error_timer);
spin_lock_init(&umidi->disc_lock);
init_rwsem(&umidi->disc_rwsem);
mutex_init(&umidi->mutex);
umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
le16_to_cpu(umidi->dev->descriptor.idProduct));
- umidi->error_timer.function = snd_usbmidi_error_timer;
- umidi->error_timer.data = (unsigned long)umidi;
+ setup_timer(&umidi->error_timer, snd_usbmidi_error_timer,
+ (unsigned long)umidi);
/* detect the endpoint(s) to use */
memset(endpoints, 0, sizeof(endpoints));
}
},
+{
+ /* Akai MPC Element */
+ USB_DEVICE(0x09e8, 0x0021),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = & (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+
/* TerraTec devices */
{
USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
-/*
- * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+#ifndef __USB_STREAM_H
+#define __USB_STREAM_H
-#define USB_STREAM_INTERFACE_VERSION 2
-
-#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
- _IOW('H', 0x90, struct usb_stream_config)
-
-struct usb_stream_packet {
- unsigned offset;
- unsigned length;
-};
-
-
-struct usb_stream_config {
- unsigned version;
- unsigned sample_rate;
- unsigned period_frames;
- unsigned frame_size;
-};
-
-struct usb_stream {
- struct usb_stream_config cfg;
- unsigned read_size;
- unsigned write_size;
-
- int period_size;
-
- unsigned state;
-
- int idle_insize;
- int idle_outsize;
- int sync_packet;
- unsigned insize_done;
- unsigned periods_done;
- unsigned periods_polled;
-
- struct usb_stream_packet outpacket[2];
- unsigned inpackets;
- unsigned inpacket_head;
- unsigned inpacket_split;
- unsigned inpacket_split_at;
- unsigned next_inpacket_split;
- unsigned next_inpacket_split_at;
- struct usb_stream_packet inpacket[0];
-};
-
-enum usb_stream_state {
- usb_stream_invalid,
- usb_stream_stopped,
- usb_stream_sync0,
- usb_stream_sync1,
- usb_stream_ready,
- usb_stream_running,
- usb_stream_xrun,
-};
-
-#if __KERNEL__
+#include <uapi/sound/usb_stream.h>
#define USB_STREAM_NURBS 4
#define USB_STREAM_URBDEPTH 4
int usb_stream_start(struct usb_stream_kernel *);
void usb_stream_stop(struct usb_stream_kernel *);
-
-#endif
+#endif /* __USB_STREAM_H */