Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
December 2008
- 90 participants
- 163 discussions
Hi,
the patch below (to the latest sound git tree) adds the extra delay
count for USB-audio driver. This change will appear as the return
value of snd_pcm_delay().
Could you check whether it's appropriate behavior you've wanted?
thanks,
Takashi
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 40c5a6f..dcbdc60 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -269,6 +269,7 @@ struct snd_pcm_runtime {
snd_pcm_uframes_t avail_max;
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time*/
+ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
/* -- HW params -- */
snd_pcm_access_t access; /* access mode */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index e61e125..df7c3fa 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -597,14 +597,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
status->avail = snd_pcm_playback_avail(runtime);
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
- runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+ runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
status->delay = runtime->buffer_size - status->avail;
- else
+ status->delay += runtime->delay;
+ } else
status->delay = 0;
} else {
status->avail = snd_pcm_capture_avail(runtime);
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- status->delay = status->avail;
+ status->delay = status->avail + runtime->delay;
else
status->delay = 0;
}
@@ -2423,6 +2424,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
n = snd_pcm_playback_hw_avail(runtime);
else
n = snd_pcm_capture_avail(runtime);
+ n += runtime->delay;
break;
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 6e70ba4..7d5a103 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -629,6 +629,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
subs->hwptr_done += offs;
if (subs->hwptr_done >= runtime->buffer_size)
subs->hwptr_done -= runtime->buffer_size;
+ runtime->delay += offs;
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = offs * stride;
if (period_elapsed)
@@ -638,12 +639,20 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
/*
* process after playback data complete
- * - nothing to do
+ * - decrease the delay count again
*/
static int retire_playback_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
+ unsigned long flags;
+ int stride = runtime->frame_bits >> 3;
+ int processed = urb->transfer_buffer_length / stride;
+
+ spin_lock_irqsave(&subs->lock, flags);
+ if (processed > runtime->delay)
+ runtime->delay -= processed;
+ spin_unlock_irqrestore(&subs->lock, flags);
return 0;
}
@@ -1542,6 +1551,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
subs->hwptr_done = 0;
subs->transfer_done = 0;
subs->phase = 0;
+ runtime->delay = 0;
/* clear urbs (to be sure) */
deactivate_urbs(subs, 0, 1);
2
6
Hello,
I have a media application that uses alsa as its sound renderer. It has worked on numerous systems without any problems until I came across a mandriva distro that bundles with PulseAudio. The alsa pulseaudio plugin is installed correctly, however I am having weird problems.
When I am setting up my hw params, and I call snd_pcm_hw_params_any(), I get an "Operation not permitted" error. I am not sure why this is happening, anyone else see this before? I am using pulseaudio version 0.9.9 and alsa 1.0.16.
Thanks in advance!
_________________________________________________________________
Be the filmmaker you always wanted to be—learn how to burn a DVD with Windows®.
http://clk.atdmt.com/MRT/go/108588797/direct/01/
4
8
Hi,
since my original diet plan for HD-audio driver isn't going well
as expected, I decided the traditional strategy: divide and conquer.
The below is the preliminary patch for modularizing snd-hda-intel.
Now the codec-specific codes are split into several modules, and
loaded automatically on demand.
The patch is against the latest sound.git tree:
git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
It's also included in the recent sound-unstable tree, too
(topic/hda-modularize branch):
git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-unstable-2.6.git
A known issue is that "alsasound stop" may not work with this because
of the explicit module refcount without dependency. But it's a script
problem, basically. The similar problem must be there for snd-aoa,
for example, too.
Let me know if you see any other issues.
thanks,
Takashi
===
From 1289e9e8b42f973f2ab39e5f4f2239ff826c27e9 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai(a)suse.de>
Date: Thu, 27 Nov 2008 15:47:11 +0100
Subject: [PATCH] ALSA: hda - Modularize HD-audio driver
Split the monolithc HD-audio driver into several pieces:
- snd-hda-intel HD-audio PCI controller driver; loaded via udev
- snd-hda-codec HD-audio codec bus driver
- snd-hda-codec-* Specific HD-audio codec drivers
When built as modules, snd-hda-codec (that is invoked by snd-hda-intel)
looks up the codec vendor ID and loads the corresponding codec module
automatically via request_module().
When built in a kernel, each codec drivers are statically hooked up
before probing the PCI.
This patch adds appropriate EXPORT_SYMBOL_GPL()'s and the module
information for each driver, and driver-linking codes between
codec-bus and codec drivers.
TODO:
- Avoid EXPORT_SYMBOL*() when built-in kernel
- Restore __devinit appropriately depending on the condition
Signed-off-by: Takashi Iwai <tiwai(a)suse.de>
---
sound/pci/hda/Kconfig | 50 +++++++++++
sound/pci/hda/Makefile | 77 ++++++++++++----
sound/pci/hda/hda_beep.c | 2 +
sound/pci/hda/hda_codec.c | 187 ++++++++++++++++++++++++++++++---------
sound/pci/hda/hda_codec.h | 11 +++
sound/pci/hda/hda_generic.c | 1 +
sound/pci/hda/hda_hwdep.c | 2 +-
sound/pci/hda/hda_patch.h | 24 -----
sound/pci/hda/patch_analog.c | 26 +++++-
sound/pci/hda/patch_atihdmi.c | 31 ++++++-
sound/pci/hda/patch_cmedia.c | 27 +++++-
sound/pci/hda/patch_conexant.c | 28 ++++++-
sound/pci/hda/patch_intelhdmi.c | 30 ++++++-
sound/pci/hda/patch_nvhdmi.c | 27 +++++-
sound/pci/hda/patch_realtek.c | 26 +++++-
sound/pci/hda/patch_si3054.c | 35 +++++++-
sound/pci/hda/patch_sigmatel.c | 27 +++++-
sound/pci/hda/patch_via.c | 26 +++++-
18 files changed, 528 insertions(+), 109 deletions(-)
delete mode 100644 sound/pci/hda/hda_patch.h
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 7c60f1a..717040a 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -46,6 +46,11 @@ config SND_HDA_CODEC_REALTEK
Say Y here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-realtek.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_ANALOG
bool "Build Analog Device HD-audio codec support"
default y
@@ -53,6 +58,11 @@ config SND_HDA_CODEC_ANALOG
Say Y here to include Analog Device HD-audio codec support in
snd-hda-intel driver, such as AD1986A.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-analog.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_SIGMATEL
bool "Build IDT/Sigmatel HD-audio codec support"
default y
@@ -60,6 +70,11 @@ config SND_HDA_CODEC_SIGMATEL
Say Y here to include IDT (Sigmatel) HD-audio codec support in
snd-hda-intel driver, such as STAC9200.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-idt.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_VIA
bool "Build VIA HD-audio codec support"
default y
@@ -67,6 +82,11 @@ config SND_HDA_CODEC_VIA
Say Y here to include VIA HD-audio codec support in
snd-hda-intel driver, such as VT1708.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-via.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_ATIHDMI
bool "Build ATI HDMI HD-audio codec support"
default y
@@ -74,6 +94,11 @@ config SND_HDA_CODEC_ATIHDMI
Say Y here to include ATI HDMI HD-audio codec support in
snd-hda-intel driver, such as ATI RS600 HDMI.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-atihdmi.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_NVHDMI
bool "Build NVIDIA HDMI HD-audio codec support"
default y
@@ -81,6 +106,11 @@ config SND_HDA_CODEC_NVHDMI
Say Y here to include NVIDIA HDMI HD-audio codec support in
snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-nvhdmi.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_INTELHDMI
bool "Build INTEL HDMI HD-audio codec support"
default y
@@ -88,6 +118,11 @@ config SND_HDA_CODEC_INTELHDMI
Say Y here to include INTEL HDMI HD-audio codec support in
snd-hda-intel driver, such as Eaglelake integrated HDMI.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-intelhdmi.
+ This module is automatically loaded at probing.
+
config SND_HDA_ELD
def_bool y
depends on SND_HDA_CODEC_INTELHDMI
@@ -99,6 +134,11 @@ config SND_HDA_CODEC_CONEXANT
Say Y here to include Conexant HD-audio codec support in
snd-hda-intel driver, such as CX20549.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-conexant.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_CMEDIA
bool "Build C-Media HD-audio codec support"
default y
@@ -106,6 +146,11 @@ config SND_HDA_CODEC_CMEDIA
Say Y here to include C-Media HD-audio codec support in
snd-hda-intel driver, such as CMI9880.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-cmedia.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_SI3054
bool "Build Silicon Labs 3054 HD-modem codec support"
default y
@@ -113,6 +158,11 @@ config SND_HDA_CODEC_SI3054
Say Y here to include Silicon Labs 3054 HD-modem codec
(and compatibles) support in snd-hda-intel driver.
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-si3054.
+ This module is automatically loaded at probing.
+
config SND_HDA_GENERIC
bool "Enable generic HD-audio codec parser"
default y
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 6daf5fd..50f9d09 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,22 +1,59 @@
-snd-hda-intel-y := hda_intel.o
-# since snd-hda-intel is the only driver using hda-codec,
-# merge it into a single module although it was originally
-# designed to be individual modules
-snd-hda-intel-y += hda_codec.o
-snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o
-snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
-snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
-snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o
+snd-hda-intel-objs := hda_intel.o
+snd-hda-codec-y := hda_codec.o
+snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
+snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
+# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
+snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
+snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
+
+snd-hda-codec-realtek-objs := patch_realtek.o
+snd-hda-codec-cmedia-objs := patch_cmedia.o
+snd-hda-codec-analog-objs := patch_analog.o
+snd-hda-codec-idt-objs := patch_sigmatel.o
+snd-hda-codec-si3054-objs := patch_si3054.o
+snd-hda-codec-atihdmi-objs := patch_atihdmi.o
+snd-hda-codec-conexant-objs := patch_conexant.o
+snd-hda-codec-via-objs := patch_via.o
+snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o
+snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o hda_eld.o
+
+# common driver
+obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
+
+# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans)
+ifdef CONFIG_SND_HDA_CODEC_REALTEK
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_CMEDIA
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_ANALOG
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_SI3054
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_CONEXANT
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_VIA
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+endif
+
+# this must be the last entry after codec drivers;
+# otherwise the codec patches won't be hooked before the PCI probe
+# when built in kernel
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 3ecd7e7..e6cc946 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -128,6 +128,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device);
void snd_hda_detach_beep_device(struct hda_codec *codec)
{
@@ -140,3 +141,4 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
kfree(beep);
}
}
+EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 1cb85b7..4aa7b1b 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -31,7 +31,6 @@
#include <sound/initval.h>
#include "hda_local.h"
#include <sound/hda_hwdep.h>
-#include "hda_patch.h" /* codec presets */
/*
* vendor / preset table
@@ -62,39 +61,26 @@ static struct hda_vendor_id hda_vendor_ids[] = {
{} /* terminator */
};
-static const struct hda_codec_preset *hda_preset_tables[] = {
-#ifdef CONFIG_SND_HDA_CODEC_REALTEK
- snd_hda_preset_realtek,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_CMEDIA
- snd_hda_preset_cmedia,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_ANALOG
- snd_hda_preset_analog,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
- snd_hda_preset_sigmatel,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_SI3054
- snd_hda_preset_si3054,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
- snd_hda_preset_atihdmi,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_CONEXANT
- snd_hda_preset_conexant,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_VIA
- snd_hda_preset_via,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
- snd_hda_preset_nvhdmi,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
- snd_hda_preset_intelhdmi,
-#endif
- NULL
-};
+static DEFINE_MUTEX(preset_mutex);
+static LIST_HEAD(hda_preset_tables);
+
+int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
+{
+ mutex_lock(&preset_mutex);
+ list_add_tail(&preset->list, &hda_preset_tables);
+ mutex_unlock(&preset_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
+
+int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
+{
+ mutex_lock(&preset_mutex);
+ list_del(&preset->list);
+ mutex_unlock(&preset_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset);
#ifdef CONFIG_SND_HDA_POWER_SAVE
static void hda_power_work(struct work_struct *work);
@@ -128,6 +114,7 @@ const char *snd_hda_get_jack_location(u32 cfg)
}
return "UNKNOWN";
}
+EXPORT_SYMBOL_GPL(snd_hda_get_jack_location);
const char *snd_hda_get_jack_connectivity(u32 cfg)
{
@@ -135,6 +122,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg)
return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3];
}
+EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity);
const char *snd_hda_get_jack_type(u32 cfg)
{
@@ -148,6 +136,7 @@ const char *snd_hda_get_jack_type(u32 cfg)
return jack_types[(cfg & AC_DEFCFG_DEVICE)
>> AC_DEFCFG_DEVICE_SHIFT];
}
+EXPORT_SYMBOL_GPL(snd_hda_get_jack_type);
/*
* Compose a 32bit command word to be sent to the HD-audio controller
@@ -196,6 +185,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
snd_hda_power_down(codec);
return res;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_read);
/**
* snd_hda_codec_write - send a single command without waiting for response
@@ -224,6 +214,7 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
snd_hda_power_down(codec);
return err;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_write);
/**
* snd_hda_sequence_write - sequence writes
@@ -238,6 +229,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
for (; seq->nid; seq++)
snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
}
+EXPORT_SYMBOL_GPL(snd_hda_sequence_write);
/**
* snd_hda_get_sub_nodes - get the range of sub nodes
@@ -259,6 +251,7 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
*start_id = (parm >> 16) & 0x7fff;
return (int)(parm & 0x7fff);
}
+EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes);
/**
* snd_hda_get_connections - get connection list
@@ -347,6 +340,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
}
return conns;
}
+EXPORT_SYMBOL_GPL(snd_hda_get_connections);
/**
@@ -381,6 +375,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event);
/*
* process queued unsolicited events
@@ -482,7 +477,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device)
*
* Returns 0 if successful, or a negative error code.
*/
-int __devinit snd_hda_bus_new(struct snd_card *card,
+int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
const struct hda_bus_template *temp,
struct hda_bus **busp)
{
@@ -526,6 +521,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
*busp = bus;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_bus_new);
#ifdef CONFIG_SND_HDA_GENERIC
#define is_generic_config(codec) \
@@ -534,19 +530,33 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
#define is_generic_config(codec) 0
#endif
+#ifdef CONFIG_SND_HDA_INTEL_MODULE
+#define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */
+#else
+#define HDA_MODREQ_MAX_COUNT 0
+#endif
+
/*
* find a matching codec preset
*/
static const struct hda_codec_preset *
find_codec_preset(struct hda_codec *codec)
{
- const struct hda_codec_preset **tbl, *preset;
+ struct hda_codec_preset_list *tbl;
+ const struct hda_codec_preset *preset;
+ int mod_requested = 0;
if (is_generic_config(codec))
return NULL; /* use the generic parser */
- for (tbl = hda_preset_tables; *tbl; tbl++) {
- for (preset = *tbl; preset->id; preset++) {
+ again:
+ mutex_lock(&preset_mutex);
+ list_for_each_entry(tbl, &hda_preset_tables, list) {
+ if (!try_module_get(tbl->owner)) {
+ snd_printk(KERN_ERR "hda_codec: cannot module_get\n");
+ continue;
+ }
+ for (preset = tbl->preset; preset->id; preset++) {
u32 mask = preset->mask;
if (preset->afg && preset->afg != codec->afg)
continue;
@@ -556,9 +566,27 @@ find_codec_preset(struct hda_codec *codec)
mask = ~0;
if (preset->id == (codec->vendor_id & mask) &&
(!preset->rev ||
- preset->rev == codec->revision_id))
+ preset->rev == codec->revision_id)) {
+ mutex_unlock(&preset_mutex);
+ codec->owner = tbl->owner;
return preset;
+ }
}
+ module_put(tbl->owner);
+ }
+ mutex_unlock(&preset_mutex);
+
+ if (mod_requested < HDA_MODREQ_MAX_COUNT) {
+ char name[32];
+ if (!mod_requested)
+ snprintf(name, sizeof(name), "snd-hda-codec-id:%08x",
+ codec->vendor_id);
+ else
+ snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*",
+ (codec->vendor_id >> 16) & 0xffff);
+ request_module(name);
+ mod_requested++;
+ goto again;
}
return NULL;
}
@@ -598,7 +626,7 @@ static int get_codec_name(struct hda_codec *codec)
/*
* look for an AFG and MFG nodes
*/
-static void __devinit setup_fg_nodes(struct hda_codec *codec)
+static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
{
int i, total_nodes;
hda_nid_t nid;
@@ -661,6 +689,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
+ module_put(codec->owner);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
kfree(codec->name);
@@ -677,7 +706,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
*
* Returns 0 if successful, or a negative error code.
*/
-int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
struct hda_codec **codecp)
{
struct hda_codec *codec;
@@ -779,6 +808,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
*codecp = codec;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_new);
int snd_hda_codec_configure(struct hda_codec *codec)
{
@@ -838,6 +868,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
msleep(1);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream);
void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
{
@@ -851,6 +882,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
#endif
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_stream);
/*
* amp access functions
@@ -862,7 +894,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
/* initialize the hash table */
-static void __devinit init_hda_cache(struct hda_cache_rec *cache,
+static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache,
unsigned int record_size)
{
memset(cache, 0, sizeof(*cache));
@@ -932,6 +964,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
}
return info->amp_caps;
}
+EXPORT_SYMBOL_GPL(query_amp_caps);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps)
@@ -945,6 +978,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
info->head.val |= INFO_AMP_CAPS;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
/*
* read the current volume to info
@@ -998,6 +1032,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
return 0;
return get_vol_mute(codec, info, nid, ch, direction, index);
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read);
/*
* update the AMP value, mask = bit mask to set, val = the value
@@ -1017,6 +1052,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
put_vol_mute(codec, info, nid, ch, direction, idx, val);
return 1;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
/*
* update the AMP stereo with the same mask and value
@@ -1030,6 +1066,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
idx, mask, val);
return ret;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo);
#ifdef SND_HDA_NEEDS_RESUME
/* resume the all amp commands from the cache */
@@ -1055,6 +1092,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
}
}
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp);
#endif /* SND_HDA_NEEDS_RESUME */
/* volume */
@@ -1082,6 +1120,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = caps;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info);
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1101,6 +1140,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
& HDA_AMP_VOLMASK;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get);
int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1125,6 +1165,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
snd_hda_power_down(codec);
return change;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv)
@@ -1151,6 +1192,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
return -EFAULT;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv);
/*
* set (static) TLV for virtual master volume; recalculated as max 0dB
@@ -1170,6 +1212,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
tlv[2] = -nums * step;
tlv[3] = step;
}
+EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv);
/* find a mixer control element with the given name */
static struct snd_kcontrol *
@@ -1189,6 +1232,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
{
return _snd_hda_find_mixer_ctl(codec, name, 0);
}
+EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl);
/* Add a control element and assign to the codec */
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
@@ -1205,6 +1249,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
*knewp = kctl;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_ctl_add);
#ifdef CONFIG_SND_HDA_RECONFIG
/* Clear all controls assigned to the given codec */
@@ -1243,6 +1288,8 @@ void snd_hda_codec_reset(struct hda_codec *codec)
codec->num_pcms = 0;
codec->pcm_info = NULL;
codec->preset = NULL;
+ module_put(codec->owner);
+ codec->owner = NULL;
}
#endif /* CONFIG_SND_HDA_RECONFIG */
@@ -1281,6 +1328,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_add_vmaster);
/* switch */
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
@@ -1294,6 +1342,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 1;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info);
int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1313,6 +1362,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
HDA_AMP_MUTE) ? 0 : 1;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get);
int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1343,6 +1393,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
snd_hda_power_down(codec);
return change;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
/*
* bound volume controls
@@ -1368,6 +1419,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->spdif_mutex);
return err;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get);
int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1391,6 +1443,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->spdif_mutex);
return err < 0 ? err : change;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put);
/*
* generic bound volume/swtich controls
@@ -1410,6 +1463,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->spdif_mutex);
return err;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info);
int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1426,6 +1480,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->spdif_mutex);
return err;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get);
int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1448,6 +1503,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->spdif_mutex);
return err < 0 ? err : change;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put);
int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *tlv)
@@ -1464,6 +1520,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
mutex_unlock(&codec->spdif_mutex);
return err;
}
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv);
struct hda_ctl_ops snd_hda_bind_vol = {
.info = snd_hda_mixer_amp_volume_info,
@@ -1471,6 +1528,7 @@ struct hda_ctl_ops snd_hda_bind_vol = {
.put = snd_hda_mixer_amp_volume_put,
.tlv = snd_hda_mixer_amp_tlv
};
+EXPORT_SYMBOL_GPL(snd_hda_bind_vol);
struct hda_ctl_ops snd_hda_bind_sw = {
.info = snd_hda_mixer_amp_switch_info,
@@ -1478,6 +1536,7 @@ struct hda_ctl_ops snd_hda_bind_sw = {
.put = snd_hda_mixer_amp_switch_put,
.tlv = snd_hda_mixer_amp_tlv
};
+EXPORT_SYMBOL_GPL(snd_hda_bind_sw);
/*
* SPDIF out controls
@@ -1739,6 +1798,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_create_spdif_out_ctls);
/*
* SPDIF sharing with analog output
@@ -1776,6 +1836,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
return snd_hda_ctl_add(codec,
snd_ctl_new1(&spdif_share_sw, mout));
}
+EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw);
/*
* SPDIF input
@@ -1885,6 +1946,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
AC_DIG1_ENABLE;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls);
#ifdef SND_HDA_NEEDS_RESUME
/*
@@ -1930,6 +1992,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
snd_hda_power_down(codec);
return err;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache);
/* resume the all commands from the cache */
void snd_hda_codec_resume_cache(struct hda_codec *codec)
@@ -1945,6 +2008,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec)
get_cmd_cache_cmd(key), buffer->val);
}
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache);
/**
* snd_hda_sequence_write_cache - sequence writes with caching
@@ -1962,6 +2026,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb,
seq->param);
}
+EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache);
#endif /* SND_HDA_NEEDS_RESUME */
/*
@@ -2080,7 +2145,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
*
* Returns 0 if successful, otherwise a negative error code.
*/
-int __devinit snd_hda_build_controls(struct hda_bus *bus)
+int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
{
struct hda_codec *codec;
@@ -2091,6 +2156,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_build_controls);
int snd_hda_codec_build_controls(struct hda_codec *codec)
{
@@ -2202,6 +2268,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
return val;
}
+EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format);
/**
* snd_hda_query_supported_pcm - query the supported PCM rates and formats
@@ -2381,6 +2448,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
return 1;
}
+EXPORT_SYMBOL_GPL(snd_hda_is_supported_format);
/*
* PCM stuff
@@ -2578,6 +2646,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus)
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
/**
* snd_hda_check_board_config - compare the current codec with the config table
@@ -2633,6 +2702,7 @@ int snd_hda_check_board_config(struct hda_codec *codec,
}
return -1;
}
+EXPORT_SYMBOL_GPL(snd_hda_check_board_config);
/**
* snd_hda_add_new_ctls - create controls from the array
@@ -2668,6 +2738,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
#ifdef CONFIG_SND_HDA_POWER_SAVE
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
@@ -2710,6 +2781,10 @@ void snd_hda_power_up(struct hda_codec *codec)
cancel_delayed_work(&codec->power_work);
codec->power_transition = 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_power_up);
+
+#define power_save(codec) \
+ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
#define power_save(codec) \
((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
@@ -2725,6 +2800,7 @@ void snd_hda_power_down(struct hda_codec *codec)
msecs_to_jiffies(power_save(codec) * 1000));
}
}
+EXPORT_SYMBOL_GPL(snd_hda_power_down);
int snd_hda_check_amp_list_power(struct hda_codec *codec,
struct hda_loopback_check *check,
@@ -2761,6 +2837,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
#endif
/*
@@ -2780,6 +2857,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec,
chmode[uinfo->value.enumerated.item].channels);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
int snd_hda_ch_mode_get(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol,
@@ -2797,6 +2875,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec,
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
int snd_hda_ch_mode_put(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol,
@@ -2817,6 +2896,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
return 1;
}
+EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
/*
* input MUX helper
@@ -2837,6 +2917,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux,
strcpy(uinfo->value.enumerated.name, imux->items[index].label);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_input_mux_info);
int snd_hda_input_mux_put(struct hda_codec *codec,
const struct hda_input_mux *imux,
@@ -2858,6 +2939,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
*cur_val = idx;
return 1;
}
+EXPORT_SYMBOL_GPL(snd_hda_input_mux_put);
/*
@@ -2910,6 +2992,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open);
int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
struct hda_multi_out *mout,
@@ -2922,6 +3005,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
/*
* release the digital out
@@ -2934,6 +3018,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close);
/*
* set up more restrictions for analog out
@@ -2973,6 +3058,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
return snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
}
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open);
/*
* set up the i/o for analog out
@@ -3031,6 +3117,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare);
/*
* clean up the setting for analog out
@@ -3057,6 +3144,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup);
/*
* Helper for automatic pin configuration
@@ -3342,11 +3430,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_parse_pin_def_config);
/* labels for input pins */
const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
};
+EXPORT_SYMBOL_GPL(auto_pin_cfg_labels);
#ifdef CONFIG_PM
@@ -3374,6 +3464,7 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_suspend);
/**
* snd_hda_resume - resume the codecs
@@ -3394,7 +3485,8 @@ int snd_hda_resume(struct hda_bus *bus)
}
return 0;
}
-#endif
+EXPORT_SYMBOL_GPL(snd_hda_resume);
+#endif /* CONFIG_PM */
/*
* generic arrays
@@ -3423,6 +3515,7 @@ void *snd_array_new(struct snd_array *array)
}
return snd_array_elem(array, array->used++);
}
+EXPORT_SYMBOL_GPL(snd_array_new);
/* free the given array elements */
void snd_array_free(struct snd_array *array)
@@ -3432,6 +3525,7 @@ void snd_array_free(struct snd_array *array)
array->alloced = 0;
array->list = NULL;
}
+EXPORT_SYMBOL_GPL(snd_array_free);
/*
* used by hda_proc.c and hda_eld.c
@@ -3450,6 +3544,7 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen)
buf[j] = '\0'; /* necessary when j == 0 */
}
+EXPORT_SYMBOL_GPL(snd_print_pcm_rates);
void snd_print_pcm_bits(int pcm, char *buf, int buflen)
{
@@ -3462,3 +3557,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
buf[j] = '\0'; /* necessary when j == 0 */
}
+EXPORT_SYMBOL_GPL(snd_print_pcm_bits);
+
+MODULE_DESCRIPTION("HDA codec core");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 9fe0b67..586ea08 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -642,6 +642,16 @@ struct hda_codec_preset {
int (*patch)(struct hda_codec *codec);
};
+struct hda_codec_preset_list {
+ const struct hda_codec_preset *preset;
+ struct module *owner;
+ struct list_head list;
+};
+
+/* initial hook */
+int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset);
+int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset);
+
/* ops set by the preset patch */
struct hda_codec_ops {
int (*build_controls)(struct hda_codec *codec);
@@ -735,6 +745,7 @@ struct hda_codec {
/* detected preset */
const struct hda_codec_preset *preset;
+ struct module *owner;
const char *name; /* codec name */
const char *modelname; /* model name for preset */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 98ff010..65745e9 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -1101,3 +1101,4 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
snd_hda_generic_free(codec);
return err;
}
+EXPORT_SYMBOL(snd_hda_parse_generic_codec);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 173af48..300ab40 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -116,7 +116,7 @@ static void hwdep_free(struct snd_hwdep *hwdep)
clear_hwdep_elements(hwdep->private_data);
}
-int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
+int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
{
char hwname[16];
struct snd_hwdep *hwdep;
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
deleted file mode 100644
index 38212c1..0000000
--- a/sound/pci/hda/hda_patch.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * HDA Patches - included by hda_codec.c
- */
-
-/* Realtek codecs */
-extern struct hda_codec_preset snd_hda_preset_realtek[];
-/* C-Media codecs */
-extern struct hda_codec_preset snd_hda_preset_cmedia[];
-/* Analog Devices codecs */
-extern struct hda_codec_preset snd_hda_preset_analog[];
-/* SigmaTel codecs */
-extern struct hda_codec_preset snd_hda_preset_sigmatel[];
-/* SiLabs 3054/3055 modem codecs */
-extern struct hda_codec_preset snd_hda_preset_si3054[];
-/* ATI HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_atihdmi[];
-/* Conexant audio codec */
-extern struct hda_codec_preset snd_hda_preset_conexant[];
-/* VIA codecs */
-extern struct hda_codec_preset snd_hda_preset_via[];
-/* NVIDIA HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_nvhdmi[];
-/* INTEL HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_intelhdmi[];
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 0cc6be1..c1918a1 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -27,7 +27,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
struct ad198x_spec {
struct snd_kcontrol_new *mixers[5];
@@ -4308,7 +4307,7 @@ static int patch_ad1882(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_analog[] = {
+static struct hda_codec_preset snd_hda_preset_analog[] = {
{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
@@ -4326,3 +4325,26 @@ struct hda_codec_preset snd_hda_preset_analog[] = {
{ .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:11d4*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Analog Devices HD-audio codec");
+
+static struct hda_codec_preset_list analog_list = {
+ .preset = snd_hda_preset_analog,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_analog_init(void)
+{
+ return snd_hda_add_codec_preset(&analog_list);
+}
+
+static void __exit patch_analog_exit(void)
+{
+ snd_hda_delete_codec_preset(&analog_list);
+}
+
+module_init(patch_analog_init)
+module_exit(patch_analog_exit)
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 5603a1a..5887b82 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -27,7 +27,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
struct atihdmi_spec {
struct hda_multi_out multiout;
@@ -187,7 +186,7 @@ static int patch_atihdmi(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_atihdmi[] = {
+static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
@@ -196,3 +195,31 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = {
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:1002793c");
+MODULE_ALIAS("snd-hda-codec-id:10027919");
+MODULE_ALIAS("snd-hda-codec-id:1002791a");
+MODULE_ALIAS("snd-hda-codec-id:1002aa01");
+MODULE_ALIAS("snd-hda-codec-id:10951390");
+MODULE_ALIAS("snd-hda-codec-id:17e80047");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
+
+static struct hda_codec_preset_list atihdmi_list = {
+ .preset = snd_hda_preset_atihdmi,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_atihdmi_init(void)
+{
+ return snd_hda_add_codec_preset(&atihdmi_list);
+}
+
+static void __exit patch_atihdmi_exit(void)
+{
+ snd_hda_delete_codec_preset(&atihdmi_list);
+}
+
+module_init(patch_atihdmi_init)
+module_exit(patch_atihdmi_exit)
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 6ef57fb..f3ebe83 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -28,7 +28,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
#define NUM_PINS 11
@@ -736,8 +735,32 @@ static int patch_cmi9880(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_cmedia[] = {
+static struct hda_codec_preset snd_hda_preset_cmedia[] = {
{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:13f69880");
+MODULE_ALIAS("snd-hda-codec-id:434d4980");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("C-Media HD-audio codec");
+
+static struct hda_codec_preset_list cmedia_list = {
+ .preset = snd_hda_preset_cmedia,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_cmedia_init(void)
+{
+ return snd_hda_add_codec_preset(&cmedia_list);
+}
+
+static void __exit patch_cmedia_exit(void)
+{
+ snd_hda_delete_codec_preset(&cmedia_list);
+}
+
+module_init(patch_cmedia_init)
+module_exit(patch_cmedia_exit)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 0760107..b20e1ce 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -27,7 +27,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
#define CXT_PIN_DIR_IN 0x00
#define CXT_PIN_DIR_OUT 0x01
@@ -1771,7 +1770,7 @@ static int patch_cxt5051(struct hda_codec *codec)
/*
*/
-struct hda_codec_preset snd_hda_preset_conexant[] = {
+static struct hda_codec_preset snd_hda_preset_conexant[] = {
{ .id = 0x14f15045, .name = "CX20549 (Venice)",
.patch = patch_cxt5045 },
{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
@@ -1780,3 +1779,28 @@ struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_cxt5051 },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:14f15045");
+MODULE_ALIAS("snd-hda-codec-id:14f15047");
+MODULE_ALIAS("snd-hda-codec-id:14f15051");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Conexant HD-audio codec");
+
+static struct hda_codec_preset_list conexant_list = {
+ .preset = snd_hda_preset_conexant,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_conexant_init(void)
+{
+ return snd_hda_add_codec_preset(&conexant_list);
+}
+
+static void __exit patch_conexant_exit(void)
+{
+ snd_hda_delete_codec_preset(&conexant_list);
+}
+
+module_init(patch_conexant_init)
+module_exit(patch_conexant_exit)
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
index fe08bef..290da56 100644
--- a/sound/pci/hda/patch_intelhdmi.c
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -32,7 +32,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
#define CVT_NID 0x02 /* audio converter */
#define PIN_NID 0x03 /* HDMI output pin */
@@ -675,7 +674,7 @@ static int patch_intel_hdmi(struct hda_codec *codec)
return 0;
}
-struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
+static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
{ .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi },
{ .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi },
{ .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi },
@@ -683,3 +682,30 @@ struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:808629fb");
+MODULE_ALIAS("snd-hda-codec-id:80862801");
+MODULE_ALIAS("snd-hda-codec-id:80862802");
+MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:10951392");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
+
+static struct hda_codec_preset_list intel_list = {
+ .preset = snd_hda_preset_intelhdmi,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_intelhdmi_init(void)
+{
+ return snd_hda_add_codec_preset(&intel_list);
+}
+
+static void __exit patch_intelhdmi_exit(void)
+{
+ snd_hda_delete_codec_preset(&intel_list);
+}
+
+module_init(patch_intelhdmi_init)
+module_exit(patch_intelhdmi_exit)
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index 1360d54..e23de55 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -28,7 +28,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
struct nvhdmi_spec {
struct hda_multi_out multiout;
@@ -159,8 +158,32 @@ static int patch_nvhdmi(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
+static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
{ .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi },
{ .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0007");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
+
+static struct hda_codec_preset_list nvhdmi_list = {
+ .preset = snd_hda_preset_nvhdmi,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_nvhdmi_init(void)
+{
+ return snd_hda_add_codec_preset(&nvhdmi_list);
+}
+
+static void __exit patch_nvhdmi_exit(void)
+{
+ snd_hda_delete_codec_preset(&nvhdmi_list);
+}
+
+module_init(patch_nvhdmi_init)
+module_exit(patch_nvhdmi_exit)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 9cd2545..ba640d3 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -30,7 +30,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
#define ALC880_FRONT_EVENT 0x01
#define ALC880_DCVOL_EVENT 0x02
@@ -16579,7 +16578,7 @@ static int patch_alc662(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_realtek[] = {
+static struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -16611,3 +16610,26 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:10ec*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek HD-audio codec");
+
+static struct hda_codec_preset_list realtek_list = {
+ .preset = snd_hda_preset_realtek,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_realtek_init(void)
+{
+ return snd_hda_add_codec_preset(&realtek_list);
+}
+
+static void __exit patch_realtek_exit(void)
+{
+ snd_hda_delete_codec_preset(&realtek_list);
+}
+
+module_init(patch_realtek_init)
+module_exit(patch_realtek_exit)
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 9332b63..43b436c 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -28,7 +28,6 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
/* si3054 verbs */
#define SI3054_VERB_READ_NODE 0x900
@@ -283,7 +282,7 @@ static int patch_si3054(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_si3054[] = {
+static struct hda_codec_preset snd_hda_preset_si3054[] = {
{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
@@ -301,3 +300,35 @@ struct hda_codec_preset snd_hda_preset_si3054[] = {
{}
};
+MODULE_ALIAS("snd-hda-codec-id:163c3055");
+MODULE_ALIAS("snd-hda-codec-id:163c3155");
+MODULE_ALIAS("snd-hda-codec-id:11c13026");
+MODULE_ALIAS("snd-hda-codec-id:11c13055");
+MODULE_ALIAS("snd-hda-codec-id:11c13155");
+MODULE_ALIAS("snd-hda-codec-id:10573055");
+MODULE_ALIAS("snd-hda-codec-id:10573057");
+MODULE_ALIAS("snd-hda-codec-id:10573155");
+MODULE_ALIAS("snd-hda-codec-id:11063288");
+MODULE_ALIAS("snd-hda-codec-id:15433155");
+MODULE_ALIAS("snd-hda-codec-id:18540018");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
+
+static struct hda_codec_preset_list si3054_list = {
+ .preset = snd_hda_preset_si3054,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_si3054_init(void)
+{
+ return snd_hda_add_codec_preset(&si3054_list);
+}
+
+static void __exit patch_si3054_exit(void)
+{
+ snd_hda_delete_codec_preset(&si3054_list);
+}
+
+module_init(patch_si3054_init)
+module_exit(patch_si3054_exit)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 70181d5..9e07f44 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -33,7 +33,6 @@
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
#include "hda_beep.h"
enum {
@@ -5455,7 +5454,7 @@ static int patch_stac9872(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_sigmatel[] = {
+static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
{ .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
{ .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
@@ -5519,3 +5518,27 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:8384*");
+MODULE_ALIAS("snd-hda-codec-id:111d*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
+
+static struct hda_codec_preset_list sigmatel_list = {
+ .preset = snd_hda_preset_sigmatel,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_sigmatel_init(void)
+{
+ return snd_hda_add_codec_preset(&sigmatel_list);
+}
+
+static void __exit patch_sigmatel_exit(void)
+{
+ snd_hda_delete_codec_preset(&sigmatel_list);
+}
+
+module_init(patch_sigmatel_init)
+module_exit(patch_sigmatel_exit)
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 05182be..6e4d01d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -47,7 +47,6 @@
#include <sound/asoundef.h>
#include "hda_codec.h"
#include "hda_local.h"
-#include "hda_patch.h"
/* amp values */
#define AMP_VAL_IDX_SHIFT 19
@@ -3249,7 +3248,7 @@ static int patch_vt1702(struct hda_codec *codec)
/*
* patch entries
*/
-struct hda_codec_preset snd_hda_preset_via[] = {
+static struct hda_codec_preset snd_hda_preset_via[] = {
{ .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
{ .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
{ .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
@@ -3320,3 +3319,26 @@ struct hda_codec_preset snd_hda_preset_via[] = {
.patch = patch_vt1702},
{} /* terminator */
};
+
+MODULE_ALIAS("snd-hda-codec-id:1106*");
+
+static struct hda_codec_preset_list via_list = {
+ .preset = snd_hda_preset_via,
+ .owner = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VIA HD-audio codec");
+
+static int __init patch_via_init(void)
+{
+ return snd_hda_add_codec_preset(&via_list);
+}
+
+static void __exit patch_via_exit(void)
+{
+ snd_hda_delete_codec_preset(&via_list);
+}
+
+module_init(patch_via_init)
+module_exit(patch_via_exit)
--
1.6.0.4
3
7
06 Feb '09
Hi,
here is the output from alsa-info.sh
http://www.alsa-project.org/db/?f=8282910dc807e1f141896886cd5f8fd574117000
I found another small mistake. In the Mixer my Soundcard is shown as
"Realtek ALC888".
When i switch this to lines in patch_realtek.c then it is shown as
"Realtek ALC1200".
static struct hda_codec_preset snd_hda_preset_realtek[] = {
......
{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
.patch = patch_alc883 },
.....
Thomas
Am 25.12.2008 05:31, schrieb Wu Fengguang:
> Hi Thomas,
>
> Could you provide more information by running
> http://www.alsa-project.org/alsa-info.sh
>
> I'm particularity interested in the full dmesg and contents of
> /proc/asound/card?/*\#?
>
> Thanks,
> Fengguang
>
> On Tue, Dec 23, 2008 at 12:22:29PM +0100, Thomas Schneider wrote:
>
>> Hi,
>>
>> i am looking for a way to make Digital-Audio work with the external
>> and internal S/PDIF-Output of my Motherboard Asus M3A-H/HDMI with
>> ALC1200 Soundard. I use the latest unstable snapshot and i can´t
>> make it work at the same time.
>>
>> On the external S/PDIF-Output is my Digital Receiver connected,
>> on the internal one my GeForce 8500GT to get sound over HDMI
>> on my LCT-TV.
>>
>> When i load the driver without any model-options my Soundcard is
>> detected as Asus P5Q-EM HDMI
>>
>> ALSA /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:2716:
>> hda_codec: model 'asus-p5q' is selected for config 1043:82fe (Asus
>> P5Q-EM HDMI)
>> [ 6.721700] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave Headphone Playback Volume, skipped
>> [ 6.721714] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave Speaker Playback Volume, skipped
>> [ 6.721716] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave Mono Playback Volume, skipped
>> [ 6.721719] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave Line-Out Playback Volume, skipped
>> [ 6.721721] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave PCM Playback Volume, skipped
>> [ 6.721729] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave Speaker Playback Switch, skipped
>> [ 6.721731] ALSA
>> /usr/local/src/alsa-driver-unstable/pci/hda/hda_codec.c:1339: Cannot
>> find slave Mono Playback Switch, skipped
>>
>> Now i have sound on my LCD-TV over HDMI (internal S/PDIF-Out)
>>
>> When i load the driver with model=6stack-dig i have sound on my
>> Digital-Receiver (external S/PDIF-Out).
>>
>> In the mailinglist-archive or in the doku i have seen, that the only
>> difference
>> between this models is the DIGOUT_NID
>>
>> asus-p5q = 0x10
>> 6stack-dig = 0x06
>>
>> I there a way to get both output to work at the same time so i have
>> sound on my LCD-TV and my Digital-Receiver ?
>>
>>
>> Regards
>>
>> Thomas
>> _______________________________________________
>> Alsa-devel mailing list
>> Alsa-devel(a)alsa-project.org
>> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel(a)alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
3
12
Hi,
following is a report of some tests of alsa.1.0.18rc3 in view of support of Tascam US-122L, which might be of interest for you. As a preliminary information, note that I patched my own Fedora kernel and alsa-plugins with Karsten Wiese'patches a few month ago and use regularly Tascam US-122L under Linux which works very fine; I also provide (experimental) packages for Fedora 9 from june 2008 on my web page.
Test 1: succeeded
- replacement of my own alsa-plugins-usb_stream-1.0.16-4.us122lv05.fc9 by alsa-plugins-usbstream-1.0.18-1.rc3.fc10 on Fedora 9 (using my own patched kernel 2.6.26 including the snd-usb-us122l module). Everything works.
Test 2: succeeded
- replacement of previous alsa-1.0.16 by alsa.1.0.18-1.rc3 (Fedora packages; thus alsa-driver-1.0.18rc3 not included). Everything works, including Tascam US-122L when using my patched kernel (which includes the snd-usb-us122l module).
Test 3: failed
- installation of alsa-driver-1.0.18rc3 (succeeded) on Fedora 9 (as weel, I tested with new Fedora 10 beta which includes kernel 2.6.27.rc3); plug in the US-122L leads to error messages from snd-usb-us122l:
# cat /var/log/messages
...
Oct 11 09:21:51 pollux kernel: usb 2-6: new high speed USB device using ehci_hcd and address 3
Oct 11 09:21:51 pollux kernel: usb 2-6: config 1 interface 1 altsetting 1 bulk endpoint 0x83 has invalid maxpacket 9
Oct 11 09:21:51 pollux kernel: usb 2-6: configuration #1 chosen from 1 choice
Oct 11 09:21:51 pollux kernel: usb 2-6: New USB device found, idVendor=0644, idProduct=800e
Oct 11 09:21:51 pollux kernel: usb 2-6: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Oct 11 09:21:51 pollux kernel: usb 2-6: Product: US-122L
Oct 11 09:21:51 pollux kernel: usb 2-6: Manufacturer: TASCAM
Oct 11 09:21:51 pollux kernel: usb 2-6: SerialNumber: no serial number
Oct 11 09:21:51 pollux kernel: ALSA /home/Test/alsa-driver-1.0.18rc3/usb/usx2y/../../alsa-kernel/usb/usx2y/usb_stream.c:618: 0
Oct 11 09:21:55 pollux kernel: ALSA /home/Test/alsa-driver-1.0.18rc3/usb/usx2y/../../alsa-kernel/usb/usx2y/us122l.c:329: us122l_start error -14
Oct 11 09:21:55 pollux kernel: snd-usb-us122l: probe of 2-6:1.1 failed with error -5
Oct 11 09:21:55 pollux kernel: usbcore: registered new interface driver snd-usb-us122l
and
# cat /proc/asound/cards
0 [Intel ]: HDA-Intel - HDA Intel
HDA Intel at 0xfebfc000 irq 21
US-122L finally not being recognized.
Test 4: succeded
- same than test 3 for Fedora 9, but using a patched ehci-hcd module (the patch adding some features from the original one by Karsten Wiese not - yet ? - included in kernel 2.6.26). Everything works including of course the US-122L.
Question:
Thus, a patched ehci-hcd module is required. Is the patch scheduled to appear in kernel 2.6.27 or would it be useful to work for providing a kind of kmod ?
Regards
Phil.
--
Philippe Carriere <philippe-f.carriere(a)wanadoo.fr>
3
6
This code:
#include <alsa/asoundlib.h>
int main(){
snd_pcm_t *handle;
if(snd_pcm_open(&handle, "default:1", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
exit(1);
}
if(snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
SND_PCM_ACCESS_RW_INTERLEAVED,
2, 24000, 1, 100000) < 0) {
exit(2);
}
}
fails with error "ALSA lib pcm.c:7193:(snd_pcm_set_params) Unable to
get period size for PLAYBACK: Invalid argument"
Disable resampling and you get "ALSA lib
pcm.c:7142:(snd_pcm_set_params) Rate doesn't match (requested 24000Hz,
get 0Hz)" (normal, I suppose). With other samplerates works fine.
I'm using alsa-driver-kmp-default-1.0.16.20080602 and
alsa-1.0.16.hg20080510 RPM packages from multimedia:audio openSUSE
Build Service repository (from Takashi Iwai) and an AD1988 (hda-intel)
codec. A XUbuntu user also has the same problem with an hda-intel
codec (that I suppose uses stable 1.0.16).
With a SB Live! in the same computer there are no problems.
This was discovered with bsnes ( http://byuu.cinnamonpirate.com/bsnes/
- http://board.zsnes.com/phpBB2/viewtopic.php?t=11584 ) that can use
openal, libao or alsa directly. The problem just happens when using
24KHz with alsa. So I suppose the problem is in the
snd_pcm_set_params() itself, since openal and libao have not the
problem but they set parameters "manually", not with
snd_pcm_set_params().
3
2
[alsa-devel] snd_pcm_avail_update() needed before snd_pcm_delay() with hda-intel
by Christian Morales Vega 24 Jan '09
by Christian Morales Vega 24 Jan '09
24 Jan '09
snd_pcm_avail_update() documentation says: "Using of this function is
useless for the standard read/write operations. Use it only for mmap
access. See to snd_pcm_delay."
snd_pcm_delay() documentation says: "Note this function does not
update the actual r/w pointer for applications. The function
snd_pcm_avail_update() have to be called before any begin+commit
operation."
My english is far from perfect, and so the problem can be that I
missunderstood the docs but:
1- "Using of this function"? Should not be "Use of this function"?
2- Is snd_pcm_avail_update() really useless when not using mmap?
I have a SB Live! where snd_pcm_delay() always returns the correct
value, without any need for snd_pcm_avail_update(). But the same code
in the same machine with an hda-intel AD1988 needs a call to
snd_pcm_avail_update() before snd_pcm_delay() to give the correct
result. Without it snd_pcm_delay() always returns the value that *was*
correct in the last snd_pcm_writei() call.
So should the "application frame position" be always updated, or only
in read/write operations? In the first case AD1988 fails, in the
second case perhaps SB Live! is making too mucho work ;-)
4
9
[alsa-devel] Acer Aspire 8920g / snd-hda-intel / ALC889 / surround sound
by Sergey 'Jin' Bostandzhyan 23 Jan '09
by Sergey 'Jin' Bostandzhyan 23 Jan '09
23 Jan '09
Hi,
there's been a thread about a similar issue around 2008-04, it ended with a
working front left/right setup, which is of course better than no sound, but
it would be really nice to be able to use all available speakers.
The notebook has 5.1 surround, but all speakers except front left and front
right stay silent.
I'm running Fedora 10, 2.6.27.9-159.fc10.x86_64,
# cat /proc/asound/version
Advanced Linux Sound Architecture Driver Version 1.0.18a.
# cat /proc/asound/cards
0 [Intel ]: HDA-Intel - HDA Intel
HDA Intel at 0xfc300000 irq 22
1 [HDMI ]: HDA-Intel - HDA ATI HDMI
HDA ATI HDMI at 0xc7eec000 irq 17
When I select model "auto", then I get a working front left and front right
speaker. When I select model "acer-aspire", everything is mute and I have
to use the hda-verb utility to get some sound out of the front speakers, so
right now I am using the "auto" option.
I see a segfault in alsactl when I look at dmesg, not sure if this is
related to the problem:
HDA Intel 0000:00:1b.0: PCI INT A -> GSI 22 (level, low) -> IRQ 22
HDA Intel 0000:00:1b.0: setting latency timer to 64
ALSA sound/pci/hda/hda_codec.c:2587: hda_codec: model 'auto' is selected
ALSA sound/pci/hda/hda_codec.c:3303: autoconfig: line_outs=1 (0x14/0x0/0x0/0x0/0x0)
ALSA sound/pci/hda/hda_codec.c:3307: speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
ALSA sound/pci/hda/hda_codec.c:3311: hp_outs=1 (0x15/0x0/0x0/0x0/0x0)
ALSA sound/pci/hda/hda_codec.c:3312: mono: mono_out=0x0
ALSA sound/pci/hda/hda_codec.c:3320: inputs: mic=0x12, fmic=0x18, line=0x1a, fline=0x0, cd=0x0, aux=0x0
HDA Intel 0000:01:00.1: PCI INT B -> GSI 17 (level, low) -> IRQ 17
HDA Intel 0000:01:00.1: setting latency timer to 64
alsactl[1631]: segfault at 0 ip 00000000004106e7 sp 00007fffb7682fa0 error 4 in alsactl[400000+14000]
alsactl[1624]: segfault at 0 ip 00000000004106e7 sp 00007fff4ba9e3c0 error 4 in alsactl[400000+14000]
The full output of the alsa-info script is here:
http://www.alsa-project.org/db/?f=405364959a8f52c85f045f35fa1f3bf4536b13bc
I have a working setup to compile the alsa-driver, so I'm ready to test
whatever is needed :) Any ideas?
Kind regards,
Jin
2
6
Hi,
I got an access to old ISA card called Turtle Beach Multisound Pinnacle.
I could not resist and update the Pinnacle driver from alsa-driver package
to work with current kernel (2.6.28-rc6).
The attached patch is current state of the driver. It still contains many
formatting issues but it allows pcm and midi output (maybe input as well).
This is for people who wants to try and report results.
The driver requires firmware files put into firmware/turtlebeach directory.
How to prepare these files is explained already in kernel:
Documentation/sound/oss/MultiSound
I made Multisound Classic driver compilable but I have no hardware to test.
Main changes comparing to "old" driver from the alsa-driver package are:
1. Update probing framework to use ISA/PnP functions
2. Convert midi to use mpu401 driver (from rawmidi)
3. CS changes
Regards,
Krzysztof
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 660beb4..40f4a41 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -411,5 +411,36 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
you need to install the firmware files from the
alsa-firmware package.
+config SND_MSND_PINNACLE
+ tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
+ depends on X86
+ select FW_LOADER
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say Y to include support for Turtle Beach MultiSound Pinnacle/
+ Fiji soundcards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-msnd-pinnacle.
+
+config SND_MSND_CLASSIC
+ tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
+ depends on X86
+ select FW_LOADER
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+ Monterey (not for the Pinnacle or Fiji).
+
+ See <file:Documentation/sound/oss/MultiSound> for important information
+ about this driver. Note that it has been discontinued, but the
+ Voyetra Turtle Beach knowledge base entry for it is still available
+ at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-msnd-classic.
+
endif # SND_ISA
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 63af13d..beb96ec 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -26,5 +26,5 @@ obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \
- sb/ wavefront/ wss/
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ \
+ opti9xx/ sb/ wavefront/ wss/
diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
new file mode 100644
index 0000000..5d3c814
--- /dev/null
+++ b/sound/isa/msnd/Makefile
@@ -0,0 +1,9 @@
+
+snd-msnd-lib-objs := msnd.o msnd_midi.o
+snd-msnd-pinnacle-objs := msnd_pinnacle.o msnd_pinnacle_mixer.o
+snd-msnd-classic-objs := msnd_classic.o msnd_pinnacle_mixer.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o snd-msnd-lib.o
+obj-$(CONFIG_SND_MSND_CLASSIC) += snd-msnd-classic.o snd-msnd-lib.o
+
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
new file mode 100644
index 0000000..cc17580
--- /dev/null
+++ b/sound/isa/msnd/msnd.c
@@ -0,0 +1,224 @@
+/*********************************************************************
+ *
+ * 2002/06/30 Karsten Wiese:
+ * removed kernel-version dependencies.
+ * ripped from linux kernel 2.4.18 (OSS Implementation) by me.
+ * In the OSS Version, this file is compiled to a separate MODULE,
+ * that is used by the pinnacle and the classic driver.
+ * since there is no classic driver for alsa yet (i dont have a classic
+ * & writing one blindfold is difficult) this file's object is statically
+ * linked into the pinnacle-driver-module for now. look for the string
+ * "uncomment this to make this a module again"
+ * to do guess what.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ ********************************************************************/
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include "msnd.h"
+
+#define LOGNAME "msnd"
+
+
+void snd_msnd_init_queue(unsigned long base, int start, int size)
+{
+ isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
+ isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ isa_writew(0, base + JQS_wHead);
+ isa_writew(0, base + JQS_wTail);
+}
+EXPORT_SYMBOL(snd_msnd_init_queue);
+
+
+int snd_msnd_wait_TXDE(struct snd_msnd *dev)
+{
+ unsigned int io = dev->io;
+ int timeout = 1000;
+
+ while (timeout-- > 0)
+ if (inb(io + HP_ISR) & HPISR_TXDE)
+ return 0;
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_wait_TXDE);
+
+int snd_msnd_wait_HC0(struct snd_msnd *dev)
+{
+ unsigned int io = dev->io;
+ int timeout = 1000;
+
+ while (timeout-- > 0)
+ if (!(inb(io + HP_CVR) & HPCVR_HC))
+ return 0;
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_wait_HC0);
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_HC0(dev) == 0) {
+ outb(cmd, dev->io + HP_CVR);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
+
+
+int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
+ unsigned char mid, unsigned char low)
+{
+ unsigned int io = dev->io;
+
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(high, io + HP_TXH);
+ outb(mid, io + HP_TXM);
+ outb(low, io + HP_TXL);
+ return 0;
+ }
+
+ printk(KERN_DEBUG LOGNAME ": Send host word timeout\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_word);
+
+int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
+{
+ int i;
+
+ if (len % 3 != 0) {
+ printk(KERN_WARNING
+ LOGNAME ": Upload host data not multiple of 3!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += 3)
+ if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
+ return -EIO;
+
+ inb(dev->io + HP_RXL);
+ inb(dev->io + HP_CVR);
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_msnd_upload_host);
+
+int snd_msnd_enable_irq(struct snd_msnd *dev)
+{
+ unsigned long flags;
+
+ if (dev->irq_ref++)
+ return 0;
+
+ printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(dev->irqid, dev->io + HP_IRQM);
+
+ outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+ outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+ enable_irq(dev->irq);
+ snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
+ dev->dspq_buff_size);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_enable_irq);
+
+
+int snd_msnd_disable_irq(struct snd_msnd *dev)
+{
+ unsigned long flags;
+
+ if (--dev->irq_ref > 0)
+ return 0;
+
+ if (dev->irq_ref < 0)
+ printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n",
+ dev->irq_ref);
+
+ printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(HPIRQ_NONE, dev->io + HP_IRQM);
+ disable_irq(dev->irq);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_disable_irq);
+
+
+MODULE_AUTHOR("Andrew Veliath <andrewtv(a)usa.net>");
+MODULE_DESCRIPTION("Turtle Beach MultiSound Driver Base");
+MODULE_LICENSE("GPL");
+
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
new file mode 100644
index 0000000..7d07ce6
--- /dev/null
+++ b/sound/isa/msnd/msnd.h
@@ -0,0 +1,341 @@
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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 __MSND_H
+#define __MSND_H
+
+#define VERSION "0.1.3.0"
+
+#define DEFSAMPLERATE 44100
+#define DEFSAMPLESIZE SNDRV_PCM_FORMAT_S16
+#define DEFCHANNELS 1
+
+#define SNDCARD_MSND 38
+
+#define SRAM_BANK_SIZE 0x8000
+#define SRAM_CNTL_START 0x7F00
+
+#define DSP_BASE_ADDR 0x4000
+#define DSP_BANK_BASE 0x4000
+
+#define HP_ICR 0x00
+#define HP_CVR 0x01
+#define HP_ISR 0x02
+#define HP_IVR 0x03
+#define HP_NU 0x04
+#define HP_INFO 0x04
+#define HP_TXH 0x05
+#define HP_RXH 0x05
+#define HP_TXM 0x06
+#define HP_RXM 0x06
+#define HP_TXL 0x07
+#define HP_RXL 0x07
+
+#define HP_ICR_DEF 0x00
+#define HP_CVR_DEF 0x12
+#define HP_ISR_DEF 0x06
+#define HP_IVR_DEF 0x0f
+#define HP_NU_DEF 0x00
+
+#define HP_IRQM 0x09
+
+#define HPR_BLRC 0x08
+#define HPR_SPR1 0x09
+#define HPR_SPR2 0x0A
+#define HPR_TCL0 0x0B
+#define HPR_TCL1 0x0C
+#define HPR_TCL2 0x0D
+#define HPR_TCL3 0x0E
+#define HPR_TCL4 0x0F
+
+#define HPICR_INIT 0x80
+#define HPICR_HM1 0x40
+#define HPICR_HM0 0x20
+#define HPICR_HF1 0x10
+#define HPICR_HF0 0x08
+#define HPICR_TREQ 0x02
+#define HPICR_RREQ 0x01
+
+#define HPCVR_HC 0x80
+
+#define HPISR_HREQ 0x80
+#define HPISR_DMA 0x40
+#define HPISR_HF3 0x10
+#define HPISR_HF2 0x08
+#define HPISR_TRDY 0x04
+#define HPISR_TXDE 0x02
+#define HPISR_RXDF 0x01
+
+#define HPIO_290 0
+#define HPIO_260 1
+#define HPIO_250 2
+#define HPIO_240 3
+#define HPIO_230 4
+#define HPIO_220 5
+#define HPIO_210 6
+#define HPIO_3E0 7
+
+#define HPMEM_NONE 0
+#define HPMEM_B000 1
+#define HPMEM_C800 2
+#define HPMEM_D000 3
+#define HPMEM_D400 4
+#define HPMEM_D800 5
+#define HPMEM_E000 6
+#define HPMEM_E800 7
+
+#define HPIRQ_NONE 0
+#define HPIRQ_5 1
+#define HPIRQ_7 2
+#define HPIRQ_9 3
+#define HPIRQ_10 4
+#define HPIRQ_11 5
+#define HPIRQ_12 6
+#define HPIRQ_15 7
+
+#define HIMT_PLAY_DONE 0x00
+#define HIMT_RECORD_DONE 0x01
+#define HIMT_MIDI_EOS 0x02
+#define HIMT_MIDI_OUT 0x03
+
+#define HIMT_MIDI_IN_UCHAR 0x0E
+#define HIMT_DSP 0x0F
+
+#define HDEX_BASE 0x92
+#define HDEX_PLAY_START (0 + HDEX_BASE)
+#define HDEX_PLAY_STOP (1 + HDEX_BASE)
+#define HDEX_PLAY_PAUSE (2 + HDEX_BASE)
+#define HDEX_PLAY_RESUME (3 + HDEX_BASE)
+#define HDEX_RECORD_START (4 + HDEX_BASE)
+#define HDEX_RECORD_STOP (5 + HDEX_BASE)
+#define HDEX_MIDI_IN_START (6 + HDEX_BASE)
+#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE)
+#define HDEX_MIDI_OUT_START (8 + HDEX_BASE)
+#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE)
+#define HDEX_AUX_REQ (10 + HDEX_BASE)
+
+#define HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF))
+#define LOWORD(l) ((u16)(u32)(l))
+#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF))
+#define LOBYTE(w) ((u8)(w))
+#define MAKELONG(low, hi) ((long)(((u16)(low))|(((u32)((u16)(hi)))<<16)))
+#define MAKEWORD(low, hi) ((u16)(((u8)(low))|(((u16)((u8)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w) (u16)((w)/2)
+#define PCTODSP_BASED(w) (u16)(((w)/2) + DSP_BASE_ADDR)
+#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2)
+
+#ifdef SLOWIO
+# undef outb
+# undef inb
+# define outb outb_p
+# define inb inb_p
+#endif
+
+/* JobQueueStruct */
+#define JQS_wStart 0x00
+#define JQS_wSize 0x02
+#define JQS_wHead 0x04
+#define JQS_wTail 0x06
+#define JQS__size 0x08
+
+/* DAQueueDataStruct */
+#define DAQDS_wStart 0x00
+#define DAQDS_wSize 0x02
+#define DAQDS_wFormat 0x04
+#define DAQDS_wSampleSize 0x06
+#define DAQDS_wChannels 0x08
+#define DAQDS_wSampleRate 0x0A
+#define DAQDS_wIntMsg 0x0C
+#define DAQDS_wFlags 0x0E
+#define DAQDS__size 0x10
+
+/* Generic FIFO * /
+typedef struct {
+ size_t n, len;
+ char *data;
+ int head, tail;
+} msnd_fifo; */
+
+
+
+struct snd_msnd {
+ void *mappedbase;
+ int play_period_bytes;
+ int playLimit;
+ int playPeriods;
+ int playDMAPos;
+ int captureDMAPos;
+ int capturePeriodBytes;
+ int captureLimit;
+ int capturePeriods;
+ struct snd_card *card;
+ void *msndmidi_mpu;
+ struct snd_rawmidi *rmidi;
+
+ /* Hardware resources */
+ long io;
+ int memid, irqid;
+ int irq, irq_ref;
+ unsigned long base;
+
+ /* Motorola 56k DSP SMA */
+ unsigned long SMA;
+ unsigned long DAPQ, DARQ, MODQ, MIDQ, DSPQ;
+ unsigned long pwDSPQData, pwMIDQData, pwMODQData;
+ int dspq_data_buff, dspq_buff_size;
+
+ /* State variables */
+ enum { msndClassic, msndPinnacle } type;
+ mode_t mode;
+ unsigned long flags;
+#define F_RESETTING 0
+#define F_HAVEDIGITAL 1
+#define F_AUDIO_WRITE_INUSE 2
+#define F_WRITING 3
+#define F_WRITEBLOCK 4
+#define F_WRITEFLUSH 5
+#define F_AUDIO_READ_INUSE 6
+#define F_READING 7
+#define F_READBLOCK 8
+#define F_EXT_MIDI_INUSE 9
+#define F_HDR_MIDI_INUSE 10
+#define F_DISABLE_WRITE_NDELAY 11
+ spinlock_t lock;
+ int nresets;
+ unsigned recsrc;
+#define LEVEL_ENTRIES 32
+ int left_levels[LEVEL_ENTRIES];
+ int right_levels[LEVEL_ENTRIES];
+ int mixer_mod_count;
+ int calibrate_signal;
+ int play_sample_size, play_sample_rate, play_channels;
+ int play_ndelay;
+ int capture_sample_size, capture_sample_rate, capture_channels;
+ int capture_ndelay;
+ u8 bCurrentMidiPatch;
+
+ int last_playbank, last_recbank;
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+};
+
+void snd_msnd_init_queue(unsigned long, int start, int size);
+
+int snd_msnd_wait_TXDE(struct snd_msnd *chip);
+int snd_msnd_wait_HC0(struct snd_msnd *chip);
+int snd_msnd_send_dsp_cmd(struct snd_msnd *chip, u8 cmd);
+int snd_msnd_send_word(struct snd_msnd *chip,
+ unsigned char high,
+ unsigned char mid,
+ unsigned char low);
+int snd_msnd_upload_host(struct snd_msnd *chip,
+ const u8 *bin, int len);
+int snd_msnd_enable_irq(struct snd_msnd *chip);
+int snd_msnd_disable_irq(struct snd_msnd *chip);
+
+
+int snd_msndmidi_new(struct snd_card *card, int device);
+void snd_msndmidi_input_read(void *mpu);
+
+static inline u8
+isa_readb(unsigned long offset)
+{
+ void __iomem *addr = ioremap(offset, 1);
+ u8 ret = readb(addr);
+ iounmap(addr);
+ return ret;
+}
+
+static inline u16
+isa_readw(unsigned long offset)
+{
+ void __iomem *addr = ioremap(offset, 2);
+ u16 ret = readw(addr);
+ iounmap(addr);
+ return ret;
+}
+
+static inline u32
+isa_readl(unsigned long offset)
+{
+ void __iomem *addr = ioremap(offset, 4);
+ u32 ret = readl(addr);
+ iounmap(addr);
+ return ret;
+}
+
+static inline void
+isa_writeb(u8 b, unsigned long offset)
+{
+ void __iomem *addr = ioremap(offset, 2);
+ writeb(b, addr);
+ iounmap(addr);
+}
+
+static inline void
+isa_writew(u16 w, unsigned long offset)
+{
+ void __iomem *addr = ioremap(offset, 2);
+ writew(w, addr);
+ iounmap(addr);
+}
+
+static inline void
+isa_writel(u32 l, unsigned long offset)
+{
+ void __iomem *addr = ioremap(offset, 4);
+ writel(l, addr);
+ iounmap(addr);
+}
+
+static inline void
+isa_memset_io(unsigned long offset, u8 val, long n)
+{
+ void __iomem *addr = ioremap(offset, n);
+ memset_io(addr, val, n);
+ iounmap(addr);
+}
+
+static inline void
+isa_memcpy_fromio(void *dest, unsigned long offset, long n)
+{
+ void __iomem *addr = ioremap(offset, n);
+ memcpy_fromio(dest, addr, n);
+ iounmap(addr);
+}
+
+static inline void
+isa_memcpy_toio(unsigned long offset, const void *src, long n)
+{
+ void __iomem *addr = ioremap(offset, n);
+ memcpy_toio(addr, src, n);
+ iounmap(addr);
+}
+
+#endif /* __MSND_H */
diff --git a/sound/isa/msnd/msnd_classic.c b/sound/isa/msnd/msnd_classic.c
new file mode 100644
index 0000000..3b23a09
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.c
@@ -0,0 +1,3 @@
+/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */
+#define MSND_CLASSIC
+#include "msnd_pinnacle.c"
diff --git a/sound/isa/msnd/msnd_classic.h b/sound/isa/msnd/msnd_classic.h
new file mode 100644
index 0000000..f4f2cc9
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.h
@@ -0,0 +1,182 @@
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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 __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO 0x10
+
+#define HP_MEMM 0x08
+
+#define HP_BITM 0x0E
+#define HP_WAIT 0x0D
+#define HP_DSPR 0x0A
+#define HP_PROR 0x0B
+#define HP_BLKS 0x0C
+
+#define HPPRORESET_OFF 0
+#define HPPRORESET_ON 1
+
+#define HPDSPRESET_OFF 0
+#define HPDSPRESET_ON 1
+
+#define HPBLKSEL_0 0
+#define HPBLKSEL_1 1
+
+#define HPWAITSTATE_0 0
+#define HPWAITSTATE_1 1
+
+#define HPBITMODE_16 0
+#define HPBITMODE_8 1
+
+#define HIDSP_INT_PLAY_UNDER 0x00
+#define HIDSP_INT_RECORD_OVER 0x01
+#define HIDSP_INPUT_CLIPPING 0x02
+#define HIDSP_MIDI_IN_OVER 0x10
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define HDEXAR_CLEAR_PEAKS 1
+#define HDEXAR_IN_SET_POTS 2
+#define HDEXAR_AUX_SET_POTS 3
+#define HDEXAR_CAL_A_TO_D 4
+#define HDEXAR_RD_EXT_DSP_BITS 5
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x0040
+#define TIME_PRO_RESET 0x0032
+
+#define AGND 0x01
+#define SIGNAL 0x02
+
+#define EXT_DSP_BIT_DCAL 0x0001
+#define EXT_DSP_BIT_MIDI_CON 0x0002
+
+#define BUFFSIZE 0x8000
+#define HOSTQ_SIZE 0x40
+
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DAP_BUFF_SIZE 0x2400
+#define DAR_BUFF_SIZE 0x2000
+
+#define DAPQ_STRUCT_SIZE 0x10
+#define DARQ_STRUCT_SIZE 0x10
+#define DAPQ_BUFF_SIZE (3 * 0x10)
+#define DARQ_BUFF_SIZE (3 * 0x10)
+#define MODQ_BUFF_SIZE 0x400
+#define MIDQ_BUFF_SIZE 0x200
+#define DSPQ_BUFF_SIZE 0x40
+
+#define DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+#define DSPQ_DATA_BUFF 0x7260
+
+#define DAPQ_OFFSET SRAM_CNTL_START
+#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
+
+#define MOP_SYNTH 0x10
+#define MOP_EXTOUT 0x32
+#define MOP_EXTTHRU 0x02
+#define MOP_OUTMASK 0x01
+
+#define MIP_EXTIN 0x01
+#define MIP_SYNTH 0x00
+#define MIP_INMASK 0x32
+
+/* Classic SMA Common Data */
+#define SMA_wCurrPlayBytes 0x0000
+#define SMA_wCurrRecordBytes 0x0002
+#define SMA_wCurrPlayVolLeft 0x0004
+#define SMA_wCurrPlayVolRight 0x0006
+#define SMA_wCurrInVolLeft 0x0008
+#define SMA_wCurrInVolRight 0x000a
+#define SMA_wUser_3 0x000c
+#define SMA_wUser_4 0x000e
+#define SMA_dwUser_5 0x0010
+#define SMA_dwUser_6 0x0014
+#define SMA_wUser_7 0x0018
+#define SMA_wReserved_A 0x001a
+#define SMA_wReserved_B 0x001c
+#define SMA_wReserved_C 0x001e
+#define SMA_wReserved_D 0x0020
+#define SMA_wReserved_E 0x0022
+#define SMA_wReserved_F 0x0024
+#define SMA_wReserved_G 0x0026
+#define SMA_wReserved_H 0x0028
+#define SMA_wCurrDSPStatusFlags 0x002a
+#define SMA_wCurrHostStatusFlags 0x002c
+#define SMA_wCurrInputTagBits 0x002e
+#define SMA_wCurrLeftPeak 0x0030
+#define SMA_wCurrRightPeak 0x0032
+#define SMA_wExtDSPbits 0x0034
+#define SMA_bExtHostbits 0x0036
+#define SMA_bBoardLevel 0x0037
+#define SMA_bInPotPosRight 0x0038
+#define SMA_bInPotPosLeft 0x0039
+#define SMA_bAuxPotPosRight 0x003a
+#define SMA_bAuxPotPosLeft 0x003b
+#define SMA_wCurrMastVolLeft 0x003c
+#define SMA_wCurrMastVolRight 0x003e
+#define SMA_bUser_12 0x0040
+#define SMA_bUser_13 0x0041
+#define SMA_wUser_14 0x0042
+#define SMA_wUser_15 0x0044
+#define SMA_wCalFreqAtoD 0x0046
+#define SMA_wUser_16 0x0048
+#define SMA_wUser_17 0x004a
+#define SMA__size 0x004c
+
+#ifdef HAVE_DSPCODEH
+# include "msndperm.c"
+# include "msndinit.c"
+# define PERMCODE msndperm
+# define INITCODE msndinit
+# define PERMCODESIZE sizeof(msndperm)
+# define INITCODESIZE sizeof(msndinit)
+#else
+# ifndef CONFIG_MSNDCLAS_INIT_FILE
+# define CONFIG_MSNDCLAS_INIT_FILE "turtlebeach/msndinit.bin"
+# endif
+# ifndef CONFIG_MSNDCLAS_PERM_FILE
+# define CONFIG_MSNDCLAS_PERM_FILE "turtlebeach/msndperm.bin"
+# endif
+# define PERMCODEFILE CONFIG_MSNDCLAS_PERM_FILE
+# define INITCODEFILE CONFIG_MSNDCLAS_INIT_FILE
+# define PERMCODE dspini
+# define INITCODE permini
+# define PERMCODESIZE sizeof_dspini
+# define INITCODESIZE sizeof_permini
+#endif
+#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
new file mode 100644
index 0000000..99feb40
--- /dev/null
+++ b/sound/isa/msnd/msnd_midi.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) by Jaroslav Kysela <perex(a)perex.cz>
+ * Routines for control of MPU-401 in UART mode
+ *
+ * MPU-401 supports UART mode which is not capable generate transmit
+ * interrupts thus output is done via polling. Also, if irq < 0, then
+ * input is done also via polling. Do not expect good performance.
+ *
+ *
+ * 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/io.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "msnd.h"
+#ifdef MSND_CLASSIC
+# ifdef CONFIG_MSNDCLAS_HAVE_BOOT
+# define HAVE_DSPCODEH
+# endif
+# include "msnd_classic.h"
+# define LOGNAME "msnd_classic"
+#else
+# ifdef CONFIG_MSNDPIN_HAVE_BOOT
+# define HAVE_DSPCODEH
+# endif
+# include "msnd_pinnacle.h"
+# define LOGNAME "snd_msnd_pinnacle"
+#endif
+
+
+#define MSNDMIDI_MODE_BIT_INPUT 0
+#define MSNDMIDI_MODE_BIT_OUTPUT 1
+#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2
+#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER 3
+
+#define MSNDMIDI_MODE_INPUT (1<<MSNDMIDI_MODE_BIT_INPUT)
+#define MSNDMIDI_MODE_OUTPUT (1<<MSNDMIDI_MODE_BIT_OUTPUT)
+#define MSNDMIDI_MODE_INPUT_TRIGGER (1<<MSNDMIDI_MODE_BIT_INPUT_TRIGGER)
+#define MSNDMIDI_MODE_OUTPUT_TRIGGER (1<<MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER)
+
+#define MSNDMIDI_MODE_INPUT_TIMER (1<<0)
+#define MSNDMIDI_MODE_OUTPUT_TIMER (1<<1)
+
+
+/*
+
+ */
+
+#define snd_msndmidi_input_avail(mpu) (!(inb(MPU401C(mpu)) & 0x80))
+#define snd_msndmidi_output_ready(mpu) (!(inb(MPU401C(mpu)) & 0x40))
+
+#define MPU401_RESET 0xff
+#define MPU401_ENTER_UART 0x3f
+#define MPU401_ACK 0xfe
+
+
+struct snd_msndmidi {
+ struct snd_rawmidi *rmidi;
+ struct snd_msnd *dev;
+
+ unsigned long mode; /* MSNDMIDI_MODE_XXXX */
+ int timer_invoked;
+
+ void *private_data;
+
+ struct snd_rawmidi_substream *substream_input;
+ struct snd_rawmidi_substream *substream_output;
+
+ spinlock_t input_lock;
+ spinlock_t output_lock;
+ spinlock_t timer_lock;
+
+ struct timer_list timer;
+};
+
+
+/* not used static void snd_msnd_midi_clear_rx(struct msndmidi *mpu)
+{/ * int timeout = 100000;
+ for (; timeout > 0 && snd_msndmidi_input_avail(mpu); timeout--)
+ inb(MPU401D(mpu));
+#ifdef CONFIG_SND_DEBUG
+ if (timeout <= 0)
+ snd_printk("cmd: clear rx timeout (status = 0x%x)\n", inb(MPU401C(mpu)));
+#endif
+* /
+} */
+
+/*
+static void _snd_msndmidi_interrupt(struct msndmidi *mpu)
+{
+ if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
+ snd_msndmidi_input_read(mpu);
+ else
+ snd_msndmidi_clear_rx(mpu);
+ / * ok. for better Tx performance try do some output when input is done * /
+ if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode))
+ snd_msndmidi_output_write(mpu);
+}
+
+void snd_msndmidi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct msndmidi *mpu = dev_id;
+
+ if (mpu == NULL)
+ return;
+ _snd_msndmidi_interrupt(mpu);
+}*/
+/*
+static void snd_msndmidi_timer(unsigned long data)
+{
+ unsigned long flags;
+ struct msndmidi *mpu = (void *)data;
+
+ spin_lock_irqsave(&mpu->timer_lock, flags);
+ / * mpu->mode |= MPU401_MODE_TIMER;* /
+ mpu->timer.expires = 1 + jiffies;
+ add_timer(&mpu->timer);
+ spin_unlock_irqrestore(&mpu->timer_lock, flags);
+ if (mpu->rmidi)
+ _snd_msndmidi_interrupt(mpu);
+}
+
+static void snd_msndmidi_add_timer (struct msndmidi *mpu, int input)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave (&mpu->timer_lock, flags);
+ if (mpu->timer_invoked == 0) {
+ mpu->timer.data = (unsigned long)mpu;
+ mpu->timer.function = snd_msndmidi_timer;
+ mpu->timer.expires = 1 + jiffies;
+ add_timer(&mpu->timer);
+ }
+ mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER;
+ spin_unlock_irqrestore (&mpu->timer_lock, flags);
+}
+
+static void snd_msndmidi_remove_timer (struct snd_msndmidi *mpu, int input)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave (&mpu->timer_lock, flags);
+ if (mpu->timer_invoked) {
+ mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : ~MPU401_MODE_OUTPUT_TIMER;
+ if (!mpu->timer_invoked)
+ del_timer(&mpu->timer);
+ }
+ spin_unlock_irqrestore (&mpu->timer_lock, flags);
+} */
+
+/*
+
+ */
+
+/* not used so far .... ?
+static void snd_msndmidi_cmd(struct snd_msndmidi *mpu, unsigned char cmd, int ack)
+{
+ unsigned long flags;
+ int timeout, ok;
+
+ spin_lock_irqsave(&mpu->input_lock, flags);
+/ * if (mpu->hardware != MPU401_HW_TRID4DWAVE) {
+ outb(0x00, MPU401D(mpu));
+ / * snd_msndmidi_clear_rx(mpu);* /
+ }
+ / * ok. standard MPU-401 initialization * /
+ if (mpu->hardware != MPU401_HW_SB) {
+ for (timeout = 1000; timeout > 0 && !snd_msndmidi_output_ready(mpu); timeout--)
+ udelay(10);
+#ifdef CONFIG_SND_DEBUG
+ if (!timeout)
+ snd_printk("cmd: tx timeout (status = 0x%x)\n", inb(MPU401C(mpu)));
+#endif
+ }
+ outb(cmd, MPU401C(mpu));
+ if (ack) {
+ ok = 0;
+ timeout = 10000;
+ while (!ok && timeout-- > 0) {
+ if (snd_msndmidi_input_avail(mpu)) {
+ if (inb(MPU401D(mpu)) == MPU401_ACK)
+ ok = 1;
+ }
+ }
+ if (!ok && inb(MPU401D(mpu)) == MPU401_ACK)
+ ok = 1;
+ } else {
+ ok = 1;
+ }* /
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+// if (!ok)
+// snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, inb(MPU401C(mpu)), inb(MPU401D(mpu)));
+ // snd_printk("cmd: 0x%x at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, inb(MPU401C(mpu)), inb(MPU401D(mpu)));
+} */
+
+/*
+ * input/output open/close - protected by open_mutex in rawmidi.c
+ */
+static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_msndmidi *mpu;
+// int err;
+#ifdef CONFIG_SND_DEBUG0
+ printk(KERN_DEBUG "snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)\n");
+#endif
+
+ mpu = substream->rmidi->private_data;
+/* if (mpu->open_input && (err = mpu->open_input(mpu)) < 0)
+ return err;
+ if (!test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) {
+ snd_msndmidi_cmd(mpu, MPU401_RESET, 1);
+ snd_msndmidi_cmd(mpu, MPU401_ENTER_UART, 1);
+ }*/
+
+ mpu->substream_input = substream;
+
+ // SetMidiInPort(EXTIN_MIP);
+ snd_msnd_enable_irq(mpu->dev);
+
+ snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
+ set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+ return 0;
+}
+
+static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_msndmidi *mpu;
+
+#ifdef CONFIG_SND_DEBUG0
+ printk(KERN_DEBUG "snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)\n");
+#endif
+
+ mpu = substream->rmidi->private_data;
+ snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
+ clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+ mpu->substream_input = NULL;
+ snd_msnd_disable_irq(mpu->dev);
+/* if (!test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode))
+ snd_msndmidi_cmd(mpu, MPU401_RESET, 0);
+ if (mpu->close_input)
+ mpu->close_input(mpu);*/
+ return 0;
+}
+
+static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
+{
+ u16 tail;
+
+ tail = isa_readw(mpu->dev->MIDQ + JQS_wTail);
+ isa_writew(tail, mpu->dev->MIDQ + JQS_wHead);
+}
+
+/*
+ * trigger input
+ */
+static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ unsigned long flags;
+ struct snd_msndmidi *mpu;
+// int max = 64;
+#ifdef CONFIG_SND_DEBUG0
+ printk(KERN_DEBUG "snd_msndmidi_input_trigger(, %i)\n", up);
+#endif
+
+ mpu = substream->rmidi->private_data;
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ if (up) {
+ if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
+ snd_msndmidi_input_drop(mpu);
+ } else {
+ clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
+ }
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+ if (up)
+ snd_msndmidi_input_read(mpu);
+}
+
+void snd_msndmidi_input_read(void *mpuv)
+{
+ unsigned long flags;
+ struct snd_msndmidi *mpu = mpuv;
+
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ while (isa_readw(mpu->dev->MIDQ + JQS_wTail) != isa_readw(mpu->dev->MIDQ + JQS_wHead)) {
+ u16 wTmp, val;
+ val = isa_readw(mpu->dev->pwMIDQData + 2*isa_readw(mpu->dev->MIDQ + JQS_wHead));
+
+ if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) {
+ // printk("MID: 0x%04X\n", (unsigned)val);
+ snd_rawmidi_receive(mpu->substream_input, (unsigned char *)&val, 1);
+ }
+
+ wTmp = isa_readw(mpu->dev->MIDQ + JQS_wHead) + 1;
+ if (wTmp > isa_readw(mpu->dev->MIDQ + JQS_wSize))
+ isa_writew(0, mpu->dev->MIDQ + JQS_wHead);
+ else
+ isa_writew(wTmp, mpu->dev->MIDQ + JQS_wHead);
+ }
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+}
+EXPORT_SYMBOL(snd_msndmidi_input_read);
+
+static struct snd_rawmidi_ops snd_msndmidi_input = {
+ .open = snd_msndmidi_input_open,
+ .close = snd_msndmidi_input_close,
+ .trigger = snd_msndmidi_input_trigger,
+};
+
+static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
+{
+ struct snd_msndmidi *mpu = rmidi->private_data;
+/* if (mpu->irq_flags && mpu->irq >= 0)
+ free_irq(mpu->irq, (void *) mpu);
+ if (mpu->res) {
+ release_resource(mpu->res);
+ kfree_nocheck(mpu->res);
+ }*/
+ kfree(mpu);
+}
+
+int snd_msndmidi_new(struct snd_card *card, int device)
+{
+ struct snd_msnd *chip = card->private_data;
+ struct snd_msndmidi *mpu;
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
+ if (err < 0)
+ return err;
+ mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL);
+ if (mpu == NULL) {
+ snd_device_free(card, rmidi);
+ return -ENOMEM;
+ }
+ mpu->dev = chip;
+ chip->msndmidi_mpu = mpu;
+ rmidi->private_data = mpu;
+ rmidi->private_free = snd_msndmidi_free;
+ spin_lock_init(&mpu->input_lock);
+ spin_lock_init(&mpu->output_lock);
+ spin_lock_init(&mpu->timer_lock);
+/* if (!integrated) {
+ if ((mpu->res = request_region(port, 2, "MPU401 UART")) == NULL) {
+ snd_device_free(card, rmidi);
+ return -EBUSY;
+ }
+ }
+ mpu->port = port;
+ if (irq >= 0 && irq_flags) {
+ if (request_irq(irq, snd_msndmidi_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) {
+ snd_printk("unable to grab IRQ %d\n", irq);
+ snd_device_free(card, rmidi);
+ return -EBUSY;
+ }
+ mpu->irq = irq;
+ mpu->irq_flags = irq_flags;
+ }*/
+ strcpy(rmidi->name, "MSND MIDI");
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_msndmidi_input);
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT ;
+ mpu->rmidi = rmidi;
+ return 0;
+}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
new file mode 100644
index 0000000..18b1e07
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -0,0 +1,1894 @@
+/*********************************************************************
+ *
+ * Linux multisound pinnacle/fiji driver for alsa 0.9rc2CVS
+ *
+ * 2002/06/30 Karsten Wiese:
+ * for now this is only used to build a pinnacle / fiji driver.
+ * the OSS parent of this code is designed to also support
+ * the multisound classic via the file msnd_classic.c.
+ * to make it easier for some brave heart to implemt classic
+ * support in alsa, i left all the MSND_CLASSIC tokens in this file.
+ * but for now this untested & undone.
+ *
+ *
+ * ripped from linux kernel 2.4.18 by Karsten Wiese.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ * msnd_pinnacle.c / msnd_classic.c
+ *
+ * -- If MSND_CLASSIC is defined:
+ *
+ * -> driver for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * -- Else
+ *
+ * -> driver for Turtle Beach Pinnacle/Fiji
+ *
+ * 12-3-2000 Modified IO port validation Steve Sycamore
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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.
+ *
+ ********************************************************************/
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+#include <sound/mpu401.h>
+#include <linux/isa.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/pnp.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+
+#ifdef MSND_CLASSIC
+# ifndef __alpha__
+# define SLOWIO
+# endif
+#endif
+#include "msnd.h"
+#ifdef MSND_CLASSIC
+# ifdef CONFIG_MSNDCLAS_HAVE_BOOT
+# define HAVE_DSPCODEH
+# endif
+# include "msnd_classic.h"
+# define LOGNAME "msnd_classic"
+#else
+# ifdef CONFIG_MSNDPIN_HAVE_BOOT
+# define HAVE_DSPCODEH
+# endif
+# include "msnd_pinnacle.h"
+# define LOGNAME "snd_msnd_pinnacle"
+#endif
+
+/* functions from external mixer file */
+void snd_msndmix_setup(struct snd_msnd *chip);
+unsigned long snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc);
+int __devinit snd_msndmix_new(struct snd_card *card);
+
+static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
+{
+ long tmp = (size * HZ * chip->play_sample_size) / 8;
+ return tmp / (chip->play_sample_rate * chip->play_channels);
+}
+
+static inline long get_rec_delay_jiffies(struct snd_msnd *chip, long size)
+{
+ long tmp = (size * HZ * chip->capture_sample_size) / 8;
+ return tmp / (chip->capture_sample_rate * chip->capture_channels);
+}
+
+#ifndef HAVE_DSPCODEH
+static const u8 *dspini, *permini;
+static int sizeof_dspini, sizeof_permini;
+#endif
+
+static int snd_msnd_dsp_full_reset(struct snd_card *card);
+
+int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
+{
+ if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
+ return 0;
+ snd_msnd_dsp_full_reset(chip->card);
+ return snd_msnd_send_dsp_cmd(chip, cmd);
+}
+
+static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ unsigned long lpDAQ;
+
+ chip->last_playbank = -1;
+ chip->playLimit = pcm_count * (pcm_periods - 1);
+ chip->playPeriods = pcm_periods;
+ isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
+ isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
+
+ chip->play_period_bytes = pcm_count;
+
+ lpDAQ = chip->base + DAPQ_DATA_BUFF;
+ for (n = 0; n < 3; ++n, lpDAQ += DAQDS__size) {
+ isa_writew(PCTODSP_BASED((u32)(pcm_count * (n % pcm_periods))), lpDAQ + DAQDS_wStart);
+ isa_writew(0, lpDAQ + DAQDS_wSize);
+ isa_writew(1, lpDAQ + DAQDS_wFormat);
+ isa_writew(chip->play_sample_size, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(chip->play_channels, lpDAQ + DAQDS_wChannels);
+ isa_writew(chip->play_sample_rate, lpDAQ + DAQDS_wSampleRate);
+ isa_writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+ isa_writew(n, lpDAQ + DAQDS_wFlags);
+ }
+}
+
+static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ unsigned long lpDAQ;
+ //unsigned long flags;
+
+// snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
+
+ chip->last_recbank = 2;
+ chip->captureLimit = pcm_count * (pcm_periods - 1);
+ chip->capturePeriods = pcm_periods;
+ isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
+ isa_writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size), chip->DARQ + JQS_wTail);
+
+ /* Critical section: bank 1 access. this is how the OSS driver does it:
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ isa_memset_io(chip->base, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);*/
+
+ chip->capturePeriodBytes = pcm_count;
+ //snd_printd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
+
+ for (n = 0, lpDAQ = chip->base + DARQ_DATA_BUFF; n < 3/*pcm_periods*/; ++n, lpDAQ += DAQDS__size) {
+ isa_writew(PCTODSP_BASED((u32)(pcm_count * (n % pcm_periods)) + 0x3000), lpDAQ + DAQDS_wStart);
+ isa_writew(pcm_count, lpDAQ + DAQDS_wSize);
+ isa_writew(1, lpDAQ + DAQDS_wFormat);
+ isa_writew(chip->capture_sample_size, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(chip->capture_channels, lpDAQ + DAQDS_wChannels);
+ isa_writew(chip->capture_sample_rate, lpDAQ + DAQDS_wSampleRate);
+ isa_writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+ isa_writew(n, lpDAQ + DAQDS_wFlags);
+ }
+}
+
+#ifdef NO0
+static void reset_queues(struct snd_msnd *chip)
+{
+ if (chip->mode & FMODE_WRITE) {
+ msnd_fifo_make_empty(&(chip->DAPF));
+ snd_msnd_reset_play_queue();
+ }
+ if (chip->mode & FMODE_READ) {
+ msnd_fifo_make_empty(&(chip.DARF));
+ snd_msnd_reset_capture_queue();
+ }
+}
+#endif
+
+
+static void dsp_write_flush(struct snd_msnd *chip)
+{
+ if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
+ return;
+ set_bit(F_WRITEFLUSH, &chip->flags);
+/* interruptible_sleep_on_timeout(
+ &chip->writeflush,
+ get_play_delay_jiffies(&chip, chip->DAPF.len));*/
+ clear_bit(F_WRITEFLUSH, &chip->flags);
+ if (!signal_pending(current))
+ schedule_timeout_interruptible(get_play_delay_jiffies(chip, chip->play_period_bytes));
+ clear_bit(F_WRITING, &chip->flags);
+}
+
+static void dsp_halt(struct snd_msnd *chip, struct file *file)
+{
+ if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
+ clear_bit(F_READING, &chip->flags);
+ snd_msnd_send_dsp_cmd_chk(chip, HDEX_RECORD_STOP);
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file);
+ chip->mode &= ~FMODE_READ;
+ }
+ clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ }
+ if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
+ if (test_bit(F_WRITING, &chip->flags)) {
+ dsp_write_flush(chip);
+ snd_msnd_send_dsp_cmd_chk(chip, HDEX_PLAY_STOP);
+ }
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file);
+ chip->mode &= ~FMODE_WRITE;
+ }
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ }
+}
+
+#ifdef NO0
+static int dsp_release(struct file *file)
+{
+ dsp_halt(file);
+ return 0;
+}
+#endif
+
+
+static void set_default_audio_parameters(struct snd_msnd *chip)
+{
+ chip->play_sample_size = DEFSAMPLESIZE;
+ chip->play_sample_rate = DEFSAMPLERATE;
+ chip->play_channels = DEFCHANNELS;
+ chip->capture_sample_size = DEFSAMPLESIZE;
+ chip->capture_sample_rate = DEFSAMPLERATE;
+ chip->capture_channels = DEFCHANNELS;
+}
+
+
+static int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
+{
+ int /*size, n,*/ timeout = 3;
+ u16 wTmp;
+ //unsigned long DAQD;
+
+ /* Increment the tail and check for queue wrap */
+ wTmp = isa_readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+ //printk(KERN_DEBUG "%iR wTmp = %i", bank, (int)wTmp);
+ if (wTmp > isa_readw(chip->DARQ + JQS_wSize))
+ wTmp = 0;
+ //printk(KERN_DEBUG " %i\n", (int)wTmp);
+ while (wTmp == isa_readw(chip->DARQ + JQS_wHead) && timeout--)
+ udelay(1);
+
+ if (chip->capturePeriods == 2) {
+ unsigned long lpDAQ = chip->base + DARQ_DATA_BUFF + bank * DAQDS__size + DAQDS_wStart;
+ unsigned short offset = isa_readw(lpDAQ);
+ isa_writew(offset == PCTODSP_BASED(0x3000) ? PCTODSP_BASED(0x3000 + chip->capturePeriodBytes) : PCTODSP_BASED(0x3000), lpDAQ);
+ }
+
+ isa_writew(wTmp, chip->DARQ + JQS_wTail);
+
+ /* Get our digital audio queue struct
+ DAQD = bank * DAQDS__size + chip->base + DARQ_DATA_BUFF;*/
+
+ /* Get length of data */
+ //size = isa_readw(DAQD + DAQDS_wSize);
+
+ /* Read data from the head (unprotected bank 1 access okay
+ since this is only called inside an interrupt) */
+// outb(HPBLKSEL_1, chip->io + HP_BLKS);
+/* if ((n = msnd_fifo_write(
+ &chip->DARF,
+ (char *)(chip->base + bank * DAR_BUFF_SIZE),
+ size, 0)) <= 0) {
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ return n;
+ }*/
+// outb(HPBLKSEL_0, chip->io + HP_BLKS);
+
+ return 1;
+}
+
+static int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
+{
+ u16 DAPQ_tail;
+ int protect = start, nbanks = 0;
+ unsigned long DAQD;
+ static int play_banks_submitted;
+ //unsigned long flags;
+ //spin_lock_irqsave(&chip->lock, flags); not necessary
+
+ DAPQ_tail = isa_readw(chip->DAPQ + JQS_wTail);
+ while (DAPQ_tail != isa_readw(chip->DAPQ + JQS_wHead) || start) {
+ int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
+
+ if (start) {
+ start = 0;
+ play_banks_submitted = 0;
+ }
+
+ /* Get our digital audio queue struct */
+ DAQD = bank_num * DAQDS__size + chip->base + DAPQ_DATA_BUFF;
+
+ /* Write size of this bank */
+ isa_writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
+ if (play_banks_submitted < 3)
+ ++play_banks_submitted;
+ else {
+ if (chip->playPeriods == 2) {
+ unsigned short offset = isa_readw(DAQD + DAQDS_wStart);
+ isa_writew(offset == PCTODSP_BASED(0x0) ? PCTODSP_BASED(0x0 + chip->play_period_bytes): PCTODSP_BASED(0x0), DAQD + DAQDS_wStart);
+ }
+ }
+ ++nbanks;
+
+ /* Then advance the tail */
+ /*
+ if (protect)
+ snd_printd("B %X %lX\n", bank_num, xtime.tv_usec);
+ */
+
+ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+ isa_writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
+ /* Tell the DSP to play the bank */
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
+ if (protect)
+ if (2 == bank_num)
+ break;
+ }
+ /*
+ if (protect)
+ snd_printd("%lX\n", xtime.tv_usec);
+ */
+ //spin_unlock_irqrestore(&chip->lock, flags); not necessary
+ return nbanks;
+}
+
+
+static int InTrigger; // interrupt diagnostic, comment this out later
+static int banksPlayed;
+//static int playPosQueriesSinceInt;
+//static int play_bytes_remaining_last;
+//static int play_bytes_jiffies_last;
+
+static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
+{
+ switch (HIBYTE(wMessage)) {
+ case HIMT_PLAY_DONE: {
+ //snd_printd("snd_msnd_eval_dsp_msg(%i)\n", wMessage);
+ #ifdef CONFIG_SND_DEBUG0
+ if (banksPlayed < 3)
+ printk(KERN_DEBUG "%08X: HIMT_PLAY_DONE: %i\n", (unsigned)jiffies, LOBYTE(wMessage));
+ #endif
+ #ifdef CONFIG_SND_DEBUG0
+ {
+ int xx = *(short int*)(__ISA_IO_base + 0x7F40 + dev->base);
+ printk(KERN_DEBUG "%08X: P %X\n", (unsigned)jiffies, xx);
+ }
+ #endif
+
+ if (chip->last_playbank == LOBYTE(wMessage)) {
+ snd_printd("chip.last_playbank == LOBYTE(wMessage)\n");
+ break;
+ }
+ banksPlayed++;
+
+ if (test_bit(F_WRITING, &chip->flags))
+ snd_msnd_DAPQ(chip, 0);
+
+ chip->last_playbank = LOBYTE(wMessage);
+ chip->playDMAPos += chip->play_period_bytes;
+ if (chip->playDMAPos > chip->playLimit)
+ chip->playDMAPos = 0;
+ //playPosQueriesSinceInt = 0;
+ snd_pcm_period_elapsed(chip->playback_substream);
+ //play_bytes_remaining_last += chip->play_period_bytes;
+
+ break;
+ }
+ case HIMT_RECORD_DONE:
+ if (chip->last_recbank == LOBYTE(wMessage))
+ break;
+ chip->last_recbank = LOBYTE(wMessage);
+ chip->captureDMAPos += chip->capturePeriodBytes;
+ if (chip->captureDMAPos > (chip->captureLimit))
+ chip->captureDMAPos = 0;
+
+ if (test_bit(F_READING, &chip->flags))
+ snd_msnd_DARQ(chip, chip->last_recbank);
+
+ snd_pcm_period_elapsed(chip->capture_substream);
+ break;
+
+ case HIMT_DSP:
+ switch (LOBYTE(wMessage)) {
+#ifndef MSND_CLASSIC
+ case HIDSP_PLAY_UNDER:
+#endif
+ case HIDSP_INT_PLAY_UNDER:
+ printk(KERN_DEBUG LOGNAME ": Play underflow %i\n", banksPlayed);
+ if (banksPlayed > 2)
+ clear_bit(F_WRITING, &chip->flags);
+ break;
+
+ case HIDSP_INT_RECORD_OVER:
+ printk(KERN_DEBUG LOGNAME ": Record overflow\n");
+ clear_bit(F_READING, &chip->flags);
+ break;
+
+ default:
+ printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n",
+ LOBYTE(wMessage), LOBYTE(wMessage));
+ break;
+ }
+ break;
+
+ case HIMT_MIDI_IN_UCHAR:
+printk(KERN_DEBUG "msnd midi int");
+ if (chip->msndmidi_mpu)
+ snd_msndmidi_input_read(chip->msndmidi_mpu);
+ break;
+
+ default:
+ printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage));
+ break;
+ }
+}
+
+//static int InInterrupt = 0;
+irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
+{
+ struct snd_msnd *chip = dev_id;
+ /*if (InInterrupt) {
+ printk(KERN_DEBUG "INTERRUPT in InInterrupt\n");
+ return IRQ_NONE;
+ }
+ InInterrupt = 1;*/
+#ifdef CONFIG_SND_DEBUG
+ // interrupt diagnostic, comment this out later
+ if (InTrigger)
+ printk(KERN_DEBUG "INTERRUPT in InTrigger %i\n", InTrigger); // should never happen
+#endif
+ /* Send ack to DSP */
+// inb(chip->io + HP_RXL);
+
+ /* Evaluate queued DSP messages */
+ while (isa_readw(chip->DSPQ + JQS_wTail) != isa_readw(chip->DSPQ + JQS_wHead)) {
+ u16 wTmp;
+
+ snd_msnd_eval_dsp_msg(chip, isa_readw(chip->pwDSPQData + 2*isa_readw(chip->DSPQ + JQS_wHead)));
+
+ wTmp = isa_readw(chip->DSPQ + JQS_wHead) + 1;
+ if (wTmp > isa_readw(chip->DSPQ + JQS_wSize))
+ isa_writew(0, chip->DSPQ + JQS_wHead);
+ else
+ isa_writew(wTmp, chip->DSPQ + JQS_wHead);
+ }
+ /* Send ack to DSP */
+ inb(chip->io + HP_RXL);
+ //InInterrupt = 0;
+ return IRQ_HANDLED;
+}
+
+
+static int snd_msnd_reset_dsp(long io, unsigned char *info)
+{
+ int timeout = 100;
+
+ outb(HPDSPRESET_ON, io + HP_DSPR);
+ msleep(1);
+#ifndef MSND_CLASSIC
+ if (info)
+ *info = inb(io + HP_INFO);
+#endif
+ outb(HPDSPRESET_OFF, io + HP_DSPR);
+ msleep(1);
+ while (timeout-- > 0) {
+ if (inb(io + HP_CVR) == HP_CVR_DEF)
+ return 0;
+ msleep(1);
+ }
+ printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+ return -EIO;
+}
+
+static int __devinit snd_msnd_probe(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ unsigned char info;
+#ifndef MSND_CLASSIC
+ char *xv, *rev = NULL;
+ char *pin = "TB Pinnacle", *fiji = "TB Fiji";
+ char *pinfiji = "TB Pinnacle/Fiji";
+#endif
+
+ if (!request_region(chip->io, DSP_NUMIO, "probing")) {
+ printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+ return -ENODEV;
+ }
+
+ if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
+ release_region(chip->io, DSP_NUMIO);
+ return -ENODEV;
+ }
+
+#ifdef MSND_CLASSIC
+ strcpy(card->shortname, "Classic/Tahiti/Monterey");
+ printk(KERN_INFO LOGNAME ": %s, "
+#else
+ switch (info >> 4) {
+ case 0xf:
+ xv = "<= 1.15";
+ break;
+ case 0x1:
+ xv = "1.18/1.2";
+ break;
+ case 0x2:
+ xv = "1.3";
+ break;
+ case 0x3:
+ xv = "1.4";
+ break;
+ default:
+ xv = "unknown";
+ break;
+ }
+
+ switch (info & 0x7) {
+ case 0x0:
+ rev = "I";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x1:
+ rev = "F";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x2:
+ rev = "G";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x3:
+ rev = "H";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x4:
+ rev = "E";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x5:
+ rev = "C";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x6:
+ rev = "D";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x7:
+ rev = "A-B (Fiji) or A-E (Pinnacle)";
+ strcpy(card->shortname, pinfiji);
+ break;
+ }
+ printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
+#endif /* MSND_CLASSIC */
+ "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+ card->shortname,
+#ifndef MSND_CLASSIC
+ rev, xv,
+#endif
+ chip->io, chip->io + DSP_NUMIO - 1,
+ chip->irq,
+ chip->base, chip->base + 0x7fff);
+
+ strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
+ release_region(chip->io, DSP_NUMIO);
+ return 0;
+}
+
+static int snd_msnd_init_sma(struct snd_msnd *chip)
+{
+ static int initted;
+ u16 mastVolLeft, mastVolRight;
+ unsigned long flags;
+
+#ifdef MSND_CLASSIC
+ outb(chip->memid, chip->io + HP_MEMM);
+#endif
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ if (initted) {
+ mastVolLeft = isa_readw(chip->SMA + SMA_wCurrMastVolLeft);
+ mastVolRight = isa_readw(chip->SMA + SMA_wCurrMastVolRight);
+ } else
+ mastVolLeft = mastVolRight = 0;
+ isa_memset_io(chip->base, 0, 0x8000);
+
+ /* Critical section: bank 1 access */
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ isa_memset_io(chip->base, 0, 0x8000);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ chip->pwDSPQData = (chip->base + DSPQ_DATA_BUFF);
+ chip->pwMODQData = (chip->base + MODQ_DATA_BUFF);
+ chip->pwMIDQData = (chip->base + MIDQ_DATA_BUFF);
+
+ /* Motorola 56k shared memory base */
+ chip->SMA = chip->base + SMA_STRUCT_START;
+
+ /* Digital audio play queue */
+ chip->DAPQ = chip->base + DAPQ_OFFSET;
+ snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
+
+ /* Digital audio record queue */
+ chip->DARQ = chip->base + DARQ_OFFSET;
+ snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
+
+ /* MIDI out queue */
+ chip->MODQ = chip->base + MODQ_OFFSET;
+ snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
+
+ /* MIDI in queue */
+ chip->MIDQ = chip->base + MIDQ_OFFSET;
+ snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
+
+ /* DSP -> host message queue */
+ chip->DSPQ = chip->base + DSPQ_OFFSET;
+ snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
+
+ /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+ isa_writew(1, chip->SMA + SMA_wCurrPlayFormat);
+ isa_writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
+ isa_writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
+ isa_writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
+#endif
+ isa_writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
+ isa_writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
+ isa_writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
+#ifndef MSND_CLASSIC
+ isa_writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
+ isa_writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
+#endif
+ isa_writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
+
+ initted = 1;
+
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+static int __devinit snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
+{
+ snd_printd("snd_msnd_calibrate_adc(%i)\n", srate);
+ isa_writew(srate, chip->SMA + SMA_wCalFreqAtoD);
+ if (chip->calibrate_signal == 0)
+ isa_writew(isa_readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ else
+ isa_writew(isa_readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+ snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
+ schedule_timeout_interruptible(msecs_to_jiffies(333));
+ return 0;
+ }
+ printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
+ return -EIO;
+}
+
+static int upload_dsp_code(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+#ifndef HAVE_DSPCODEH
+ const struct firmware *init_fw = NULL, *perm_fw = NULL;
+#endif
+ int err;
+
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+#ifndef HAVE_DSPCODEH
+
+ err = request_firmware(&init_fw, INITCODEFILE, card->dev);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+ goto cleanup1;
+ }
+ err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+ goto cleanup;
+ }
+ INITCODE = init_fw->data;
+ INITCODESIZE = init_fw->size;
+ PERMCODE = perm_fw->data;
+ PERMCODESIZE = perm_fw->size;
+#endif
+ isa_memcpy_toio(chip->base, PERMCODE, PERMCODESIZE);
+ if (snd_msnd_upload_host(chip, INITCODE, INITCODESIZE) < 0) {
+ printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ err = -ENODEV;
+ goto cleanup;
+ }
+#ifdef HAVE_DSPsleep
+ printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n");
+#else
+ printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
+#endif
+ err = 0;
+
+cleanup:
+#ifndef HAVE_DSPCODEH
+ release_firmware(perm_fw);
+cleanup1:
+ release_firmware(init_fw);
+#endif
+ return err;
+}
+
+#ifdef MSND_CLASSIC
+static void reset_proteus(struct snd_msnd *chip)
+{
+ outb(HPPRORESET_ON, chip->io + HP_PROR);
+ msleep(TIME_PRO_RESET);
+ outb(HPPRORESET_OFF, chip->io + HP_PROR);
+ msleep(TIME_PRO_RESET_DONE);
+}
+#endif
+
+static int snd_msnd_initialize(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int err, timeout;
+ //snd_printd("snd_msnd_initialize(void)\n");
+
+#ifdef MSND_CLASSIC
+ outb(HPWAITSTATE_0, chip->io + HP_WAIT);
+ outb(HPBITMODE_16, chip->io + HP_BITM);
+
+ reset_proteus(chip);
+#endif
+ err = snd_msnd_init_sma(chip);
+ if (err < 0) {
+ printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+ return err;
+ }
+
+ err = snd_msnd_reset_dsp(chip->io, NULL);
+ if (err < 0)
+ return err;
+
+ err = upload_dsp_code(card);
+ if (err < 0) {
+ printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+ return err;
+ }
+
+ timeout = 200;
+
+ //snd_printd("%li\n", chip->base);
+ while (isa_readw(chip->base)) {
+ msleep(1);
+ if (!timeout--) {
+ printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n");
+ return -EIO;
+ }
+ }
+
+ snd_msndmix_setup(chip);
+ return 0;
+}
+
+static int snd_msnd_dsp_full_reset(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int rv;
+
+ if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
+ return 0;
+
+ set_bit(F_RESETTING, &chip->flags);
+ dsp_halt(chip, NULL); /* Unconditionally halt */
+
+ rv = snd_msnd_initialize(card);
+ if (rv)
+ printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+ snd_msndmix_force_recsrc(chip, 0);
+ clear_bit(F_RESETTING, &chip->flags);
+ return rv;
+}
+
+static int snd_msnd_dev_free(struct snd_device *device)
+{
+ snd_printd("snd_msnd_chip_free()\n");
+ return 0;
+}
+
+static struct snd_pcm_hardware snd_msnd_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 0x3000,
+ .period_bytes_min = 0x40,
+ .period_bytes_max = 0x1800,
+ .periods_min = 2,
+ .periods_max = 3,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware snd_msnd_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 0x3000,
+ .period_bytes_min = 0x40,
+ .period_bytes_max = 0x1800,
+ .periods_min = 2,
+ .periods_max = 3,
+ .fifo_size = 0,
+};
+
+
+static unsigned int rates[] = {
+ 8000, 11025, 16000, 22050,
+ 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ //snd_printd("snd_msnd_playback_open()\n");
+
+ set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_enable_irq(chip);
+
+ runtime->dma_area = chip->mappedbase;
+ //memset(__ISA_IO_base + chip->base, 0, 3*0x2400);
+ runtime->dma_bytes = 0x3000;
+
+ chip->playback_substream = substream;
+ runtime->hw = snd_msnd_playback;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+ return 0;
+}
+
+static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ //snd_printd("snd_msnd_playback_close()\n");
+ snd_msnd_disable_irq(chip);
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ return 0;
+}
+
+
+static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ int i;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned long lpDAQ = chip->base + DAPQ_DATA_BUFF;
+
+ //this results in 8 with the 2 synts amsynth & bristol so for now i hardcode it:
+ //chip->play_sample_size = snd_pcm_format_width(substream->runtime->format);
+ //printk(KERN_DEBUG "chip->play_sample_size %i\n", chip->play_sample_size);
+ chip->play_sample_size = 16;
+ chip->play_channels = params_channels(params);
+ chip->play_sample_rate = params_rate(params);
+
+ //snd_printd("snd_msnd_playback_hw_params()\n");
+ //snd_printd("f: %i; c: %i; r: %i\n", chip->play_sample_size, chip->play_channels, chip->play_sample_rate);
+
+ for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size) {
+ isa_writew(chip->play_sample_size, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(chip->play_channels, lpDAQ + DAQDS_wChannels);
+ isa_writew(chip->play_sample_rate, lpDAQ + DAQDS_wSampleRate);
+ }
+ // dont do this here: snd_msnd_calibrate_adc(chip->play_sample_rate);
+
+ return 0;
+}
+
+
+
+/*static int snd_msnd_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_printd("snd_msnd_playback_hw_free()\n");
+ return 0;
+} */
+
+static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+ unsigned int pcm_periods = pcm_size / pcm_count;
+
+ //snd_printd("snd_msnd_playback_prepare()\n");
+ //snd_printd("buffer_bytes=%i; period_bytes=%i\n", pcm_size, pcm_count);
+ snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
+ chip->playDMAPos = 0;
+ return 0;
+}
+
+//static int played_bytes;
+static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ int result = 0;
+
+ //spin_lock(&chip->reg_lock);
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ //snd_printd("snd_msnd_playback_trigger(START)\n");
+ InTrigger = 1; // interrupt diagnostic, comment this out later
+ //play_bytes_remaining_last = 0;
+ banksPlayed = 0;
+ //playPosQueriesSinceInt = 0;
+ //played_bytes = -1;
+ set_bit(F_WRITING, &chip->flags);
+ // this gives looong timeouts, so dont do it here: snd_msnd_calibrate_adc(chip->play_sample_rate);
+ snd_msnd_DAPQ(chip, 1);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ //snd_printd("snd_msnd_playback_trigger(STop)\n");
+ InTrigger = 2; // interrupt diagnostic, comment this out later
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ } else {
+ snd_printd("snd_msnd_playback_trigger(?????)\n");
+ result = -EINVAL;
+ }
+ InTrigger = 0; // interrupt diagnostic, comment this out later
+ // spin_unlock(&chip->reg_lock);
+
+ //snd_printd("snd_msnd_playback_trigger() ENDE\n");
+ return result;
+}
+
+static snd_pcm_uframes_t snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ //snd_printd("snd_msnd_playback_pointer()\n");
+
+ /* with the following mess i tried to generate a more precise pointer position
+ * it generated errors with the alsa framework i could not resolve.....
+ //int pos = dev.playDMAPos;
+ unsigned remaining = *(short int*)(__ISA_IO_base + 0x7F40 + dev.base),
+ ljiffies = (unsigned)jiffies;
+ int diff;
+ if (-1 == played_bytes) {
+ if (0 == remaining)
+ played_bytes = 0;
+ else
+ played_bytes = dev.play_period_bytes - remaining;
+ // played_bytes += 0x60;
+ } else {
+ int ref = (ljiffies - play_bytes_jiffies_last)
+ * (runtime->frame_bits / 16)
+ * (runtime->rate /HZ);
+ diff = play_bytes_remaining_last - remaining;
+ //printk(KERN_DEBUG "pb %i diff %i ref %i", played_bytes, diff, ref);
+ if (diff < ref) {
+ diff += dev.play_period_bytes;
+ //printk(" newdiff %i ", diff);
+ }
+ played_bytes += diff;
+ //printk("\n");
+ }
+
+ play_bytes_remaining_last = remaining;
+ play_bytes_jiffies_last = ljiffies;
+ played_bytes %= snd_msnd_playback.buffer_bytes_max;
+
+ // if (playPosQueriesSinceInt++)
+ // pos += dev.play_period_bytes - remaining;
+
+ {
+ snd_printd("%08X: remaining %04X\n", (unsigned)jiffies, remaining);
+ snd_printd("snd_msnd_playback_pointer() %X\n", played_bytes);
+ }
+
+ diff = dev.playDMAPos - played_bytes;
+ if (diff < 0)
+ diff += snd_msndpinnacle_playback.buffer_bytes_max;
+
+ return bytes_to_frames(runtime,
+ diff < (snd_msndpinnacle_playback.buffer_bytes_max / 2)
+ ? dev.playDMAPos : played_bytes);
+ // end of mess
+ */
+ return bytes_to_frames(substream->runtime, chip->playDMAPos);
+}
+
+
+static struct snd_pcm_ops snd_msnd_playback_ops = {
+ .open = snd_msnd_playback_open,
+ .close = snd_msnd_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_msnd_playback_hw_params,
+ .prepare = snd_msnd_playback_prepare,
+ .trigger = snd_msnd_playback_trigger,
+ .pointer = snd_msnd_playback_pointer,
+};
+
+static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ set_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ snd_msnd_enable_irq(chip);
+ runtime->dma_area = chip->mappedbase + 0x3000;
+ runtime->dma_bytes = 0x3000;
+ memset(runtime->dma_area, 0, runtime->dma_bytes);
+ chip->capture_substream = substream;
+ runtime->hw = snd_msnd_capture;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+ return 0;
+}
+
+static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ snd_msnd_disable_irq(chip);
+ clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ return 0;
+}
+
+static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+ unsigned int pcm_periods = pcm_size / pcm_count;
+
+ snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
+ chip->captureDMAPos = 0;
+ return 0;
+}
+
+static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ chip->last_recbank = -1;
+ set_bit(F_READING, &chip->flags);
+ if (snd_msnd_send_dsp_cmd_chk(chip, HDEX_RECORD_START) == 0)
+ return 0;
+
+ clear_bit(F_READING, &chip->flags);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ clear_bit(F_READING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static snd_pcm_uframes_t snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ return bytes_to_frames(runtime, chip->captureDMAPos);
+}
+
+
+static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ int i;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned long lpDAQ = chip->base + DARQ_DATA_BUFF;
+
+ //this results in 8 with the 2 synts amsynth & bristol so for now i hardcode it:
+ //chip->play_sample_size = snd_pcm_format_width(substream->runtime->format);
+ //printk(KERN_DEBUG "chip->play_sample_size %i\n", chip->play_sample_size);
+ chip->capture_sample_size = 16;
+ chip->capture_channels = params_channels(params);
+ chip->capture_sample_rate = params_rate(params);
+
+ //snd_printd("snd_msnd_capture_hw_params()\n");
+ //snd_printd("f: %i; c: %i; r: %i\n", chip->capture_sample_size, chip->capture_channels, chip->capture_sample_rate);
+
+ for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size) {
+ isa_writew(chip->capture_sample_size, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(chip->capture_channels, lpDAQ + DAQDS_wChannels);
+ isa_writew(chip->capture_sample_rate, lpDAQ + DAQDS_wSampleRate);
+ }
+ return 0;
+}
+
+
+static struct snd_pcm_ops snd_msnd_capture_ops = {
+ .open = snd_msnd_capture_open,
+ .close = snd_msnd_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_msnd_capture_hw_params,
+ .prepare = snd_msnd_capture_prepare,
+ .trigger = snd_msnd_capture_trigger,
+ .pointer = snd_msnd_capture_pointer,
+};
+
+
+int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm)
+{
+ struct snd_msnd *chip = card->private_data;
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
+
+ pcm->private_free = NULL;//snd_msnd_pcm_free;
+ pcm->private_data = chip;
+ pcm->info_flags = 0;//SNDRV_PCM_INFO_HALF_DUPLEX;
+ strcpy(pcm->name, "Hurricane");
+
+
+ if (rpcm)
+ *rpcm = pcm;
+ return 0;
+}
+
+/*
+ * ALSA callback function, called when attempting to open the MIDI device.
+ */
+static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
+{
+ snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
+ return 0;
+}
+
+static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
+{
+ snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
+}
+
+static long mpu_io[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
+
+static int __devinit snd_msnd_attach(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_msnd_dev_free,
+ };
+
+ err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
+ chip);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
+ return err;
+ }
+ request_region(chip->io, DSP_NUMIO, card->shortname);
+
+ if (!request_mem_region((unsigned)(__ISA_IO_base + chip->base), BUFFSIZE, card->shortname)) {
+ printk(KERN_ERR LOGNAME ": unable to grab memory region 0x%lx-0x%lx\n",
+ chip->base, chip->base + BUFFSIZE - 1);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ return -EBUSY;
+ }
+ chip->mappedbase = __ISA_IO_base + chip->base;
+
+ snd_printd("chip->mappedbase = 0x%08X\n", (unsigned)chip->mappedbase);
+
+ err = snd_msnd_dsp_full_reset(card);
+ if (err < 0)
+ goto err_release_region;
+
+ /* Register device */
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0)
+ goto err_release_region;
+
+ err = snd_msnd_pcm(card, 0, NULL);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
+ goto err_release_region;
+ }
+
+ err = snd_msndmix_new(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
+ goto err_release_region;
+ }
+
+
+ if (mpu_io[0] != SNDRV_AUTO_PORT)
+ {
+ struct snd_mpu401 *mpu;
+
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_io[0],
+ MPU401_MODE_INPUT |
+ MPU401_MODE_OUTPUT,
+ mpu_irq[0], IRQF_DISABLED,
+ &chip->rmidi);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new Midi device\n");
+ goto err_release_region;
+ }
+ mpu = chip->rmidi->private_data;
+
+ mpu->open_input = snd_msnd_mpu401_open;
+ mpu->close_input = snd_msnd_mpu401_close;
+ mpu->private_data = chip;
+ }
+
+ disable_irq(chip->irq);
+ snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
+ snd_msndmix_force_recsrc(chip, 0);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto err_release_region;
+
+ return 0;
+
+err_release_region:
+ release_mem_region(__ISA_IO_base + chip->base, BUFFSIZE);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ return err;
+}
+
+
+static void __devexit snd_msnd_unload(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+
+ release_mem_region(__ISA_IO_base + chip->base, BUFFSIZE);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ snd_card_free(card);
+}
+
+#ifndef MSND_CLASSIC
+
+/* Pinnacle/Fiji Logical Device Configuration */
+
+static int __devinit snd_msnd_write_cfg(int cfg, int reg, int value)
+{
+ outb(reg, cfg);
+ outb(value, cfg + 1);
+ if (value != inb(cfg + 1)) {
+ printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_mem(int cfg, int num, int mem)
+{
+ u16 wmem;
+
+ mem >>= 8;
+ wmem = (u16)(mem & 0xfff);
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+ return -EIO;
+ if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT)))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_activate_logical(int cfg, int num)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_logical(int cfg, int num, u16 io0, u16 io1, u16 irq, int mem)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg_io0(cfg, num, io0))
+ return -EIO;
+ if (snd_msnd_write_cfg_io1(cfg, num, io1))
+ return -EIO;
+ if (snd_msnd_write_cfg_irq(cfg, num, irq))
+ return -EIO;
+ if (snd_msnd_write_cfg_mem(cfg, num, mem))
+ return -EIO;
+ if (snd_msnd_activate_logical(cfg, num))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_pinnacle_cfg_reset(int cfg)
+{
+ int i;
+
+ /* Reset devices if told to */
+ printk(KERN_INFO LOGNAME ": Resetting all devices\n");
+ for (i = 0; i < 4; ++i)
+ if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
+
+static long io[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
+static long mem[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+
+static long cfg[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+
+#ifndef MSND_CLASSIC
+/* Extra Peripheral Configuration (Default: Disable) */
+static long ide_io0[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+static long ide_io1[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+static int ide_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
+
+static long joystick_io[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
+/* If we have the digital daugherboard... */
+static int digital[SNDRV_CARDS] __devinitdata;
+
+/* Extra Peripheral Configuration */
+static int reset[SNDRV_CARDS] __devinitdata;
+#endif
+
+static int write_ndelay[SNDRV_CARDS] __devinitdata =
+ { [0 ... (SNDRV_CARDS-1)] = 1 };
+
+#ifdef CONFIG_PNP
+static int isapnp[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_ENABLE_PNP;
+#endif
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Wiese <annabellesgarden(a)yahoo.de>");
+MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_LICENSE("GPL");
+#ifndef HAVE_DSPCODEH
+MODULE_FIRMWARE(INITCODEFILE);
+MODULE_FIRMWARE(PERMCODEFILE);
+#endif
+
+#ifndef MSND_CLASSIC
+//static int play_period_bytes __initdata = DAP_BUFF_SIZE;
+#endif
+
+static int calibrate_signal __devinitdata;
+
+module_param_array(io, long, NULL, S_IRUGO);
+MODULE_PARM_DESC(io, "IO port #");
+module_param_array(irq, int, NULL, S_IRUGO);
+module_param_array(mem, long, NULL, S_IRUGO);
+module_param_array(write_ndelay, int, NULL, S_IRUGO);
+module_param(calibrate_signal, int, S_IRUGO);
+#ifndef MSND_CLASSIC
+module_param_array(digital, int, NULL, S_IRUGO);
+module_param_array(cfg, long, NULL, S_IRUGO);
+module_param_array(reset, int, 0, S_IRUGO);
+module_param_array(mpu_io, long, NULL, S_IRUGO);
+module_param_array(mpu_irq, int, NULL, S_IRUGO);
+module_param_array(ide_io0, long, NULL, S_IRUGO);
+module_param_array(ide_io1, long, NULL, S_IRUGO);
+module_param_array(ide_irq, int, NULL, S_IRUGO);
+module_param_array(joystick_io, long, NULL, S_IRUGO);
+#ifdef CONFIG_PNP
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
+#endif
+#endif
+
+#else /* not a module */
+
+#ifndef CONFIG_MSND_CALSIGNAL
+# define CONFIG_MSND_CALSIGNAL 0
+#endif
+static int
+calibrate_signal __devinitdata = CONFIG_MSND_CALSIGNAL;
+#endif /* MODULE */
+
+
+static int __devinit snd_msnd_isa_match(struct device *pdev, unsigned int i)
+{
+ if (io[i] == SNDRV_AUTO_PORT)
+ return 0;
+
+ if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
+ printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+ return 0;
+ }
+
+#ifdef MSND_CLASSIC
+ if (!(io[i] == 0x290 ||
+ io[i] == 0x260 ||
+ io[i] == 0x250 ||
+ io[i] == 0x240 ||
+ io[i] == 0x230 ||
+ io[i] == 0x220 ||
+ io[i] == 0x210 ||
+ io[i] == 0x3e0)) {
+ printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n");
+ return 0;
+ }
+#else
+ if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
+ printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must within the range 0x100 to 0x3E0 and must be evenly divisible by 0x10\n");
+ return 0;
+ }
+#endif /* MSND_CLASSIC */
+
+ if (!(irq[i] == 5 ||
+ irq[i] == 7 ||
+ irq[i] == 9 ||
+ irq[i] == 10 ||
+ irq[i] == 11 ||
+ irq[i] == 12)) {
+ printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+ return 0;
+ }
+
+ if (!(mem[i] == 0xb0000 ||
+ mem[i] == 0xc8000 ||
+ mem[i] == 0xd0000 ||
+ mem[i] == 0xd8000 ||
+ mem[i] == 0xe0000 ||
+ mem[i] == 0xe8000)) {
+ printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+ "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+ return 0;
+ }
+
+#ifndef MSND_CLASSIC
+ if (cfg[i] == SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ } else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
+ printk(KERN_INFO LOGNAME ": Config port must be 0x250, 0x260 or 0x270 (or unspecified for PnP mode)\n");
+ return 0;
+ }
+#endif /* MSND_CLASSIC */
+
+ return 1;
+}
+
+static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
+{
+ int err;
+ struct snd_card *card;
+ struct snd_msnd *chip;
+
+ printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+ VERSION ", Copyright (C) 2002 Karsten Wiese 1998 Andrew Veliath\n");
+
+ if (isapnp[idx] || cfg[idx] == SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ return -ENODEV;
+ }
+
+ card = snd_card_new(index[idx], id[idx], THIS_MODULE, sizeof(struct snd_msnd));
+ if (!card)
+ return -ENOMEM;
+
+ snd_card_set_dev(card, pdev);
+ chip = card->private_data;
+ chip->card = card;
+
+#ifdef MSND_CLASSIC
+ switch (irq[idx]) {
+ case 5:
+ chip->irqid = HPIRQ_5; break;
+ case 7:
+ chip->irqid = HPIRQ_7; break;
+ case 9:
+ chip->irqid = HPIRQ_9; break;
+ case 10:
+ chip->irqid = HPIRQ_10; break;
+ case 11:
+ chip->irqid = HPIRQ_11; break;
+ case 12:
+ chip->irqid = HPIRQ_12; break;
+ }
+
+ switch (mem[idx]) {
+ case 0xb0000:
+ chip->memid = HPMEM_B000; break;
+ case 0xc8000:
+ chip->memid = HPMEM_C800; break;
+ case 0xd0000:
+ chip->memid = HPMEM_D000; break;
+ case 0xd8000:
+ chip->memid = HPMEM_D800; break;
+ case 0xe0000:
+ chip->memid = HPMEM_E000; break;
+ case 0xe8000:
+ chip->memid = HPMEM_E800; break;
+ }
+#else
+ printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n", cfg[idx]);
+
+ if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
+ printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n", cfg[idx]);
+ snd_card_free(card);
+ return -EIO;
+ }
+ if (reset[idx])
+ if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
+ err = -EIO;
+ goto cfg_error;
+ }
+
+ /* DSP */
+ err = snd_msnd_write_cfg_logical(cfg[idx], 0,
+ io[idx], 0,
+ irq[idx], mem[idx]);
+
+ if (err)
+ goto cfg_error;
+
+ /* The following are Pinnacle specific */
+
+ /* MPU */
+ if (mpu_io[idx] != SNDRV_AUTO_PORT
+ && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring MPU to I/O 0x%lx IRQ %d\n",
+ mpu_io[idx], mpu_irq[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 1,
+ mpu_io[idx], 0,
+ mpu_irq[idx], 0);
+
+ if (err)
+ goto cfg_error;
+ }
+
+ /* IDE */
+ if (ide_io0[idx] != SNDRV_AUTO_PORT
+ && ide_io1[idx] != SNDRV_AUTO_PORT
+ && ide_irq[idx] != SNDRV_AUTO_IRQ) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
+ ide_io0[idx], ide_io1[idx], ide_irq[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 2,
+ ide_io0[idx], ide_io1[idx],
+ ide_irq[idx], 0);
+
+ if (err)
+ goto cfg_error;
+ }
+
+ /* Joystick */
+ if (joystick_io[idx] != SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring joystick to I/O 0x%lx\n",
+ joystick_io[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 3,
+ joystick_io[idx], 0,
+ 0, 0);
+
+ if (err)
+ goto cfg_error;
+ }
+ release_region(cfg[idx], 2);
+
+#endif /* MSND_CLASSIC */
+
+ set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+ chip->type = msndClassic;
+#else
+ chip->type = msndPinnacle;
+#endif
+/* snd_msnd_playback.buffer_bytes_max = 3 * (
+ snd_msnd_playback.period_bytes_max =
+ snd_msnd_playback.period_bytes_min =
+ chip->play_period_bytes = play_period_bytes
+ );
+ printk(KERN_INFO LOGNAME ": play_period_bytes=0x%X\n", chip->play_period_bytes);
+*/
+ chip->io = io[idx];
+ chip->irq = irq[idx];
+ chip->base = mem[idx];
+
+ chip->calibrate_signal = calibrate_signal ? 1 : 0;
+ chip->recsrc = 0;
+ chip->dspq_data_buff = DSPQ_DATA_BUFF;
+ chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+ if (write_ndelay[idx])
+ clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+ if (digital[idx])
+ set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+ spin_lock_init(&chip->lock);
+ err = snd_msnd_probe(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ snd_card_free(card);
+ return err;
+ }
+
+ err = snd_msnd_attach(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ snd_card_free(card);
+ return err;
+ }
+ dev_set_drvdata(pdev, card);
+
+ return 0;
+
+#ifndef MSND_CLASSIC
+cfg_error:
+ release_region(cfg[idx], 2);
+ snd_card_free(card);
+ return err;
+#endif
+}
+
+static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
+{
+ snd_msnd_unload(dev_get_drvdata(pdev));
+ dev_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#define DEV_NAME "msnd-pinnacle"
+
+static struct isa_driver snd_msnd_driver = {
+ .match = snd_msnd_isa_match,
+ .probe = snd_msnd_isa_probe,
+ .remove = __devexit_p(snd_msnd_isa_remove),
+ /* FIXME: suspend, resume */
+ .driver = {
+ .name = DEV_NAME
+ },
+};
+
+#ifdef CONFIG_PNP
+static int __devinit snd_msnd_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+{
+ static int idx = 0;
+ struct pnp_dev *pnp_dev;
+ struct pnp_dev *mpu_dev;
+ struct snd_card *card;
+ struct snd_msnd *chip;
+ int ret;
+
+ for ( ; idx < SNDRV_CARDS; idx++) {
+ if (isapnp[idx])
+ break;
+ }
+ if (idx >= SNDRV_CARDS)
+ return -ENODEV;
+
+ /*
+ * Check that we still have room for another sound card ...
+ */
+ pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+ if (!pnp_dev)
+ return -ENODEV;
+
+ mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
+ if (!mpu_dev)
+ return -ENODEV;
+
+ if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
+ printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
+ return -EBUSY;
+ }
+
+ if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
+ printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Create a new ALSA sound card entry, in anticipation
+ * of detecting our hardware ...
+ */
+ card = snd_card_new(index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd));
+ if (!card)
+ return -ENOMEM;
+
+ chip = card->private_data;
+ chip->card = card;
+ snd_card_set_dev(card, &pcard->card->dev);
+
+ /*
+ * Read the correct parameters off the ISA PnP bus ...
+ */
+ io[idx] = pnp_port_start(pnp_dev, 0);
+ irq[idx] = pnp_irq(pnp_dev, 0);
+ mem[idx] = pnp_mem_start(pnp_dev, 0);
+ mpu_io[idx] = pnp_port_start(mpu_dev, 0);
+ mpu_irq[idx] = pnp_irq(mpu_dev, 0);
+
+ set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+ chip->type = msndClassic;
+#else
+ chip->type = msndPinnacle;
+#endif
+ chip->io = io[idx];
+ chip->irq = irq[idx];
+ chip->base = mem[idx];
+
+ chip->calibrate_signal = calibrate_signal ? 1 : 0;
+ chip->recsrc = 0;
+ chip->dspq_data_buff = DSPQ_DATA_BUFF;
+ chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+ if (write_ndelay[idx])
+ clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+ if (digital[idx])
+ set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+ spin_lock_init(&chip->lock);
+ ret = snd_msnd_probe(card);
+ if (ret < 0) {
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ goto _release_card;
+ }
+
+ ret = snd_msnd_attach(card);
+ if (ret < 0) {
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ goto _release_card;
+ }
+
+ pnp_set_card_drvdata(pcard, card);
+ ++idx;
+ return 0;
+
+_release_card:
+ snd_card_free(card);
+ return ret;
+}
+
+static void __devexit snd_msnd_pnp_remove(struct pnp_card_link *pcard)
+{
+ snd_msnd_unload(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+}
+
+static int isa_registered;
+static int pnp_registered;
+
+static struct pnp_card_device_id msnd_pnpids[] = {
+ /* Pinnacle PnP */
+ { .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
+ { .id = "" } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
+
+static struct pnp_card_driver msnd_pnpc_driver = {
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .name = "msnd_pinnacle",
+ .id_table = msnd_pnpids,
+ .probe = snd_msnd_pnp_detect,
+ .remove = __devexit_p(snd_msnd_pnp_remove),
+};
+#endif /* CONFIG_PNP */
+
+static int __init snd_msnd_init(void)
+{
+ int err;
+
+ err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
+
+ err = pnp_register_card_driver(&msnd_pnpc_driver);
+ if (!err)
+ pnp_registered = 1;
+
+ if (isa_registered)
+ err = 0;
+#endif
+ return err;
+}
+
+static void __exit snd_msnd_exit(void)
+{
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&msnd_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_msnd_driver);
+}
+
+module_init(snd_msnd_init);
+module_exit(snd_msnd_exit);
+
diff --git a/sound/isa/msnd/msnd_pinnacle.h b/sound/isa/msnd/msnd_pinnacle.h
new file mode 100644
index 0000000..b6c400e
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.h
@@ -0,0 +1,246 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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 __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO 0x08
+
+#define IREG_LOGDEVICE 0x07
+#define IREG_ACTIVATE 0x30
+#define LD_ACTIVATE 0x01
+#define LD_DISACTIVATE 0x00
+#define IREG_EECONTROL 0x3F
+#define IREG_MEMBASEHI 0x40
+#define IREG_MEMBASELO 0x41
+#define IREG_MEMCONTROL 0x42
+#define IREG_MEMRANGEHI 0x43
+#define IREG_MEMRANGELO 0x44
+#define MEMTYPE_8BIT 0x00
+#define MEMTYPE_16BIT 0x02
+#define MEMTYPE_RANGE 0x00
+#define MEMTYPE_HIADDR 0x01
+#define IREG_IO0_BASEHI 0x60
+#define IREG_IO0_BASELO 0x61
+#define IREG_IO1_BASEHI 0x62
+#define IREG_IO1_BASELO 0x63
+#define IREG_IRQ_NUMBER 0x70
+#define IREG_IRQ_TYPE 0x71
+#define IRQTYPE_HIGH 0x02
+#define IRQTYPE_LOW 0x00
+#define IRQTYPE_LEVEL 0x01
+#define IRQTYPE_EDGE 0x00
+
+#define HP_DSPR 0x04
+#define HP_BLKS 0x04
+
+#define HPDSPRESET_OFF 2
+#define HPDSPRESET_ON 0
+
+#define HPBLKSEL_0 2
+#define HPBLKSEL_1 3
+
+#define HIMT_DAT_OFF 0x03
+
+#define HIDSP_PLAY_UNDER 0x00
+#define HIDSP_INT_PLAY_UNDER 0x01
+#define HIDSP_SSI_TX_UNDER 0x02
+#define HIDSP_RECQ_OVERFLOW 0x08
+#define HIDSP_INT_RECORD_OVER 0x09
+#define HIDSP_SSI_RX_OVERFLOW 0x0a
+
+#define HIDSP_MIDI_IN_OVER 0x10
+
+#define HIDSP_MIDI_FRAME_ERR 0x11
+#define HIDSP_MIDI_PARITY_ERR 0x12
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define HIDSP_INPUT_CLIPPING 0x20
+#define HIDSP_MIX_CLIPPING 0x30
+#define HIDSP_DAT_IN_OFF 0x21
+
+#define HDEXAR_SET_ANA_IN 0
+#define HDEXAR_CLEAR_PEAKS 1
+#define HDEXAR_IN_SET_POTS 2
+#define HDEXAR_AUX_SET_POTS 3
+#define HDEXAR_CAL_A_TO_D 4
+#define HDEXAR_RD_EXT_DSP_BITS 5
+
+#define HDEXAR_SET_SYNTH_IN 4
+#define HDEXAR_READ_DAT_IN 5
+#define HDEXAR_MIC_SET_POTS 6
+#define HDEXAR_SET_DAT_IN 7
+
+#define HDEXAR_SET_SYNTH_48 8
+#define HDEXAR_SET_SYNTH_44 9
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x001E
+#define TIME_PRO_RESET 0x0032
+
+#define AGND 0x01
+#define SIGNAL 0x02
+
+#define EXT_DSP_BIT_DCAL 0x0001
+#define EXT_DSP_BIT_MIDI_CON 0x0002
+
+#define BUFFSIZE 0x8000
+#define HOSTQ_SIZE 0x40
+
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DAP_BUFF_SIZE 0x2400
+#define DAR_BUFF_SIZE 0x1000
+
+#define DAPQ_STRUCT_SIZE 0x10
+#define DARQ_STRUCT_SIZE 0x10
+#define DAPQ_BUFF_SIZE (3 * 0x10)
+#define DARQ_BUFF_SIZE (3 * 0x10)
+#define MODQ_BUFF_SIZE 0x400
+#define MIDQ_BUFF_SIZE 0x800
+#define DSPQ_BUFF_SIZE 0x5A0
+
+#define DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+#define DSPQ_DATA_BUFF 0x7860
+
+#define DAPQ_OFFSET SRAM_CNTL_START
+#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
+
+#define MOP_WAVEHDR 0
+#define MOP_EXTOUT 1
+#define MOP_HWINIT 0xfe
+#define MOP_NONE 0xff
+#define MOP_MAX 1
+
+#define MIP_EXTIN 0
+#define MIP_WAVEHDR 1
+#define MIP_HWINIT 0xfe
+#define MIP_MAX 1
+
+/* Pinnacle/Fiji SMA Common Data */
+#define SMA_wCurrPlayBytes 0x0000
+#define SMA_wCurrRecordBytes 0x0002
+#define SMA_wCurrPlayVolLeft 0x0004
+#define SMA_wCurrPlayVolRight 0x0006
+#define SMA_wCurrInVolLeft 0x0008
+#define SMA_wCurrInVolRight 0x000a
+#define SMA_wCurrMHdrVolLeft 0x000c
+#define SMA_wCurrMHdrVolRight 0x000e
+#define SMA_dwCurrPlayPitch 0x0010
+#define SMA_dwCurrPlayRate 0x0014
+#define SMA_wCurrMIDIIOPatch 0x0018
+#define SMA_wCurrPlayFormat 0x001a
+#define SMA_wCurrPlaySampleSize 0x001c
+#define SMA_wCurrPlayChannels 0x001e
+#define SMA_wCurrPlaySampleRate 0x0020
+#define SMA_wCurrRecordFormat 0x0022
+#define SMA_wCurrRecordSampleSize 0x0024
+#define SMA_wCurrRecordChannels 0x0026
+#define SMA_wCurrRecordSampleRate 0x0028
+#define SMA_wCurrDSPStatusFlags 0x002a
+#define SMA_wCurrHostStatusFlags 0x002c
+#define SMA_wCurrInputTagBits 0x002e
+#define SMA_wCurrLeftPeak 0x0030
+#define SMA_wCurrRightPeak 0x0032
+#define SMA_bMicPotPosLeft 0x0034
+#define SMA_bMicPotPosRight 0x0035
+#define SMA_bMicPotMaxLeft 0x0036
+#define SMA_bMicPotMaxRight 0x0037
+#define SMA_bInPotPosLeft 0x0038
+#define SMA_bInPotPosRight 0x0039
+#define SMA_bAuxPotPosLeft 0x003a
+#define SMA_bAuxPotPosRight 0x003b
+#define SMA_bInPotMaxLeft 0x003c
+#define SMA_bInPotMaxRight 0x003d
+#define SMA_bAuxPotMaxLeft 0x003e
+#define SMA_bAuxPotMaxRight 0x003f
+#define SMA_bInPotMaxMethod 0x0040
+#define SMA_bAuxPotMaxMethod 0x0041
+#define SMA_wCurrMastVolLeft 0x0042
+#define SMA_wCurrMastVolRight 0x0044
+#define SMA_wCalFreqAtoD 0x0046
+#define SMA_wCurrAuxVolLeft 0x0048
+#define SMA_wCurrAuxVolRight 0x004a
+#define SMA_wCurrPlay1VolLeft 0x004c
+#define SMA_wCurrPlay1VolRight 0x004e
+#define SMA_wCurrPlay2VolLeft 0x0050
+#define SMA_wCurrPlay2VolRight 0x0052
+#define SMA_wCurrPlay3VolLeft 0x0054
+#define SMA_wCurrPlay3VolRight 0x0056
+#define SMA_wCurrPlay4VolLeft 0x0058
+#define SMA_wCurrPlay4VolRight 0x005a
+#define SMA_wCurrPlay1PeakLeft 0x005c
+#define SMA_wCurrPlay1PeakRight 0x005e
+#define SMA_wCurrPlay2PeakLeft 0x0060
+#define SMA_wCurrPlay2PeakRight 0x0062
+#define SMA_wCurrPlay3PeakLeft 0x0064
+#define SMA_wCurrPlay3PeakRight 0x0066
+#define SMA_wCurrPlay4PeakLeft 0x0068
+#define SMA_wCurrPlay4PeakRight 0x006a
+#define SMA_wCurrPlayPeakLeft 0x006c
+#define SMA_wCurrPlayPeakRight 0x006e
+#define SMA_wCurrDATSR 0x0070
+#define SMA_wCurrDATRXCHNL 0x0072
+#define SMA_wCurrDATTXCHNL 0x0074
+#define SMA_wCurrDATRXRate 0x0076
+#define SMA_dwDSPPlayCount 0x0078
+#define SMA__size 0x007c
+
+#ifdef HAVE_DSPCODEH
+# include "pndsperm.c"
+# include "pndspini.c"
+# define PERMCODE pndsperm
+# define INITCODE pndspini
+# define PERMCODESIZE sizeof(pndsperm)
+# define INITCODESIZE sizeof(pndspini)
+#else
+# ifndef CONFIG_MSNDPIN_INIT_FILE
+# define CONFIG_MSNDPIN_INIT_FILE "turtlebeach/pndspini.bin"
+# endif
+# ifndef CONFIG_MSNDPIN_PERM_FILE
+# define CONFIG_MSNDPIN_PERM_FILE "turtlebeach/pndsperm.bin"
+# endif
+# define PERMCODEFILE CONFIG_MSNDPIN_PERM_FILE
+# define INITCODEFILE CONFIG_MSNDPIN_INIT_FILE
+# define PERMCODE dspini
+# define INITCODE permini
+# define PERMCODESIZE sizeof_dspini
+# define INITCODESIZE sizeof_permini
+#endif
+#define LONGNAME "MultiSound (Pinnacle/Fiji)"
+
+int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, register u8 cmd);
+
+
+#endif /* __MSND_PINNACLE_H */
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
new file mode 100644
index 0000000..de94e75
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -0,0 +1,343 @@
+/***************************************************************************
+ msnd_pinnacle_mixer.c - description
+ -------------------
+ begin : Fre Jun 7 2002
+ copyright : (C) 2002 by karsten wiese
+ email : annabellesgarden(a)yahoo.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. *
+ * *
+ ***************************************************************************/
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+
+#define MSND_MIXER_VOLUME 0
+#define MSND_MIXER_PCM 1
+#define MSND_MIXER_AUX 2 /* Input source 1 (aux1) */
+#define MSND_MIXER_IMIX 3 /* Recording monitor */
+#define MSND_MIXER_SYNTH 4
+#define MSND_MIXER_SPEAKER 5
+#define MSND_MIXER_LINE 6
+#define MSND_MIXER_MIC 7
+#define MSND_MIXER_RECLEV 11 /* Recording level */
+#define MSND_MIXER_IGAIN 12 /* Input gain */
+#define MSND_MIXER_OGAIN 13 /* Output gain */
+#define MSND_MIXER_DIGITAL 17 /* Digital (input) 1 */
+
+/* Device mask bits */
+
+#define MSND_MASK_VOLUME (1 << MSND_MIXER_VOLUME)
+#define MSND_MASK_SYNTH (1 << MSND_MIXER_SYNTH)
+#define MSND_MASK_PCM (1 << MSND_MIXER_PCM)
+#define MSND_MASK_SPEAKER (1 << MSND_MIXER_SPEAKER)
+#define MSND_MASK_LINE (1 << MSND_MIXER_LINE)
+#define MSND_MASK_MIC (1 << MSND_MIXER_MIC)
+#define MSND_MASK_IMIX (1 << MSND_MIXER_IMIX)
+#define MSND_MASK_RECLEV (1 << MSND_MIXER_RECLEV)
+#define MSND_MASK_IGAIN (1 << MSND_MIXER_IGAIN)
+#define MSND_MASK_OGAIN (1 << MSND_MIXER_OGAIN)
+#define MSND_MASK_AUX (1 << MSND_MIXER_AUX)
+#define MSND_MASK_DIGITAL (1 << MSND_MIXER_DIGITAL)
+
+
+
+
+
+static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[3] = {
+ "Analog", "SPDIF", "MASS"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item > 2)
+ uinfo->value.enumerated.item = 2;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.enumerated.item[0] = 0;
+
+/* if (msnd->recsrc & MSND_MASK_IMIX) { this is the default
+ ucontrol->value.enumerated.item[0] = 0;
+ }
+ else */if (msnd->recsrc & MSND_MASK_SYNTH) {
+ ucontrol->value.enumerated.item[0] = 2;
+ }
+ else if ((msnd->recsrc & MSND_MASK_DIGITAL) && test_bit(F_HAVEDIGITAL, &msnd->flags)) {
+ ucontrol->value.enumerated.item[0] = 1;
+ }
+
+ return 0;
+}
+
+
+static int snd_msndmix_set_mux(struct snd_msnd *msnd, int val)
+{
+ unsigned newrecsrc;
+ int change;
+ unsigned char msndbyte;
+
+ switch (val) {
+ case 0:
+ newrecsrc = MSND_MASK_IMIX;
+ msndbyte = HDEXAR_SET_ANA_IN;
+ break;
+ case 1:
+ newrecsrc = MSND_MASK_DIGITAL;
+ msndbyte = HDEXAR_SET_DAT_IN;
+ break;
+ case 2:
+ newrecsrc = MSND_MASK_SYNTH;
+ msndbyte = HDEXAR_SET_SYNTH_IN;
+ break;
+ default:
+ return -EINVAL;
+ }
+ change = newrecsrc != msnd->recsrc;
+ if (change) {
+ if (0 == snd_msnd_send_word(msnd, 0, 0, msndbyte))
+ if (0 == snd_msnd_send_dsp_cmd_chk(msnd, HDEX_AUX_REQ))
+ msnd->recsrc = newrecsrc;
+ }
+ return change;
+}
+
+
+static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
+}
+
+
+static int snd_msndmix_volume_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 = 100;
+ return 0;
+}
+
+static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = (msnd->left_levels[addr] * 100) / 0xFFFF;
+ ucontrol->value.integer.value[1] = (msnd->right_levels[addr] * 100) / 0xFFFF;
+ return 0;
+}
+
+
+#define update_volm(a,b) \
+ isa_writew((dev->left_levels[a] >> 1) * \
+ isa_readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##b##Left); \
+ isa_writew((dev->right_levels[a] >> 1) * \
+ isa_readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##b##Right);
+
+#define update_potm(d,s,ar) \
+ isa_writeb((dev->left_levels[d] >> 8) * \
+ isa_readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##s##Left); \
+ isa_writeb((dev->right_levels[d] >> 8) * \
+ isa_readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##s##Right); \
+ if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
+ snd_msnd_send_dsp_cmd_chk(dev, HDEX_AUX_REQ);
+
+#define update_pot(d,s,ar) \
+ isa_writeb(dev->left_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Left); \
+ isa_writeb(dev->right_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Right); \
+ if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
+ snd_msnd_send_dsp_cmd_chk(dev, HDEX_AUX_REQ);
+
+
+static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
+{
+ int bLeft, bRight;
+ int wLeft, wRight;
+ int updatemaster = 0;
+
+ //snd_printd("mixer_set(struct snd_msnd * %X, d=%i, left=%i, right=%i\n",
+ // (unsigned)dev, d, left, right);
+
+ if (d >= LEVEL_ENTRIES)
+ return -EINVAL;
+
+ bLeft = left * 0xff / 100;
+ wLeft = left * 0xffff / 100;
+
+ bRight = right * 0xff / 100;
+ wRight = right * 0xffff / 100;
+
+ dev->left_levels[d] = wLeft;
+ dev->right_levels[d] = wRight;
+
+ switch (d) {
+ /* master volume unscaled controls */
+ case MSND_MIXER_LINE: /* line pot control */
+ /* scaled by IMIX in digital mix */
+ isa_writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
+ isa_writeb(bRight, dev->SMA + SMA_bInPotPosRight);
+ if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+ snd_msnd_send_dsp_cmd_chk(dev, HDEX_AUX_REQ);
+ break;
+#ifndef MSND_CLASSIC
+ case MSND_MIXER_MIC: /* mic pot control */
+ /* scaled by IMIX in digital mix */
+ isa_writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
+ isa_writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
+ if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+ snd_msnd_send_dsp_cmd_chk(dev, HDEX_AUX_REQ);
+ break;
+#endif
+ case MSND_MIXER_VOLUME: /* master volume */
+ isa_writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
+ isa_writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
+ /* fall through */
+
+ case MSND_MIXER_AUX: /* aux pot control */
+ /* scaled by master volume */
+ /* fall through */
+
+ /* digital controls */
+ case MSND_MIXER_SYNTH: /* synth vol (dsp mix) */
+ case MSND_MIXER_PCM: /* pcm vol (dsp mix) */
+ case MSND_MIXER_IMIX: /* input monitor (dsp mix) */
+ /* scaled by master volume */
+ updatemaster = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (updatemaster) {
+ /* update master volume scaled controls */
+ update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+ update_volm(MSND_MIXER_IMIX, wCurrInVol);
+#ifndef MSND_CLASSIC
+ update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+#endif
+ update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ }
+
+ return 0;
+}
+
+
+static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ int change, addr = kcontrol->private_value;
+ int left, right;
+ // unsigned long flags;
+
+ left = ucontrol->value.integer.value[0] % 101;
+ right = ucontrol->value.integer.value[1] % 101;
+ // spin_lock_irqsave(&msnd->mixer_lock, flags);
+ change = msnd->left_levels[addr] != left
+ || msnd->right_levels[addr] != right;
+ snd_msndmix_set(msnd, addr, left, right);
+ // spin_unlock__irqrestore(&msnd->mixer_lock, flags);
+ return change;
+}
+
+
+#define DUMMY_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_msndmix_volume_info, \
+ .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
+ .private_value = addr }
+
+
+static struct snd_kcontrol_new snd_msnd_controls[] = {
+DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
+DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
+DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
+DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
+DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
+DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_msndmix_info_mux,
+ .get = snd_msndmix_get_mux,
+ .put = snd_msndmix_put_mux,
+}
+};
+
+
+
+int __devinit snd_msndmix_new(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ unsigned int idx;
+ int err;
+
+ if (snd_BUG_ON(!chip))
+ return -EINVAL;
+ // spin_lock_init(&chip->mixer_lock);
+ strcpy(card->mixername, "MSND Pinnacle Mixer");
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+ err = snd_ctl_add(card, snd_ctl_new1(snd_msnd_controls + idx, chip));
+ if (err < 0)
+ return err;
+
+#ifndef MSND_CLASSIC
+ // snd_msndmix_force_recsrc(chip, 0);
+#endif
+
+ return 0;
+}
+
+
+
+void snd_msndmix_setup(struct snd_msnd *dev)
+{
+ update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
+ update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+ update_volm(MSND_MIXER_IMIX, wCurrInVol);
+#ifndef MSND_CLASSIC
+ update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
+ update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+#endif
+
+}
+
+
+unsigned long snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
+{
+// snd_msndmix_set(dev, MSND_MIXER_VOLUME, 100, 100);
+// snd_msndmix_set(dev, MSND_MIXER_LINE, 70, 70);
+// snd_msndmix_set(dev, MSND_MIXER_IMIX, 100, 100);
+ dev->recsrc = -1;
+ return snd_msndmix_set_mux(dev, recsrc);
+}
+
+
----------------------------------------------------------------------
Szukasz mieszkania, domu, dzialki?
Sprawdz >>> http://link.interia.pl/f1f96
2
4
the old Indigo DJ driver worked after a few tweaks...
tested w/ jack, cmus, mplayer
mapping/virtual-outs seem good..
this is a diff on alsa-kernel.git. copied the old firmware and amazed it works, although something seems wonky with the samplerate registers. going to email echo about an updated firmware .. no noise bursts or ear destruction tho!
3
4