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
January 2009
- 109 participants
- 237 discussions
[PATCH] Print device number which did not support low speed audio streaming
by Andreas Bergmeier 24 Jan '09
by Andreas Bergmeier 24 Jan '09
24 Jan '09
Signed-off-by: Andreas Bergmeier <lcid-fire(a)gmx.net>
---
sound/usb/usbaudio.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 8b8eb9e..2cfb8a3 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2929,7 +2929,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
continue;
}
if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
- snd_printk(KERN_ERR "low speed audio streaming not supported\n");
+ snd_printk(KERN_ERR "%d: low speed audio streaming not supported\n", dev->devnum);
continue;
}
if (! parse_audio_endpoints(chip, j)) {
--
1.5.6.3
--------------050806070602090407040706
Content-Type: text/x-patch;
name="0001-Replaced-return-NULL-lines-by-break-in-snd_usb_fin.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename*0="0001-Replaced-return-NULL-lines-by-break-in-snd_usb_fin.patc";
filename*1="h"
1
0
[PATCH] Replaced 'return NULL' lines by break in snd_usb_find_desc so there is only one default error.
by Andreas Bergmeier 24 Jan '09
by Andreas Bergmeier 24 Jan '09
24 Jan '09
Signed-off-by: Andreas Bergmeier <lcid-fire(a)gmx.net>
---
sound/usb/usbaudio.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index d35b51c..8b8eb9e 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2054,10 +2054,10 @@ void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype)
end = p + desclen;
for (; p < end;) {
if (p[0] < 2)
- return NULL;
+ break;
next = p + p[0];
if (next > end)
- return NULL;
+ break;
if (p[1] == dtype && (!after || (void *)p > after)) {
return p;
}
--
1.5.6.3
--------------050806070602090407040706--
1
0
[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] [PATCH v2 2.6.30] ASoC: improve I2C initialization code in CS4270 driver
by Timur Tabi 23 Jan '09
by Timur Tabi 23 Jan '09
23 Jan '09
Further improvements in the I2C initialization sequence of the CS4270 driver.
All ASoC initialization is now done in the I2C probe function.
Signed-off-by: Timur Tabi <timur(a)freescale.com>
---
sound/soc/codecs/cs4270.c | 252 ++++++++++++++++++++-------------------------
1 files changed, 113 insertions(+), 139 deletions(-)
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 2e4ce04..71986e1 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -29,12 +29,6 @@
#include <sound/initval.h>
#include <linux/i2c.h>
-/* Private data for the CS4270 */
-struct cs4270_private {
- unsigned int mclk; /* Input frequency of the MCLK pin */
- unsigned int mode; /* The mode (I2S or left-justified) */
-};
-
/*
* The codec isn't really big-endian or little-endian, since the I2S
* interface requires data to be sent serially with the MSbit first.
@@ -107,6 +101,14 @@ struct cs4270_private {
#define CS4270_MUTE_DAC_A 0x01
#define CS4270_MUTE_DAC_B 0x02
+/* Private data for the CS4270 */
+struct cs4270_private {
+ struct snd_soc_codec codec;
+ u8 reg_cache[CS4270_NUMREGS];
+ unsigned int mclk; /* Input frequency of the MCLK pin */
+ unsigned int mode; /* The mode (I2S or left-justified) */
+};
+
/*
* Clock Ratio Selection for Master Mode with I2C enabled
*
@@ -502,6 +504,31 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
*/
static struct snd_soc_device *cs4270_socdev;
+struct snd_soc_dai cs4270_dai = {
+ .name = "cs4270",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = 0,
+ .formats = CS4270_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = 0,
+ .formats = CS4270_FORMATS,
+ },
+ .ops = {
+ .hw_params = cs4270_hw_params,
+ .set_sysclk = cs4270_set_dai_sysclk,
+ .set_fmt = cs4270_set_dai_fmt,
+ .digital_mute = cs4270_mute,
+ },
+};
+EXPORT_SYMBOL_GPL(cs4270_dai);
+
/*
* Initialize the I2C interface of the CS4270
*
@@ -515,47 +542,52 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = cs4270_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec;
+ struct cs4270_private *cs4270;
int i;
int ret = 0;
- /* Probing all possible addresses has one drawback: if there are
- multiple CS4270s on the bus, then you cannot specify which
- socdev is matched with which CS4270. For now, we just reject
- this I2C device if the socdev already has one attached. */
- if (codec->control_data)
- return -ENODEV;
-
- /* Note: codec_dai->codec is NULL here */
-
- codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL);
- if (!codec->reg_cache) {
- printk(KERN_ERR "cs4270: could not allocate register cache\n");
- ret = -ENOMEM;
- goto error;
- }
-
/* Verify that we have a CS4270 */
ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to read I2C\n");
- goto error;
+ return ret;
}
/* The top four bits of the chip ID should be 1100. */
if ((ret & 0xF0) != 0xC0) {
- /* The device at this address is not a CS4270 codec */
- ret = -ENODEV;
- goto error;
+ printk(KERN_ERR "cs4270: device at addr %X is not a CS4270\n",
+ i2c_client->addr);
+ return -ENODEV;
}
printk(KERN_INFO "cs4270: found device at I2C address %X\n",
i2c_client->addr);
printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);
+ /* Allocate enough space for the snd_soc_codec structure
+ and our private data together. */
+ cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+ if (!cs4270) {
+ printk(KERN_ERR "cs4270: Could not allocate codec structure\n");
+ return -ENOMEM;
+ }
+ codec = &cs4270->codec;
+ socdev->codec = codec;
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "CS4270";
+ codec->owner = THIS_MODULE;
+ codec->dai = &cs4270_dai;
+ codec->num_dai = 1;
+ codec->private_data = cs4270;
codec->control_data = i2c_client;
codec->read = cs4270_read_reg_cache;
codec->write = cs4270_i2c_write;
+ codec->reg_cache = cs4270->reg_cache;
codec->reg_cache_size = CS4270_NUMREGS;
/* The I2C interface is set up, so pre-fill our register cache */
@@ -563,35 +595,72 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
ret = cs4270_fill_cache(codec);
if (ret < 0) {
printk(KERN_ERR "cs4270: failed to fill register cache\n");
- goto error;
+ goto error_free_codec;
+ }
+
+ /* Register PCMs */
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "cs4270: failed to create PCMs\n");
+ goto error_free_codec;
}
/* Add the non-DAPM controls */
for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {
- struct snd_kcontrol *kctrl =
- snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
+ struct snd_kcontrol *kctrl;
+
+ kctrl = snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
+ if (!kctrl) {
+ printk(KERN_ERR "cs4270: error creating control '%s'\n",
+ cs4270_snd_controls[i].name);
+ ret = -ENOMEM;
+ goto error_free_pcms;
+ }
ret = snd_ctl_add(codec->card, kctrl);
- if (ret < 0)
- goto error;
+ if (ret < 0) {
+ printk(KERN_ERR "cs4270: error adding control '%s'\n",
+ cs4270_snd_controls[i].name);
+ goto error_free_pcms;
+ }
}
- i2c_set_clientdata(i2c_client, codec);
+ /* Initialize the SOC device */
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "cs4270: failed to register card\n");
+ goto error_free_pcms;;
+ }
+
+ i2c_set_clientdata(i2c_client, socdev);
return 0;
-error:
- codec->control_data = NULL;
+error_free_pcms:
+ snd_soc_free_pcms(socdev);
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
- codec->reg_cache_size = 0;
+error_free_codec:
+ kfree(cs4270);
return ret;
}
-static const struct i2c_device_id cs4270_id[] = {
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct snd_soc_device *socdev = i2c_get_clientdata(i2c_client);
+ struct snd_soc_codec *codec = socdev->codec;
+ struct cs4270_private *cs4270 = codec->private_data;
+
+ snd_soc_free_pcms(socdev);
+ kfree(cs4270);
+
+ return 0;
+}
+
+static struct i2c_device_id cs4270_id[] = {
{"cs4270", 0},
{}
};
@@ -604,27 +673,9 @@ static struct i2c_driver cs4270_i2c_driver = {
},
.id_table = cs4270_id,
.probe = cs4270_i2c_probe,
+ .remove = cs4270_i2c_remove,
};
-struct snd_soc_dai cs4270_dai = {
- .name = "CS4270",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = 0,
- .formats = CS4270_FORMATS,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = 0,
- .formats = CS4270_FORMATS,
- },
-};
-EXPORT_SYMBOL_GPL(cs4270_dai);
-
/*
* ASoC probe function
*
@@ -633,94 +684,15 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
*/
static int cs4270_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- printk(KERN_INFO "CS4270 ALSA SoC Codec\n");
-
- /* Allocate enough space for the snd_soc_codec structure
- and our private data together. */
- codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) +
- sizeof(struct cs4270_private), GFP_KERNEL);
- if (!codec) {
- printk(KERN_ERR "cs4270: Could not allocate codec structure\n");
- return -ENOMEM;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "CS4270";
- codec->owner = THIS_MODULE;
- codec->dai = &cs4270_dai;
- codec->num_dai = 1;
- codec->private_data = (void *) codec +
- ALIGN(sizeof(struct snd_soc_codec), 4);
-
- socdev->codec = codec;
-
- /* Register PCMs */
-
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to create PCMs\n");
- goto error_free_codec;
- }
-
- cs4270_socdev = socdev;
-
- ret = i2c_add_driver(&cs4270_i2c_driver);
- if (ret) {
- printk(KERN_ERR "cs4270: failed to attach driver");
- goto error_free_pcms;
- }
-
- /* Did we find a CS4270 on the I2C bus? */
- if (!codec->control_data) {
- printk(KERN_ERR "cs4270: failed to attach driver");
- goto error_del_driver;
- }
+ cs4270_socdev = platform_get_drvdata(pdev);;
- /* Initialize codec ops */
- cs4270_dai.ops.hw_params = cs4270_hw_params;
- cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
- cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
- cs4270_dai.ops.digital_mute = cs4270_mute;
-
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to register card\n");
- goto error_del_driver;
- }
-
- return 0;
-
-error_del_driver:
- i2c_del_driver(&cs4270_i2c_driver);
-
-error_free_pcms:
- snd_soc_free_pcms(socdev);
-
-error_free_codec:
- kfree(socdev->codec);
- socdev->codec = NULL;
-
- return ret;
+ return i2c_add_driver(&cs4270_i2c_driver);
}
static int cs4270_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
i2c_del_driver(&cs4270_i2c_driver);
- kfree(socdev->codec);
- socdev->codec = NULL;
-
return 0;
}
@@ -738,6 +710,8 @@ EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
static int __init cs4270_init(void)
{
+ printk(KERN_INFO "Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
+
return snd_soc_register_dai(&cs4270_dai);
}
module_init(cs4270_init);
--
1.5.5
2
1
The following changes since commit 56692396447ca3fee061c26f22590a1046fd2d6b:
Mark Brown (1):
Merge branch 'for-2.6.29' into for-2.6.30
are available in the git repository at:
ssh://master.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.30
(the usual git URI should work eventually as well but the mirroring
appears to be stuck right now and it's past 5pm on a Friday.)
Mark Brown (7):
ASoC: Fix merge with PXA tree
ASoC: Remove unneeded e7x0 inclusion of pxa-regs.h and hardware.h
ASoC: Configure SSP port PLL for Zylonite
ASoC: Fix spurious codec driver dependencies
Merge branch 'for-2.6.29' into for-2.6.30
ASoC: Include header file in cs4270 and wm9705
ASoC: Fix L3 bus handling in Kconfig
Peter Ujfalusi (1):
ASoC: Add missing comma to SND_SOC_DAPM_SWITCH_E in soc-dapm.h
Steve Sakoman (1):
ASoC: Complete Beagleboard support
Timur Tabi (1):
ASoC: remove stand-alone mode support from CS4270 codec driver
include/sound/soc-dapm.h | 2 +-
sound/soc/codecs/Kconfig | 5 +--
sound/soc/codecs/cs4270.c | 90 +++++++++++++------------------------------
sound/soc/codecs/wm9705.c | 2 +
sound/soc/fsl/Kconfig | 3 +-
sound/soc/omap/Kconfig | 14 ++++++-
sound/soc/omap/Makefile | 2 +
sound/soc/pxa/e740_wm9705.c | 2 -
sound/soc/pxa/e750_wm9705.c | 2 -
sound/soc/pxa/e800_wm9712.c | 5 +--
sound/soc/pxa/zylonite.c | 8 ++++
sound/soc/s3c24xx/Kconfig | 1 +
12 files changed, 57 insertions(+), 79 deletions(-)
2
10
The following changes since commit 8a9dee59a345f96757dd45699de1c4182d8bf9a9:
Timur Tabi (1):
ASoC: fix registration of the SoC card in the Freescale MPC8610 drivers
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.29
Peter Ujfalusi (1):
ASoC: Add missing comma to SND_SOC_DAPM_SWITCH_E in soc-dapm.h
include/sound/soc-dapm.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
2
1
[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
[alsa-devel] [PATCH] Turtle Beach Multisound Classic/Pinnacle driver (3rd rev)
by Krzysztof Helt 23 Jan '09
by Krzysztof Helt 23 Jan '09
23 Jan '09
From: Krzysztof Helt <krzysztof.h1(a)wp.pl>
This is driver for Turtle Beach Multisound cards:
Classic, Fiji and Pinnacle.
Tested pcm playback and recording and MIDI playback
on Multisound Pinnacle.
Signed-off-by: Krzysztof Helt <krzysztof.h1(a)wp.pl>
---
All issues pointed by Takashi are resolved. I moved
more code to the common part and made a common
library.
diff -urpN linux-rc5/sound/isa/msnd/Makefile linux-git/sound/isa/msnd/Makefile
--- linux-rc5/sound/isa/msnd/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/Makefile 2009-01-22 20:09:26.126460759 +0100
@@ -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 -urpN linux-rc5/sound/isa/msnd/msnd.c linux-git/sound/isa/msnd/msnd.c
--- linux-rc5/sound/isa/msnd/msnd.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd.c 2009-01-22 21:19:43.283202276 +0100
@@ -0,0 +1,699 @@
+/*********************************************************************
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "msnd.h"
+
+#define LOGNAME "msnd"
+
+
+void snd_msnd_init_queue(void *base, int start, int size)
+{
+ writew(PCTODSP_BASED(start), base + JQS_wStart);
+ writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ writew(0, base + JQS_wHead);
+ writew(0, base + JQS_wTail);
+}
+EXPORT_SYMBOL(snd_msnd_init_queue);
+
+static 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;
+}
+
+static 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;
+}
+
+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);
+
+ snd_printd(KERN_ERR 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;
+ }
+
+ snd_printd(KERN_ERR 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) {
+ snd_printk(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]))
+ 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;
+
+ snd_printdd(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);
+
+ snd_printd(KERN_ERR 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)
+ snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
+ dev->irq_ref);
+
+ snd_printdd(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);
+
+ snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_disable_irq);
+
+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 void snd_msnd_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);
+}
+
+void snd_msnd_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(chip, HDEX_RECORD_STOP);
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ snd_printd(KERN_INFO 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)) {
+ snd_msnd_dsp_write_flush(chip);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ }
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ snd_printd(KERN_INFO
+ LOGNAME ": Stopping write for %p\n", file);
+ chip->mode &= ~FMODE_WRITE;
+ }
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ }
+}
+EXPORT_SYMBOL(snd_msnd_dsp_halt);
+
+
+int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
+{
+ int /*size, n,*/ timeout = 3;
+ u16 wTmp;
+ /* void *DAQD; */
+
+ /* Increment the tail and check for queue wrap */
+ wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+ if (wTmp > readw(chip->DARQ + JQS_wSize))
+ wTmp = 0;
+ while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
+ udelay(1);
+
+ if (chip->capturePeriods == 2) {
+ void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
+ bank * DAQDS__size + DAQDS_wStart;
+ unsigned short offset = 0x3000 + chip->capturePeriodBytes;
+
+ if (readw(pDAQ) != PCTODSP_BASED(0x3000))
+ offset = 0x3000;
+ writew(PCTODSP_BASED(offset), pDAQ);
+ }
+
+ writew(wTmp, chip->DARQ + JQS_wTail);
+
+#if 0
+ /* Get our digital audio queue struct */
+ DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
+
+ /* Get length of data */
+ size = 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);
+#endif
+
+ return 1;
+}
+EXPORT_SYMBOL(snd_msnd_DARQ);
+
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
+{
+ u16 DAPQ_tail;
+ int protect = start, nbanks = 0;
+ void *DAQD;
+ static int play_banks_submitted;
+ /* unsigned long flags;
+ spin_lock_irqsave(&chip->lock, flags); not necessary */
+
+ DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
+ while (DAPQ_tail != 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->mappedbase +
+ DAPQ_DATA_BUFF;
+
+ /* Write size of this bank */
+ writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
+ if (play_banks_submitted < 3)
+ ++play_banks_submitted;
+ else if (chip->playPeriods == 2) {
+ unsigned short offset = chip->play_period_bytes;
+
+ if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
+ offset = 0;
+
+ writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
+ }
+ ++nbanks;
+
+ /* Then advance the tail */
+ /*
+ if (protect)
+ snd_printd(KERN_INFO "B %X %lX\n",
+ bank_num, xtime.tv_usec);
+ */
+
+ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+ 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(KERN_INFO "%lX\n", xtime.tv_usec);
+ */
+ /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
+ return nbanks;
+}
+EXPORT_SYMBOL(snd_msnd_DAPQ);
+
+static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+ chip->last_playbank = -1;
+ chip->playLimit = pcm_count * (pcm_periods - 1);
+ chip->playPeriods = pcm_periods;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
+
+ chip->play_period_bytes = pcm_count;
+
+ for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+ writew(PCTODSP_BASED((u32)(pcm_count * (n % pcm_periods))),
+ pDAQ + DAQDS_wStart);
+ writew(0, pDAQ + DAQDS_wSize);
+ writew(1, pDAQ + DAQDS_wFormat);
+ writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+ writew(n, pDAQ + DAQDS_wFlags);
+ }
+}
+
+static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ void *pDAQ;
+ /* 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;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
+ 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);
+ memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);*/
+
+ chip->capturePeriodBytes = pcm_count;
+ snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
+
+ pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+ for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+ u32 tmp = pcm_count * (n % pcm_periods);
+
+ writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
+ writew(pcm_count, pDAQ + DAQDS_wSize);
+ writew(1, pDAQ + DAQDS_wFormat);
+ writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+ writew(n, pDAQ + DAQDS_wFlags);
+ }
+}
+
+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 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);
+
+ set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_enable_irq(chip);
+
+ runtime->dma_area = chip->mappedbase;
+ runtime->dma_bytes = 0x3000;
+
+ chip->playback_substream = substream;
+ runtime->hw = snd_msnd_playback;
+ return 0;
+}
+
+static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ 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);
+ void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+ chip->play_sample_size = snd_pcm_format_width(params_format(params));
+ chip->play_channels = params_channels(params);
+ chip->play_sample_rate = params_rate(params);
+
+ for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+ writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+ }
+ /* dont do this here:
+ * snd_msnd_calibrate_adc(chip->play_sample_rate);
+ */
+
+ 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_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
+ chip->playDMAPos = 0;
+ return 0;
+}
+
+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;
+
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ snd_printdd("snd_msnd_playback_trigger(START)\n");
+ chip->banksPlayed = 0;
+ set_bit(F_WRITING, &chip->flags);
+ snd_msnd_DAPQ(chip, 1);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ snd_printdd("snd_msnd_playback_trigger(STop)\n");
+ /* interrupt diagnostic, comment this out later */
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ } else {
+ snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
+ result = -EINVAL;
+ }
+
+ snd_printdd("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);
+
+ 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;
+ 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(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);
+ void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+ chip->capture_sample_size = snd_pcm_format_width(params_format(params));
+ chip->capture_channels = params_channels(params);
+ chip->capture_sample_rate = params_rate(params);
+
+ for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+ writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->capture_sample_rate, pDAQ + 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_data = chip;
+ strcpy(pcm->name, "Hurricane");
+
+
+ if (rpcm)
+ *rpcm = pcm;
+ return 0;
+}
+EXPORT_SYMBOL(snd_msnd_pcm);
diff -urpN linux-rc5/sound/isa/msnd/msnd.h linux-git/sound/isa/msnd/msnd.h
--- linux-rc5/sound/isa/msnd/msnd.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd.h 2009-01-22 21:17:09.125632934 +0100
@@ -0,0 +1,287 @@
+/*********************************************************************
+ *
+ * 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 DEFSAMPLERATE 44100
+#define DEFSAMPLESIZE SNDRV_PCM_FORMAT_S16
+#define DEFCHANNELS 1
+
+#define SRAM_BANK_SIZE 0x8000
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DSP_BASE_ADDR 0x4000
+#define DSP_BANK_BASE 0x4000
+
+#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 DAP_BUFF_SIZE 0x2400
+
+#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 DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+
+#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 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
+
+struct snd_msnd {
+ void __iomem *mappedbase;
+ int play_period_bytes;
+ int playLimit;
+ int playPeriods;
+ int playDMAPos;
+ int banksPlayed;
+ 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 */
+ void __iomem *SMA;
+ void __iomem *DAPQ;
+ void __iomem *DARQ;
+ void __iomem *MODQ;
+ void __iomem *MIDQ;
+ void __iomem *DSPQ;
+ 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;
+ spinlock_t mixer_lock;
+ int nresets;
+ unsigned recsrc;
+#define LEVEL_ENTRIES 32
+ int left_levels[LEVEL_ENTRIES];
+ int right_levels[LEVEL_ENTRIES];
+ 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(void *base, int start, int size);
+
+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);
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
+int snd_msnd_DARQ(struct snd_msnd *chip, int start);
+int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+
+int snd_msndmidi_new(struct snd_card *card, int device);
+void snd_msndmidi_input_read(void *mpu);
+
+#endif /* __MSND_H */
diff -urpN linux-rc5/sound/isa/msnd/msnd_classic.c linux-git/sound/isa/msnd/msnd_classic.c
--- linux-rc5/sound/isa/msnd/msnd_classic.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd_classic.c 2009-01-16 22:00:53.058024371 +0100
@@ -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 -urpN linux-rc5/sound/isa/msnd/msnd_classic.h linux-git/sound/isa/msnd/msnd_classic.h
--- linux-rc5/sound/isa/msnd/msnd_classic.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd_classic.h 2009-01-22 21:03:28.055334713 +0100
@@ -0,0 +1,140 @@
+/*********************************************************************
+ *
+ * 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 DAR_BUFF_SIZE 0x2000
+
+#define MIDQ_BUFF_SIZE 0x200
+#define DSPQ_BUFF_SIZE 0x40
+
+#define DSPQ_DATA_BUFF 0x7260
+
+#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
+
+#define INITCODEFILE "turtlebeach/msndinit.bin"
+#define PERMCODEFILE "turtlebeach/msndperm.bin"
+#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)"
+
+/* 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);
+
+#endif /* __MSND_CLASSIC_H */
diff -urpN linux-rc5/sound/isa/msnd/msnd_midi.c linux-git/sound/isa/msnd/msnd_midi.c
--- linux-rc5/sound/isa/msnd/msnd_midi.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd_midi.c 2009-01-22 18:35:00.942072608 +0100
@@ -0,0 +1,179 @@
+/*
+ * 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/ioport.h>
+#include <linux/errno.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "msnd.h"
+
+#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
+
+struct snd_msndmidi {
+ struct snd_msnd *dev;
+
+ unsigned long mode; /* MSNDMIDI_MODE_XXXX */
+
+ struct snd_rawmidi_substream *substream_input;
+
+ spinlock_t input_lock;
+};
+
+/*
+ * 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;
+
+ snd_printdd("snd_msndmidi_input_open()\n");
+
+ mpu = substream->rmidi->private_data;
+
+ mpu->substream_input = substream;
+
+ 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;
+
+ 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);
+ return 0;
+}
+
+static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
+{
+ u16 tail;
+
+ tail = readw(mpu->dev->MIDQ + JQS_wTail);
+ 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;
+
+ snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
+
+ 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;
+ void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ while (readw(mpu->dev->MIDQ + JQS_wTail) !=
+ readw(mpu->dev->MIDQ + JQS_wHead)) {
+ u16 wTmp, val;
+ val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
+
+ if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+ &mpu->mode))
+ snd_rawmidi_receive(mpu->substream_input,
+ (unsigned char *)&val, 1);
+
+ wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
+ if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
+ writew(0, mpu->dev->MIDQ + JQS_wHead);
+ else
+ 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;
+ 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);
+ strcpy(rmidi->name, "MSND MIDI");
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_msndmidi_input);
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ return 0;
+}
diff -urpN linux-rc5/sound/isa/msnd/msnd_pinnacle.c linux-git/sound/isa/msnd/msnd_pinnacle.c
--- linux-rc5/sound/isa/msnd/msnd_pinnacle.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd_pinnacle.c 2009-01-22 21:19:31.452624274 +0100
@@ -0,0 +1,1244 @@
+/*********************************************************************
+ *
+ * Linux multisound pinnacle/fiji driver for ALSA.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/isa.h>
+#include <linux/isapnp.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+#include <sound/mpu401.h>
+
+#ifdef MSND_CLASSIC
+# ifndef __alpha__
+# define SLOWIO
+# endif
+#endif
+#include "msnd.h"
+#ifdef MSND_CLASSIC
+# include "msnd_classic.h"
+# define LOGNAME "msnd_classic"
+#else
+# include "msnd_pinnacle.h"
+# define LOGNAME "snd_msnd_pinnacle"
+#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 void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
+{
+ switch (HIBYTE(wMessage)) {
+ case HIMT_PLAY_DONE: {
+ #ifdef CONFIG_SND_DEBUG0
+ if (chip->banksPlayed < 3)
+ snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
+ (unsigned)jiffies, LOBYTE(wMessage));
+ #endif
+
+ if (chip->last_playbank == LOBYTE(wMessage)) {
+ snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
+ break;
+ }
+ chip->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;
+ snd_pcm_period_elapsed(chip->playback_substream);
+
+ 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:
+ snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
+ chip->banksPlayed);
+ if (chip->banksPlayed > 2)
+ clear_bit(F_WRITING, &chip->flags);
+ break;
+
+ case HIDSP_INT_RECORD_OVER:
+ snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
+ clear_bit(F_READING, &chip->flags);
+ break;
+
+ default:
+ snd_printd(KERN_WARNING LOGNAME
+ ": DSP message %d 0x%02x\n",
+ LOBYTE(wMessage), LOBYTE(wMessage));
+ break;
+ }
+ break;
+
+ case HIMT_MIDI_IN_UCHAR:
+ if (chip->msndmidi_mpu)
+ snd_msndmidi_input_read(chip->msndmidi_mpu);
+ break;
+
+ default:
+ snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
+ HIBYTE(wMessage), HIBYTE(wMessage));
+ break;
+ }
+}
+
+static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
+{
+ struct snd_msnd *chip = dev_id;
+ void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+
+ /* Send ack to DSP */
+ /* inb(chip->io + HP_RXL); */
+
+ /* Evaluate queued DSP messages */
+ while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
+ u16 wTmp;
+
+ snd_msnd_eval_dsp_msg(chip,
+ readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
+
+ wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
+ if (wTmp > readw(chip->DSPQ + JQS_wSize))
+ writew(0, chip->DSPQ + JQS_wHead);
+ else
+ writew(wTmp, chip->DSPQ + JQS_wHead);
+ }
+ /* Send ack to DSP */
+ inb(chip->io + HP_RXL);
+ 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);
+ }
+ snd_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")) {
+ snd_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);
+ /* Motorola 56k shared memory base */
+ chip->SMA = chip->mappedbase + SMA_STRUCT_START;
+
+ if (initted) {
+ mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
+ mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
+ } else
+ mastVolLeft = mastVolRight = 0;
+ memset_io(chip->mappedbase, 0, 0x8000);
+
+ /* Critical section: bank 1 access */
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, 0x8000);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /* Digital audio play queue */
+ chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
+ snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
+
+ /* Digital audio record queue */
+ chip->DARQ = chip->mappedbase + DARQ_OFFSET;
+ snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
+
+ /* MIDI out queue */
+ chip->MODQ = chip->mappedbase + MODQ_OFFSET;
+ snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
+
+ /* MIDI in queue */
+ chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
+ snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
+
+ /* DSP -> host message queue */
+ chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
+ snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
+
+ /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+ writew(1, chip->SMA + SMA_wCurrPlayFormat);
+ writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
+ writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
+ writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
+#endif
+ writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
+ writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
+ writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
+#ifndef MSND_CLASSIC
+ writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
+ writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
+#endif
+ writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
+
+ initted = 1;
+
+ return 0;
+}
+
+
+static int upload_dsp_code(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ const struct firmware *init_fw = NULL, *perm_fw = NULL;
+ int err;
+
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+
+ 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;
+ }
+
+ memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
+ if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
+ printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ err = -ENODEV;
+ goto cleanup;
+ }
+ printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
+ err = 0;
+
+cleanup:
+ release_firmware(perm_fw);
+cleanup1:
+ release_firmware(init_fw);
+ 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;
+
+#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;
+
+ while (readw(chip->mappedbase)) {
+ msleep(1);
+ if (!timeout--) {
+ snd_printd(KERN_ERR 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);
+ snd_msnd_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_printdd("snd_msnd_chip_free()\n");
+ return 0;
+}
+
+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 int __devinit snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
+{
+ snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
+ writew(srate, chip->SMA + SMA_wCalFreqAtoD);
+ if (chip->calibrate_signal == 0)
+ writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ else
+ writew(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;
+}
+
+/*
+ * ALSA callback function, called when attempting to open the MIDI device.
+ */
+static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
+{
+ snd_msnd_enable_irq(mpu->private_data);
+ 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);
+ snd_msnd_disable_irq(mpu->private_data);
+}
+
+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(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 = ioremap(chip->base, 0x8000);
+ if (!chip->mappedbase) {
+ printk(KERN_ERR LOGNAME
+ ": unable to map memory region 0x%lx-0x%lx\n",
+ chip->base, chip->base + BUFFSIZE - 1);
+ err = -EIO;
+ goto err_release_region;
+ }
+ chip->mappedbase = ioremap(chip->base, 0x8000);
+
+ 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:
+ if (chip->mappedbase)
+ iounmap(chip->mappedbase);
+ release_mem_region(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;
+
+ iounmap(chip->mappedbase);
+ release_mem_region(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");
+MODULE_FIRMWARE(INITCODEFILE);
+MODULE_FIRMWARE(PERMCODEFILE);
+
+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 */
+
+static int
+calibrate_signal __devinitdata;
+#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;
+
+ 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
+ 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;
+ 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 -urpN linux-rc5/sound/isa/msnd/msnd_pinnacle.h linux-git/sound/isa/msnd/msnd_pinnacle.h
--- linux-rc5/sound/isa/msnd/msnd_pinnacle.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd_pinnacle.h 2009-01-22 21:03:22.885084729 +0100
@@ -0,0 +1,203 @@
+/*********************************************************************
+ *
+ * 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 DAR_BUFF_SIZE 0x1000
+
+#define MIDQ_BUFF_SIZE 0x800
+#define DSPQ_BUFF_SIZE 0x5A0
+
+#define DSPQ_DATA_BUFF 0x7860
+
+#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
+
+#define INITCODEFILE "turtlebeach/pndspini.bin"
+#define PERMCODEFILE "turtlebeach/pndsperm.bin"
+#define LONGNAME "MultiSound (Pinnacle/Fiji)"
+
+int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, register u8 cmd);
+
+/* 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);
+
+#endif /* __MSND_PINNACLE_H */
diff -urpN linux-rc5/sound/isa/msnd/msnd_pinnacle_mixer.c linux-git/sound/isa/msnd/msnd_pinnacle_mixer.c
--- linux-rc5/sound/isa/msnd/msnd_pinnacle_mixer.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-git/sound/isa/msnd/msnd_pinnacle_mixer.c 2009-01-22 21:01:42.220129702 +0100
@@ -0,0 +1,345 @@
+/***************************************************************************
+ 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/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", "MASS", "SPDIF",
+ };
+ struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+ unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = items;
+ if (uinfo->value.enumerated.item >= items)
+ uinfo->value.enumerated.item = items - 1;
+ 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 *chip = snd_kcontrol_chip(kcontrol);
+ /* MSND_MASK_IMIX is the default */
+ ucontrol->value.enumerated.item[0] = 0;
+
+ if (chip->recsrc & MSND_MASK_SYNTH) {
+ ucontrol->value.enumerated.item[0] = 1;
+ } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
+ test_bit(F_HAVEDIGITAL, &chip->flags)) {
+ ucontrol->value.enumerated.item[0] = 2;
+ }
+
+
+ return 0;
+}
+
+static int snd_msndmix_set_mux(struct snd_msnd *chip, 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_SYNTH;
+ msndbyte = HDEXAR_SET_SYNTH_IN;
+ break;
+ case 2:
+ newrecsrc = MSND_MASK_DIGITAL;
+ msndbyte = HDEXAR_SET_DAT_IN;
+ break;
+ default:
+ return -EINVAL;
+ }
+ change = newrecsrc != chip->recsrc;
+ if (change) {
+ change = 0;
+ if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
+ if (!snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ)) {
+ chip->recsrc = newrecsrc;
+ change = 1;
+ }
+ }
+ 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;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msnd->mixer_lock, flags);
+ ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
+ ucontrol->value.integer.value[0] /= 0xFFFF;
+ ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
+ ucontrol->value.integer.value[1] /= 0xFFFF;
+ spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+ return 0;
+}
+
+
+#define update_volm(a, b) \
+ do { \
+ writew((dev->left_levels[a] >> 1) * \
+ readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##b##Left); \
+ writew((dev->right_levels[a] >> 1) * \
+ readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##b##Right); \
+ } while (0);
+
+#define update_potm(d, s, ar) \
+ do { \
+ writeb((dev->left_levels[d] >> 8) * \
+ readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##s##Left); \
+ writeb((dev->right_levels[d] >> 8) * \
+ 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); \
+ } while (0);
+
+#define update_pot(d, s, ar) \
+ do { \
+ writeb(dev->left_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Left); \
+ 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); \
+ } while (0);
+
+
+static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
+{
+ int bLeft, bRight;
+ int wLeft, wRight;
+ int updatemaster = 0;
+
+ 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 */
+ writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
+ 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 */
+ writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
+ 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 */
+ writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
+ 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;
+
+ 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)
+{
+ dev->recsrc = -1;
+ return snd_msndmix_set_mux(dev, recsrc);
+}
+
----------------------------------------------------------------------
Promocja w Speak Up. 3 miesiace angielskiego gratis.
Sprawdz teraz i wypelnij formularz! >> http://link.interia.pl/f2019
2
3
[alsa-devel] [PATCH v2 2.6.30] ASoC: remove stand-alone mode support from CS4270 codec driver
by Timur Tabi 23 Jan '09
by Timur Tabi 23 Jan '09
23 Jan '09
The CS4270 supports stand-alone mode, where the codec is not connect to the
I2C or SPI buses. Instead, input voltages configure the codec at power-on.
The CS4270 ASoC device driver has partial support for this mode, but the
code was never tested, and partial support doesn't help anyone. It also made
the rest of the code more complicated than necessary.
Signed-off-by: Timur Tabi <timur(a)freescale.com>
---
v2: Added Kconfig changes
sound/soc/codecs/Kconfig | 1 +
sound/soc/codecs/cs4270.c | 92 +++++++++++++-------------------------------
sound/soc/fsl/Kconfig | 3 +-
3 files changed, 30 insertions(+), 66 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cb5fcd6..136e1bc 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -65,6 +65,7 @@ config SND_SOC_AK4535
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
+ depends on I2C
# Cirrus Logic CS4270 Codec Hardware Mute Support
# Select if you have external muting circuitry attached to your CS4270.
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index f1aa0c3..2e4ce04 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -12,11 +12,7 @@
*
* Current features/limitations:
*
- * 1) Software mode is supported. Stand-alone mode is automatically
- * selected if I2C is disabled or if a CS4270 is not found on the I2C
- * bus. However, stand-alone mode is only partially implemented because
- * there is no mechanism yet for this driver and the machine driver to
- * communicate the values of the M0, M1, MCLK1, and MCLK2 pins.
+ * 1) Software mode is supported. Stand-alone mode is not supported.
* 2) Only I2C is supported, not SPI
* 3) Only Master mode is supported, not Slave.
* 4) The machine driver's 'startup' function must call
@@ -33,14 +29,6 @@
#include <sound/initval.h>
#include <linux/i2c.h>
-#include "cs4270.h"
-
-/* If I2C is defined, then we support software mode. However, if we're
- not compiled as module but I2C is, then we can't use I2C calls. */
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-#define USE_I2C
-#endif
-
/* Private data for the CS4270 */
struct cs4270_private {
unsigned int mclk; /* Input frequency of the MCLK pin */
@@ -60,8 +48,6 @@ struct cs4270_private {
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
-#ifdef USE_I2C
-
/* CS4270 registers addresses */
#define CS4270_CHIPID 0x01 /* Chip ID */
#define CS4270_PWRCTL 0x02 /* Power Control */
@@ -272,17 +258,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
/*
- * A list of addresses on which this CS4270 could use. I2C addresses are
- * 7 bits. For the CS4270, the upper four bits are always 1001, and the
- * lower three bits are determined via the AD2, AD1, and AD0 pins
- * (respectively).
- */
-static const unsigned short normal_i2c[] = {
- 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD;
-
-/*
* Pre-fill the CS4270 register cache.
*
* We use the auto-increment feature of the CS4270 to read all registers in
@@ -476,7 +451,6 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
}
#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-
/*
* Set the CS4270 external mute
*
@@ -501,32 +475,16 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute)
return snd_soc_write(codec, CS4270_MUTE, reg6);
}
-
+#else
+#define cs4270_mute NULL
#endif
-static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *);
-
/* A list of non-DAPM controls that the CS4270 supports */
static const struct snd_kcontrol_new cs4270_snd_controls[] = {
SOC_DOUBLE_R("Master Playback Volume",
CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1)
};
-static const struct i2c_device_id cs4270_id[] = {
- {"cs4270", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
-
-static struct i2c_driver cs4270_i2c_driver = {
- .driver = {
- .name = "CS4270 I2C",
- .owner = THIS_MODULE,
- },
- .id_table = cs4270_id,
- .probe = cs4270_i2c_probe,
-};
-
/*
* Global variable to store socdev for i2c probe function.
*
@@ -633,7 +591,20 @@ error:
return ret;
}
-#endif /* USE_I2C*/
+static const struct i2c_device_id cs4270_id[] = {
+ {"cs4270", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+static struct i2c_driver cs4270_i2c_driver = {
+ .driver = {
+ .name = "cs4270",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs4270_id,
+ .probe = cs4270_i2c_probe,
+};
struct snd_soc_dai cs4270_dai = {
.name = "CS4270",
@@ -698,7 +669,6 @@ static int cs4270_probe(struct platform_device *pdev)
goto error_free_codec;
}
-#ifdef USE_I2C
cs4270_socdev = socdev;
ret = i2c_add_driver(&cs4270_i2c_driver);
@@ -708,20 +678,16 @@ static int cs4270_probe(struct platform_device *pdev)
}
/* Did we find a CS4270 on the I2C bus? */
- if (codec->control_data) {
- /* Initialize codec ops */
- cs4270_dai.ops.hw_params = cs4270_hw_params;
- cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
- cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
-#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
- cs4270_dai.ops.digital_mute = cs4270_mute;
-#endif
- } else
- printk(KERN_INFO "cs4270: no I2C device found, "
- "using stand-alone mode\n");
-#else
- printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n");
-#endif
+ if (!codec->control_data) {
+ printk(KERN_ERR "cs4270: failed to attach driver");
+ goto error_del_driver;
+ }
+
+ /* Initialize codec ops */
+ cs4270_dai.ops.hw_params = cs4270_hw_params;
+ cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
+ cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
+ cs4270_dai.ops.digital_mute = cs4270_mute;
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -732,11 +698,9 @@ static int cs4270_probe(struct platform_device *pdev)
return 0;
error_del_driver:
-#ifdef USE_I2C
i2c_del_driver(&cs4270_i2c_driver);
error_free_pcms:
-#endif
snd_soc_free_pcms(socdev);
error_free_codec:
@@ -752,9 +716,7 @@ static int cs4270_remove(struct platform_device *pdev)
snd_soc_free_pcms(socdev);
-#ifdef USE_I2C
i2c_del_driver(&cs4270_i2c_driver);
-#endif
kfree(socdev->codec);
socdev->codec = NULL;
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index c7c78c3..9fc9082 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -10,7 +10,8 @@ config SND_SOC_MPC8610
config SND_SOC_MPC8610_HPCD
tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
- depends on MPC8610_HPCD
+ # I2C is necessary for the CS4270 driver
+ depends on MPC8610_HPCD && I2C
select SND_SOC_MPC8610
select SND_SOC_CS4270
select SND_SOC_CS4270_VD33_ERRATA
--
1.5.5
3
5
when using any kernel(2.6.17-present)
I see under dmesg:
[ 2.702799] Advanced Linux Sound Architecture Driver Version 1.0.18a.
[ 2.711657] ALSA device list:
[ 2.720204] No soundcards found.
how do I change this? i.g.
ALSA device list:
(some card name)
I have a macbook pro ATI chipset.
regards;
Justin P. Mattock
2
1