[alsa-devel] [PATCH] ALSA: Support Media Vision Jazz16 chips
From: Rask Ingemann Lambertsen rask@sygehus.dk
- Add support for Jazz16 features to the common SoundBlaster code. - Add a front end for Jazz16 based sound cards.
Tested with a Jazz16 based sound card and Linux 2.6.20.
Signed-off-by: Rask Ingemann Lambertsen rask@sygehus.dk ---
This patch is a prerequisite for the Jazz PnP patch, which needs the patched include/sound/sb.h.
Documentation/sound/alsa/ALSA-Configuration.txt | 10 include/sound/sb.h | 5 sound/isa/Kconfig | 15 + sound/isa/sb/Makefile | 2 sound/isa/sb/jazz16.c | 193 ++++++++++++++ sound/isa/sb/sb8_main.c | 105 +++++++ sound/isa/sb/sb_common.c | 12 sound/isa/sb/sb_mixer.c | 3 8 files changed, 335 insertions(+), 10 deletions(-)
--- linux-2.6.20/sound/isa/sb/Makefile.orig 2007-02-19 21:00:09.000000000 +0100 +++ linux-2.6.20/sound/isa/sb/Makefile 2007-03-02 20:14:48.000000000 +0100 @@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o snd-sbawe-objs := sbawe.o emu8000.o snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o snd-es968-objs := es968.o +snd-jazz16-objs := jazz16.o
# # this function returns: @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SB16) += snd-sb16.o snd obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o +obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o snd-sb8-dsp.o snd-sb-common.o ifeq ($(CONFIG_SND_SB16_CSP),y) obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o --- linux-2.6.20/sound/isa/sb/jazz16.c-orig 2007-02-17 20:01:40.000000000 +0100 +++ linux-2.6.20/sound/isa/sb/jazz16.c 2007-03-18 13:43:35.000000000 +0100 @@ -0,0 +1,193 @@ +/* Driver for Media Vision Jazz16 based boards. + * + * Copyright (c) 2007 by Rask Ingemann Lambertsen + * + * 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 + * + * The Jazz16 is an SB Pro compatible chip with a 16-bit mode and higher + * playback and capture rates added to it. It is not SB 16 compatible. + * There is also an MPU-401 interface. + * + * The IBM PPS Model 6015 has a Jazz16 chip on board. Please tell me if it + * works with this driver or not. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/pnp.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/sb.h> +#include <sound/mpu401.h> +#include <sound/opl3.h> +#include <sound/initval.h> + +MODULE_AUTHOR ("Rask Ingemann Lambertsen rask@sygehus.dk"); +MODULE_DESCRIPTION ("Jazz16"); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Jazz16 soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Jazz16 soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Jazz16 soundcard."); + +#define PFX "jazz16: " +#define PFX_WARN KERN_WARNING PFX +#define PFX_ERR KERN_ERR PFX + +static struct pnp_driver snd_jazz16_pnp_driver; + +static irqreturn_t jazz16_interrupt(int irq, void *dev_id) +{ + struct snd_sb *chip = (struct snd_sb *) dev_id; + return snd_sb8dsp_interrupt(chip); +} + +static struct pnp_device_id snd_jazz16_pnpids[] = { + { .id = "PNPb00f" }, + { .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, snd_jazz16_pnpids); + +static int __devinit snd_jazz16_pnp_probe(struct pnp_dev *pnp_dev, + const struct pnp_device_id *pnp_id) +{ struct snd_sb *chip; + struct snd_card *card; + struct snd_opl3 *opl3; + int err; + uint sbport, sbirq, sbdma8, sbdma16, mpuport, mpuirq; + static uint dev_num = 0; + + if (enable[dev_num]) + card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0); + else + card = NULL; + dev_num ++; + if (card == NULL) + return -ENOMEM; + pnp_set_drvdata(pnp_dev, card); + /* TODO use pnp_port_valid(), pnp_port_flags(), pnp_port_length()... */ + sbport = pnp_port_start(pnp_dev, 0); + sbirq = pnp_irq(pnp_dev, 0); + sbdma8 = pnp_dma(pnp_dev, 0); + sbdma16 = pnp_dma(pnp_dev, 1); + err = snd_sbdsp_create(card, sbport, sbirq, jazz16_interrupt, + sbdma8, sbdma16, SB_HW_AUTO, &chip); + if (err < 0) { + snd_card_free(card); + return err; + } + /* TODO length limits - strncpy()/snprintf() and friends. */ + strcpy(card->driver, "Jazz16"); + strcpy(card->shortname, "Media Vision Jazz16"); + sprintf(card->longname, "%s at 0x%x, irq %u, dma8 %u, dma16 %u", + chip->name, sbport, sbirq, sbdma8, sbdma16); + + if (chip->hardware != SB_HW_JAZZ16) { + snd_printk(PFX_ERR "Not a Jazz16 chip at 0x%x.\n", sbport); + snd_card_free(card); + return -ENODEV; + } + err = snd_sb8dsp_pcm(chip, 0, NULL); + if (err < 0) { + snd_card_free(card); + return err; + } + err = snd_sbmixer_new(chip); + if (err < 0) { + snd_card_free(card); + return err; + } + err = snd_opl3_create(card, sbport, sbport + 2, + OPL3_HW_AUTO, 1, &opl3); + if (err < 0) { + snd_printk(PFX_WARN "No OPL device found, skipping.\n"); + } else { + err = snd_opl3_timer_new(opl3, 1, 2); + if (err < 0) { + snd_card_free(card); + return err; + } + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { + snd_card_free(card); + return err; + } + } + if (pnp_port_valid(pnp_dev, 1) + && !(pnp_port_flags(pnp_dev, 1) & IORESOURCE_DISABLED)) { + int mpuirqflags; + if (!pnp_irq_valid(pnp_dev, 1) + || pnp_irq_flags(pnp_dev, 1) & IORESOURCE_DISABLED) { + mpuirq = -1; + mpuirqflags = 0; + } else { + mpuirq = pnp_irq(pnp_dev, 1); + mpuirqflags = IRQF_DISABLED; + } + mpuport = pnp_port_start(pnp_dev, 1); + err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpuport, 0, mpuirq, + mpuirqflags, NULL); + if (err < 0) { + snd_printk(PFX_WARN "MPU-401 device not configured, skipping.\n"); + } + } + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return err; + } + return 0; +} + +static void __devexit snd_jazz16_pnp_remove(struct pnp_dev *dev) +{ + snd_card_free(pnp_get_drvdata(dev)); + pnp_set_drvdata(dev, NULL); +} + +static struct pnp_driver snd_jazz16_pnp_driver = { + .name = "Jazz16", + .id_table = snd_jazz16_pnpids, + .probe = snd_jazz16_pnp_probe, + .remove = __devexit_p(snd_jazz16_pnp_remove), +}; + +static int __devinit alsa_card_jazz16_init (void) +{ + return pnp_register_driver(&snd_jazz16_pnp_driver); +} + +static void __devexit alsa_card_jazz16_exit(void) +{ + pnp_unregister_driver(&snd_jazz16_pnp_driver); +} + +module_init (alsa_card_jazz16_init); +module_exit (alsa_card_jazz16_exit); --- linux-2.6.20/sound/isa/sb/sb_mixer.c.orig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20/sound/isa/sb/sb_mixer.c 2007-02-25 01:09:05.000000000 +0100 @@ -811,6 +811,7 @@ int snd_sbmixer_new(struct snd_sb *chip) return err; break; case SB_HW_PRO: + case SB_HW_JAZZ16: if ((err = snd_sbmixer_init(chip, snd_sbpro_controls, ARRAY_SIZE(snd_sbpro_controls), @@ -946,6 +947,7 @@ void snd_sbmixer_suspend(struct snd_sb * save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); break; case SB_HW_PRO: + case SB_HW_JAZZ16: save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); break; case SB_HW_16: @@ -971,6 +973,7 @@ void snd_sbmixer_resume(struct snd_sb *c restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); break; case SB_HW_PRO: + case SB_HW_JAZZ16: restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); break; case SB_HW_16: --- linux-2.6.20/sound/isa/sb/sb_common.c.orig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20/sound/isa/sb/sb_common.c 2007-03-03 12:50:32.000000000 +0100 @@ -146,8 +146,16 @@ static int snd_sbdsp_probe(struct snd_sb } break; case 3: - chip->hardware = SB_HW_PRO; - str = "Pro"; + spin_lock_irqsave(&chip->reg_lock, flags); + if (snd_sbdsp_command(chip, SB_DSP_GET_JAZZ_VERSION) && + SB_VERSION_IS_JAZZ16(snd_sbdsp_get_byte (chip))) { + chip->hardware = SB_HW_JAZZ16; + str = "Pro (Jazz16)"; + } else { + chip->hardware = SB_HW_PRO; + str = "Pro"; + } + spin_unlock_irqrestore (&chip->reg_lock, flags); break; case 4: chip->hardware = SB_HW_16; --- linux-2.6.20/sound/isa/sb/sb8_main.c.orig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20/sound/isa/sb/sb8_main.c 2007-03-24 23:30:22.000000000 +0100 @@ -28,6 +28,9 @@ * * Wed Jul 12 22:02:55 CEST 2000 Uros Bizjak uros@kss-loka.si * Cleaned up and rewrote lowlevel routines. + * + * Sat Mar 24 23:29:20 CEST 2007 Rask Ingemann Lambertsen rask@sygehus.dk + * Added Jazz16 enhancements (ported from sound/oss/sb_common.c). */
#include <sound/driver.h> @@ -73,6 +76,15 @@ static struct snd_ratnum stereo_clocks[] } };
+/* For stereo playback and capture, the denominator is divided by two, so it + * must be even to get the intended sample rate. */ +static struct snd_ratnum jazz16_stereo_clock = { + .num = SB8_CLOCK, + .den_min = 2, + .den_max = 512, + .den_step = 2, +}; + static int snd_sb8_hw_constraint_rate_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -101,14 +113,53 @@ static int snd_sb8_hw_constraint_channel return 0; }
+static int snd_jazz16_hw_constraint_rate_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + int err = 0; + + if (c->max > 1) { + unsigned int num = 0, den = 0; + err = snd_interval_ratnum(r, 1, &jazz16_stereo_clock, &num, &den); + if (err >= 0 && den) { + params->rate_num = num; + params->rate_den = den; + } + } + return err; +} + +static int snd_jazz16_hw_constraint_channels_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + int err = 0; + + /* Force mono mode if the sample rate interval doesn't allow stereo. */ + if (SB8_DEN(r->min) == SB8_DEN(r->max) + && SB8_DEN(r->min) & 1) + { + struct snd_interval t = { .min = 1, .max = 1 }; + struct snd_interval *c; + + c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + err = snd_interval_refine(c, &t); + } + return err; +} + static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) { unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int mixreg, rate, size, count; + unsigned int mixreg, rate, size, count, dma; + unsigned char stereo, format;
rate = runtime->rate; + stereo = runtime->channels > 1; switch (chip->hardware) { case SB_HW_PRO: if (runtime->channels > 1) { @@ -117,6 +168,7 @@ static int snd_sb8_playback_prepare(stru break; } /* fallthru */ + case SB_HW_JAZZ16: case SB_HW_201: if (rate > 23000) { chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; @@ -134,8 +186,17 @@ static int snd_sb8_playback_prepare(stru } size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { + dma = chip->dma16; + format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; + } else { + dma = chip->dma8; + format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; + } spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); + if (chip->hardware >= SB_HW_PRO) + snd_sbdsp_command(chip, format); if (runtime->channels > 1) { /* set playback stereo mode */ spin_lock(&chip->mixer_lock); @@ -173,7 +234,7 @@ static int snd_sb8_playback_prepare(stru snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_dma_program(chip->dma8, runtime->dma_addr, + snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0; } @@ -232,9 +293,11 @@ static int snd_sb8_capture_prepare(struc unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int mixreg, rate, size, count; + unsigned int mixreg, rate, size, count, dma; + unsigned char stereo, format;
rate = runtime->rate; + stereo = runtime->channels > 1; switch (chip->hardware) { case SB_HW_PRO: if (runtime->channels > 1) { @@ -242,6 +305,8 @@ static int snd_sb8_capture_prepare(struc chip->capture_format = SB_DSP_HI_INPUT_AUTO; break; } + /* fall through */ + case SB_HW_JAZZ16: chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO; break; case SB_HW_201: @@ -261,10 +326,17 @@ static int snd_sb8_capture_prepare(struc } size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { + dma = chip->dma16; + format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; + } else { + dma = chip->dma8; + format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; + } spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); - if (runtime->channels > 1) - snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); + if (chip->hardware >= SB_HW_PRO) + snd_sbdsp_command(chip, format); snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); if (runtime->channels > 1) { snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); @@ -285,7 +357,7 @@ static int snd_sb8_capture_prepare(struc snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_dma_program(chip->dma8, runtime->dma_addr, + snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); return 0; } @@ -358,10 +430,12 @@ static snd_pcm_uframes_t snd_sb8_playbac { struct snd_sb *chip = snd_pcm_substream_chip(substream); size_t ptr; + int dma;
if (chip->mode != SB_MODE_PLAYBACK_8) return 0; - ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size); + dma = (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? chip->dma16 : chip->dma8; + ptr = snd_dma_pointer(dma, chip->p_dma_size); return bytes_to_frames(substream->runtime, ptr); }
@@ -369,10 +443,12 @@ static snd_pcm_uframes_t snd_sb8_capture { struct snd_sb *chip = snd_pcm_substream_chip(substream); size_t ptr; + int dma;
if (chip->mode != SB_MODE_CAPTURE_8) return 0; - ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size); + dma = (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? chip->dma16 : chip->dma8; + ptr = snd_dma_pointer(dma, chip->c_dma_size); return bytes_to_frames(substream->runtime, ptr); }
@@ -443,6 +519,19 @@ static int snd_sb8_open(struct snd_pcm_s runtime->hw = snd_sb8_capture; } switch (chip->hardware) { + case SB_HW_JAZZ16: + runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; + runtime->hw.rates |= SNDRV_PCM_RATE_8000_44100; + runtime->hw.rate_max = 45455; + runtime->hw.channels_max = 2; + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + snd_jazz16_hw_constraint_rate_channels, NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, -1); + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + snd_jazz16_hw_constraint_channels_rate, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + break; case SB_HW_PRO: runtime->hw.rate_max = 44100; runtime->hw.channels_max = 2; --- linux-2.6.20/sound/isa/Kconfig.orig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20/sound/isa/Kconfig 2007-03-25 21:49:44.000000000 +0200 @@ -248,6 +248,21 @@ config SND_INTERWAVE_STB To compile this driver as a module, choose M here: the module will be called snd-interwave-stb.
+config SND_JAZZ16 + tristate "Media Vision Jazz16" + depends on SND + select SND_OPL3_LIB + select SND_PCM + help + Say Y here to include support for Media Vision Jazz16 based + soundcards. + + You probably want to enable Jazz16 Plug and Play support + (CONFIG_JAZZ16PNP) also. + + To compile this driver as a module, choose M here: the module + will be called snd-jazz16. + config SND_OPL3SA2 tristate "Yamaha OPL3-SA2/SA3" depends on SND --- linux-2.6.20/Documentation/sound/alsa/ALSA-Configuration.txt-orig 2007-02-04 19:44:54.000000000 +0100 +++ linux-2.6.20/Documentation/sound/alsa/ALSA-Configuration.txt 2007-03-25 20:35:31.000000000 +0200 @@ -1120,6 +1120,16 @@ Prior to version 0.9.0rc4 options had a
This module supports multiple cards, autoprobe and ISA PnP.
+ Module snd-jazz16 + ----------------- + + Module for sound cards based on Media Vision Jazz16 chip (PnP only) + + This module supports multiple cards and PnP. + + Note: You will most likely want to enable Jazz16 PnP support + (CONFIG_JAZZ16PNP) in the kernel. + Module snd-korg1212 -------------------
--- linux-2.6.20/include/sound/sb.h.orig 2007-02-19 20:57:51.000000000 +0100 +++ linux-2.6.20/include/sound/sb.h 2007-03-25 21:37:01.000000000 +0200 @@ -33,6 +33,7 @@ enum sb_hw_type { SB_HW_20, SB_HW_201, SB_HW_PRO, + SB_HW_JAZZ16, /* Media Vision Jazz16 chip */ SB_HW_16, SB_HW_16CSP, /* SB16 with CSP chip */ SB_HW_ALS100, /* Avance Logic ALS100 chip */ @@ -142,6 +143,7 @@ struct snd_sb { #define SB_DSP_HI_INPUT_AUTO 0x98 #define SB_DSP_IMMED_INT 0xf2 #define SB_DSP_GET_VERSION 0xe1 +#define SB_DSP_GET_JAZZ_VERSION 0xfa #define SB_DSP_SPEAKER_ON 0xd1 #define SB_DSP_SPEAKER_OFF 0xd3 #define SB_DSP_DMA8_OFF 0xd0 @@ -265,6 +267,9 @@ struct snd_sb { #define SB_DMASETUP_DMA6 0x40 #define SB_DMASETUP_DMA7 0x80
+/* Check the output of SB_DSP_GET_JAZZ_VERSION. */ +#define SB_VERSION_IS_JAZZ16(x) ((x) == 0x12) + /* * */
On 03/26/2007 11:23 PM, Rask Ingemann Lambertsen wrote:
Fundamental model questions still waiting on reply from Adam belay...
--- linux-2.6.20/sound/isa/sb/jazz16.c-orig 2007-02-17 20:01:40.000000000 +0100 +++ linux-2.6.20/sound/isa/sb/jazz16.c 2007-03-18 13:43:35.000000000 +0100 @@ -0,0 +1,193 @@ +/* Driver for Media Vision Jazz16 based boards.
- Copyright (c) 2007 by Rask Ingemann Lambertsen
- 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
- The Jazz16 is an SB Pro compatible chip with a 16-bit mode and higher
- playback and capture rates added to it. It is not SB 16 compatible.
- There is also an MPU-401 interface.
- The IBM PPS Model 6015 has a Jazz16 chip on board. Please tell me if it
- works with this driver or not.
- */
+#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/pnp.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <sound/driver.h>
ALSA drivers usually have sound/driver.h as the first include. I'm not sure how sensible that is...
+#include <sound/core.h> +#include <sound/sb.h> +#include <sound/mpu401.h> +#include <sound/opl3.h> +#include <sound/initval.h>
+MODULE_AUTHOR ("Rask Ingemann Lambertsen rask@sygehus.dk"); +MODULE_DESCRIPTION ("Jazz16");
No spaces before the ( please.
+MODULE_LICENSE("GPL");
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */
+module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Jazz16 soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Jazz16 soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Jazz16 soundcard.");
+#define PFX "jazz16: " +#define PFX_WARN KERN_WARNING PFX +#define PFX_ERR KERN_ERR PFX
+static struct pnp_driver snd_jazz16_pnp_driver;
+static irqreturn_t jazz16_interrupt(int irq, void *dev_id) +{
- struct snd_sb *chip = (struct snd_sb *) dev_id;
Please don't cast void pointers, it's useless (and a matter of kernel coding style).
- return snd_sb8dsp_interrupt(chip);
+}
+static struct pnp_device_id snd_jazz16_pnpids[] = {
- { .id = "PNPb00f" },
- { .id = "" }
+}; +MODULE_DEVICE_TABLE(pnp, snd_jazz16_pnpids);
+static int __devinit snd_jazz16_pnp_probe(struct pnp_dev *pnp_dev,
const struct pnp_device_id *pnp_id)
+{ struct snd_sb *chip;
- struct snd_card *card;
- struct snd_opl3 *opl3;
- int err;
- uint sbport, sbirq, sbdma8, sbdma16, mpuport, mpuirq;
- static uint dev_num = 0;
- if (enable[dev_num])
card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0);
- else
card = NULL;
- dev_num ++;
- if (card == NULL)
return -ENOMEM;
-ENOMEM is not a very good return value for !enable. -ENODEV would be better. Also please dev_num++ without the space.
The hardware fundamentally supports just one card per system due to the fixed config port, so you might as well get rid of the dev_num (and the SNDRV_CARDS-wide arrays) it seems?. If you want to keep them that way just so that it's more generic looking... sure.
- pnp_set_drvdata(pnp_dev, card);
- /* TODO use pnp_port_valid(), pnp_port_flags(), pnp_port_length()... */
- sbport = pnp_port_start(pnp_dev, 0);
- sbirq = pnp_irq(pnp_dev, 0);
- sbdma8 = pnp_dma(pnp_dev, 0);
- sbdma16 = pnp_dma(pnp_dev, 1);
- err = snd_sbdsp_create(card, sbport, sbirq, jazz16_interrupt,
sbdma8, sbdma16, SB_HW_AUTO, &chip);
- if (err < 0) {
snd_card_free(card);
return err;
- }
The "snd_card_free(card); return err;" error exit is repated many times. Personally I don't really mind, but general kernel coding style is doing that with a goto to an error exit. Yes, as long as you're careful the compiler will optimize to that anyway, but for example Andrew Morton would slap you for it.
- /* TODO length limits - strncpy()/snprintf() and friends. */
That's not really needed. You know how wide the buffers and your strings are, overrunning them is just a driver bug; it's not something that can be influenced from userland or anything.
- strcpy(card->driver, "Jazz16");
- strcpy(card->shortname, "Media Vision Jazz16");
- sprintf(card->longname, "%s at 0x%x, irq %u, dma8 %u, dma16 %u",
chip->name, sbport, sbirq, sbdma8, sbdma16);
Could you use %#x instead of 0x%x? People went through the pain of adding pretty-printing to printk() so might as well use it...
- if (chip->hardware != SB_HW_JAZZ16) {
snd_printk(PFX_ERR "Not a Jazz16 chip at 0x%x.\n", sbport);
Ditto.
snd_card_free(card);
return -ENODEV;
- }
- err = snd_sb8dsp_pcm(chip, 0, NULL);
- if (err < 0) {
snd_card_free(card);
return err;
- }
- err = snd_sbmixer_new(chip);
- if (err < 0) {
snd_card_free(card);
return err;
- }
- err = snd_opl3_create(card, sbport, sbport + 2,
OPL3_HW_AUTO, 1, &opl3);
- if (err < 0) {
snd_printk(PFX_WARN "No OPL device found, skipping.\n");
- } else {
Single statement branches don't have braces in the kernel coding style.
err = snd_opl3_timer_new(opl3, 1, 2);
if (err < 0) {
snd_card_free(card);
return err;
}
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0) {
snd_card_free(card);
return err;
}
- }
- if (pnp_port_valid(pnp_dev, 1)
&& !(pnp_port_flags(pnp_dev, 1) & IORESOURCE_DISABLED)) {
int mpuirqflags;
if (!pnp_irq_valid(pnp_dev, 1)
|| pnp_irq_flags(pnp_dev, 1) & IORESOURCE_DISABLED) {
mpuirq = -1;
mpuirqflags = 0;
} else {
mpuirq = pnp_irq(pnp_dev, 1);
mpuirqflags = IRQF_DISABLED;
}
mpuport = pnp_port_start(pnp_dev, 1);
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpuport, 0, mpuirq,
mpuirqflags, NULL);
if (err < 0) {
snd_printk(PFX_WARN "MPU-401 device not configured, skipping.\n");
}
Braces again.
I like what you do with the MPU401 in this version better . If it can only be configured when the SB part is active it's fundamentally part of the card, and not something to be driven by the seperate snd-mpu401.
- }
I believe you need a snd_card_set_dev(card, &pnp_dev->dev) here.
- err = snd_card_register(card);
- if (err < 0) {
snd_card_free(card);
return err;
- }
- return 0;
+}
+static void __devexit snd_jazz16_pnp_remove(struct pnp_dev *dev) +{
- snd_card_free(pnp_get_drvdata(dev));
- pnp_set_drvdata(dev, NULL);
+}
+static struct pnp_driver snd_jazz16_pnp_driver = {
- .name = "Jazz16",
- .id_table = snd_jazz16_pnpids,
- .probe = snd_jazz16_pnp_probe,
- .remove = __devexit_p(snd_jazz16_pnp_remove),
+};
+static int __devinit alsa_card_jazz16_init (void)
No space before the (void) please.
+{
- return pnp_register_driver(&snd_jazz16_pnp_driver);
+}
+static void __devexit alsa_card_jazz16_exit(void) +{
- pnp_unregister_driver(&snd_jazz16_pnp_driver);
+}
+module_init (alsa_card_jazz16_init); +module_exit (alsa_card_jazz16_exit);
Nor after the init/exit.
I didn't look at the changes to the low-level sb code; I've too little experience there. Hope this was useful though.
And hope Adam comments on the model...
Rene.
On Tue, Mar 27, 2007 at 12:45:41AM +0200, Rene Herman wrote:
On 03/26/2007 11:23 PM, Rask Ingemann Lambertsen wrote:
- if (enable[dev_num])
card = snd_card_new(index[dev_num], id[dev_num],
THIS_MODULE, 0);
- else
card = NULL;
- dev_num ++;
- if (card == NULL)
return -ENOMEM;
-ENOMEM is not a very good return value for !enable. -ENODEV would be better. Also please dev_num++ without the space.
Oops. Well spotted.
The hardware fundamentally supports just one card per system due to the fixed config port, so you might as well get rid of the dev_num (and the SNDRV_CARDS-wide arrays) it seems?. If you want to keep them that way just so that it's more generic looking... sure.
Also, if someone, somehow, manages to have two of these cards, I would find it unforgivable if it didn't just work. According to this press release URL:http://findarticles.com/p/articles/mi_m0NEW/is_1993_July_23/ai_14099965, there should be motherboards with Jazz16 chips on them, presumably to be configured using the PnPBIOS (the specification for which was released in 1994). It might still be possible to have a stand-alone Jazz16 card in addition to an on-board one.
- if (err < 0) {
snd_printk(PFX_WARN "No OPL device found, skipping.\n");
- } else {
Single statement branches don't have braces in the kernel coding style.
OK. Documentation/CodingStyle should probably say so.
And hope Adam comments on the model...
Me too.
On 03/27/2007 02:32 AM, Rask Ingemann Lambertsen wrote:
The hardware fundamentally supports just one card per system due to the fixed config port, so you might as well get rid of the dev_num (and the SNDRV_CARDS-wide arrays) it seems?. If you want to keep them that way just so that it's more generic looking... sure.
Also, if someone, somehow, manages to have two of these cards, I would find it unforgivable if it didn't just work. According to this press release URL:http://findarticles.com/p/articles/mi_m0NEW/is_1993_July_23/ai_14099965, there should be motherboards with Jazz16 chips on them, presumably to be configured using the PnPBIOS (the specification for which was released in 1994). It might still be possible to have a stand-alone Jazz16 card in addition to an on-board one.
Okay, fair enough.
Single statement branches don't have braces in the kernel coding style.
OK. Documentation/CodingStyle should probably say so.
Linux kernel coding style is (un)fortunately a rather hodge-podge mix of written and unwritten rules. It's not random though -- reading reviews by other developers helps...
The snd_card_set_dev() was the other non-trivial thing in there. Was that logged?
Rene.
At Tue, 27 Mar 2007 10:57:48 +0200, Rene Herman wrote:
The snd_card_set_dev() was the other non-trivial thing in there.
Yeah, that's a feature newly added in the later development and became mandatory for the recent systems because udev/HAL requires the device pointer to identify the sound device. Without this call, the automatic loading won't work.
Takashi
On Tue, Mar 27, 2007 at 10:57:48AM +0200, Rene Herman wrote:
On 03/27/2007 02:32 AM, Rask Ingemann Lambertsen wrote:
Also, if someone, somehow, manages to have two of these cards, I would find it unforgivable if it didn't just work. According to this press release URL:http://findarticles.com/p/articles/mi_m0NEW/is_1993_July_23/ai_14099965, there should be motherboards with Jazz16 chips on them, presumably to be configured using the PnPBIOS (the specification for which was released in 1994). It might still be possible to have a stand-alone Jazz16 card in addition to an on-board one.
Texas Instruments/Acer TravelMate 5000 series has one on-board. Interestingly, the User's Reference Guide lists 1, 3, 5 and 7 as valid DMA channels for both 8-bit and 16-bit playback. Since the chip is only capable of half-duplex AFAIK, why have two DMA channels? What am I missing?
The snd_card_set_dev() was the other non-trivial thing in there. Was that logged?
It was (even if at 2:32 AM), and indeed automatic module loading didn't work.
On 03/27/2007 10:14 PM, Rask Ingemann Lambertsen wrote:
(dropped Adam Belay from the CC)
Texas Instruments/Acer TravelMate 5000 series has one on-board. Interestingly, the User's Reference Guide lists 1, 3, 5 and 7 as valid DMA channels for both 8-bit and 16-bit playback. Since the chip is only capable of half-duplex AFAIK, why have two DMA channels? What am I missing?
Nothing much I'd say. As far as I know, the card's half-duplex. I just now installed the Media Vision DOS driver (*) and it allows the following settings. Defaults starred:
Jazz I/O Port: 210, *220, 230, 240, 250, 260 (<-- align 10?) Jazz IRQ: 2, 3, *5, 7, 10, 15 8 bit DMA: *1, 3 16 bit DMA: 1, 3, *5, 7 MPU-401 Enable: Yes (<-- yes, no "No") MPU-401 I/O Port: 300, 310, 320, *330 MPU-401 IRQ: *2, 3, 5, 7 (<-- you're also listing 10 and 15?) CD ROM Port: 320, *340
That "CD ROM Port" seems to be a version glitch; mine only has an NCR SCSI chip with a 2x8 pin connector but the install asked me if I had a Sony, Panasonic or Mitsumi CD-ROM (those old proprietary CD-ROM interfaces).
Not much idea what that 1 and 3 are doing under "16-bit DMA". Things do seem to work when I pick 1 for the 8-bit and 3 for the 16-bit. But the DOS drivers at least don't list 5 and 7 as valid 8-bit DMAs...
(*) This driver: http://members.home.nl/rene.herman/jazz16.img
1440K FAT floppy image.
Would you happen to have a description of the DIP switches/jumpers? On mine, there's a red block of 8 DIP switches marked
MAB0 | MAB1 | DISMPU | DAB2 | DAB1 | DAB0 | DISJS | <empty>
which with the exception of the two DIS switches isn't completely self-evident; especially not since the chip's not on the bus before being programmed to be through software. There's also two 2x3 jumper blocks J10 and J11 that I've no idea about.
Rene.
On Wed, Mar 28, 2007 at 01:11:35AM +0200, Rene Herman wrote:
Nothing much I'd say. As far as I know, the card's half-duplex.
It is clearly only half-duplex when the DSP is in high-speed mode. It is less clear what will happen in low-speed mode if one tries to capture during playback or vice versa. I don't know if the Jazz16 needs high-speed mode at all, so I'll do some testing.
I just now installed the Media Vision DOS driver (*) and it allows the following settings. Defaults starred:
Jazz I/O Port: 210, *220, 230, 240, 250, 260 (<-- align 10?) Jazz IRQ: 2, 3, *5, 7, 10, 15 8 bit DMA: *1, 3 16 bit DMA: 1, 3, *5, 7 MPU-401 Enable: Yes (<-- yes, no "No") MPU-401 I/O Port: 300, 310, 320, *330 MPU-401 IRQ: *2, 3, 5, 7 (<-- you're also listing 10 and 15?)
I don't recall having ever managed to generate an MPU interrupt. I have no MIDI hardware.
CD ROM Port: 320, *340
That "CD ROM Port" seems to be a version glitch; mine only has an NCR SCSI chip with a 2x8 pin connector but the install asked me if I had a Sony, Panasonic or Mitsumi CD-ROM (those old proprietary CD-ROM interfaces).
Mine has an IDE port, jumper A for 0x1f0/0x3f6, jumper B for 0x1f0/0x376, jumper "CDROM IRQ" for 10, 11, 14 or 15. J9 & J10: 1-2 AMP OFF, 2-3: AMP ON.
Note that my board is rather anonymous. For all I know, it could be an OEM one.
Not much idea what that 1 and 3 are doing under "16-bit DMA". Things do seem to work when I pick 1 for the 8-bit and 3 for the 16-bit. But the DOS drivers at least don't list 5 and 7 as valid 8-bit DMAs...
Here goes (following a change of DMA maps in the PnP driver):
# echo 'set irq 10 dma 5 dma 1' > /sys/bus/pnp/devices/03:01/resources # modprobe snd-jazz16 $ cat /proc/asound/cards 0 [CMI8738 ]: CMI8738 - C-Media PCI CMI8738 C-Media PCI CMI8738 (model 37) at 0xd800, irq 9 1 [Jazz16 ]: Jazz16 - Media Vision Jazz16 Sound Blaster Pro (Jazz16) at 0x220, irq 10, dma8 5, dma16 1
$ aplay -v -D hw:Jazz16,0 /tmp/jazz16ting/TESTDMA.WAV Playing WAVE '/tmp/jazz16ting/TESTDMA.WAV' : Unsigned 8 bit, Rate 11025 Hz, Mono Hardware PCM card 1 'Media Vision Jazz16' device 0 subdevice 0 Its setup is: stream : PLAYBACK access : RW_INTERLEAVED format : U8 subformat : STD channels : 1 rate : 10989 exact rate : 10989 (1000000/91) msbits : 8 buffer_size : 5495 period_size : 1374 period_time : 125022 tick_time : 4000 tstamp_mode : NONE period_step : 1 sleep_min : 0 avail_min : 1374 xfer_align : 1374 start_threshold : 4122 stop_threshold : 5495 silence_threshold: 0 silence_size : 0 boundary : 1440481280 pointer (0x1578) for DMA #5 is greater than transfer size (0x1577) (repeats four times - note 0x1577 = 5495 = buffer size above)
Playback sounds normal except for a click for each "pointer ..." message. Any ideas? /proc/interrupts increments by 11.
$ aplay -v -D hw:Jazz16,0 /tmp/male.wav Playing WAVE '/tmp/male.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono Hardware PCM card 1 'Media Vision Jazz16' device 0 subdevice 0 Its setup is: stream : PLAYBACK access : RW_INTERLEAVED format : S16_LE subformat : STD channels : 1 rate : 8000 exact rate : 8000 (1000000/125) msbits : 16 buffer_size : 4000 period_size : 1000 period_time : 125000 tick_time : 4000 tstamp_mode : NONE period_step : 1 sleep_min : 0 avail_min : 1000 xfer_align : 1000 start_threshold : 4000 stop_threshold : 4000 silence_threshold: 0 silence_size : 0 boundary : 2097152000 aplay: pcm_write:1257: write error: Ind/ud-fejl
No sound, no interrupts and this message from /var/log/kernel: kernel: playback write error (DMA or IRQ trouble?)
Would you happen to have a description of the DIP switches/jumpers? On mine, there's a red block of 8 DIP switches marked
MAB0 | MAB1 | DISMPU | DAB2 | DAB1 | DAB0 | DISJS | <empty>
which with the exception of the two DIS switches isn't completely self-evident;
Guesswork: MAB0/1 to select SCSI BIOS memory address, DAB0-2 to select NCR chip SCSI device ID - does it happen to be set to 7? DAB0-2 could also tbe the NCR chip base address.
especially not since the chip's not on the bus before being programmed to be through software.
Does that also include the SCSI part?
There's also two 2x3 jumper blocks J10 and J11 that I've no idea about.
Line out left/right amplifier on/off, I guess.
On 03/28/2007 10:03 PM, Rask Ingemann Lambertsen wrote:
MPU-401 IRQ: *2, 3, 5, 7 (<-- you're also listing 10 and 15?)
I don't recall having ever managed to generate an MPU interrupt. I have no MIDI hardware.
I do, so I'll do some testing here. Need to set that up though...
CD ROM Port: 320, *340
That "CD ROM Port" seems to be a version glitch; mine only has an NCR SCSI chip with a 2x8 pin connector but the install asked me if I had a Sony, Panasonic or Mitsumi CD-ROM (those old proprietary CD-ROM interfaces).
Mine has an IDE port, jumper A for 0x1f0/0x3f6, jumper B for 0x1f0/0x376, jumper "CDROM IRQ" for 10, 11, 14 or 15. J9 & J10: 1-2 AMP OFF, 2-3: AMP ON.
Note that my board is rather anonymous. For all I know, it could be an OEM one.
I misidentified the chip. It's NCR, but not SCSI. It's a proprietary CD-ROM controller for a Philips CM260 CD-ROM drive. I remembered I actually had a standalone Philips CD-ROM controller lying around and while that has a motorola chip, it's the same type: a "DIGBIE2 LMSI". Don't have a drive to go with that...
On the back of my Jazz16 is a sticker saying "Philips".
# echo 'set irq 10 dma 5 dma 1' > /sys/bus/pnp/devices/03:01/resources
[ ... ]
Playing WAVE '/tmp/jazz16ting/TESTDMA.WAV' : Unsigned 8 bit, Rate 11025 Hz, Mono
[ ... ]
buffer_size : 5495 period_size : 1374
[ ... ]
pointer (0x1578) for DMA #5 is greater than transfer size (0x1577) (repeats four times - note 0x1577 = 5495 = buffer size above)
Playback sounds normal except for a click for each "pointer ..." message. Any ideas? /proc/interrupts increments by 11.
Well, not _really_ but I've just helped debug a problem (on a rather more modern card) with buffer alignment and I do remember some issues with ISA-DMA buffer alignment from the old DOS days; normally the OS should be taking care of it all, but maybe something on the hardware side is also confused about 8 versus 16-bit DMA. Long shot, but try playing with aplay --buffer-size=4096 and/or --period-size=1024 and maybe varying that a bit....
Playing WAVE '/tmp/male.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono
[ ... ]
No sound, no interrupts and this message from /var/log/kernel: kernel: playback write error (DMA or IRQ trouble?)
Oh good. "doesn't work" is a nice and definitive diagnosis :)
Would you happen to have a description of the DIP switches/jumpers? On mine, there's a red block of 8 DIP switches marked
MAB0 | MAB1 | DISMPU | DAB2 | DAB1 | DAB0 | DISJS | <empty>
which with the exception of the two DIS switches isn't completely self-evident;
Guesswork: MAB0/1 to select SCSI BIOS memory address, DAB0-2 to select NCR chip SCSI device ID - does it happen to be set to 7? DAB0-2 could also tbe the NCR chip base address.
I actually expect MAB0-1 is MPU Adress Base (00, 01, 10, 11 = 300, 310, 320, 330) and DAB0-2 is DSP Address Base (210, ..., 260). The other two jumper blocks are close to the NRC chip, not at all to the "SPK" out (my card also has a "soundblaster-like" wheel on the back for hardware volume control, and I believe that's the only way to influence the onboard, as opposed to onchip, amp). All switches just have two positions "ON" and "OFF" and all are currently OFF.
I'll let you know about the MPU IRQ.
Rene.
On Wed, Mar 28, 2007 at 10:03:30PM +0200, Rask Ingemann Lambertsen wrote:
It is clearly only half-duplex when the DSP is in high-speed mode. It is less clear what will happen in low-speed mode if one tries to capture during playback or vice versa. I don't know if the Jazz16 needs high-speed mode at all, so I'll do some testing.
It plays fine in low-speed mode even at 45454 Hz and in stereo.
Note that my board is rather anonymous. For all I know, it could be an OEM one.
FCC-ID KRN3261 leads me to KTL Research Limited, Hong Kong.
[8-bit playback through 16-bit DMA channel]
Playback sounds normal except for a click for each "pointer ..." message. Any ideas? /proc/interrupts increments by 11.
This additional patch fixes it:
--- linux-2.6.20/sound/isa/sb/sb8_main.c~ 2007-03-29 00:48:56.000000000 +0200 +++ linux-2.6.20/sound/isa/sb/sb8_main.c 2007-03-29 00:48:56.000000000 +0200 @@ -228,6 +228,8 @@ static int snd_sb8_playback_prepare(stru snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->playback_format != SB_DSP_OUTPUT) { + if (dma > 3) + count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); @@ -350,6 +352,8 @@ static int snd_sb8_capture_prepare(struc snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->capture_format != SB_DSP_OUTPUT) { + if (dma > 3) + count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); @@ -553,6 +557,12 @@ static int snd_sb8_open(struct snd_pcm_s } snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_clock); + if (chip->dma8 > 3) { + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); + } return 0; }
On 03/29/2007 01:20 AM, Rask Ingemann Lambertsen wrote:
Playback sounds normal except for a click for each "pointer ..." message. Any ideas? /proc/interrupts increments by 11.
This additional patch fixes it:
Mmm, well, that looks like it makes sense...
I checked the MPU IRQs (you allow 2/9, 3, 5, 7, 10, 15 while the DOS driver only allows 2/9, 3, 5, 7).
All of 2/9, 3, 5, 7, and 10 work fine here and 15 does not work. 15 also doesn't work here for the Jazz IRQ though while the DOS driver does allow 15 for that one, so I expect that's a local problem (no, nothing evident; no IDE, 15 reserved for ISA, ...). If you need me to I'll try in a different machine, but if 15 works fine for the Jazz IRQ for you, I'd write it not working for either IRQ for me off as an uninteresting glitch.
The Jazz16 has nice MPU-401 behaviour by the way; if I sent MIDI to its gameport, it loops it back out immediately unless I'm actually recording it from the Jazz16. That's sort of nice for testing...
I also checked the 210, 230 and 250 base values the DOS driver allows me to set the "Jazz16 I/O Port" to and all of those work fine. A change to jazz16pnp is attached as the first attachment. Has been tested, works fine.
Lastly, how would you feel about setting the DOS/Windows default resource values as the preffered values and all the others as mere acceptable? This will help keep the behaviour consistent over dual booting for one, and is more in line with any documentation someone might have on their card.
Ie, something like the second attachment (on top of first). Has also been tested, and also works fine.
Rene.
diff --git a/drivers/pnp/jazz16pnp.c b/drivers/pnp/jazz16pnp.c index cacb1df..e665945 100644 --- a/drivers/pnp/jazz16pnp.c +++ b/drivers/pnp/jazz16pnp.c @@ -181,7 +181,7 @@ out_no_dev: };
static struct pnp_port jazz16pnp_ports[2] __initdata = { - { .min = 0x220, .max = 0x260, .align = 0x20, .size = 0x10 }, + { .min = 0x210, .max = 0x260, .align = 0x10, .size = 0x10 }, { .min = 0x300, .max = 0x330, .align = 0x10, .size = 0x02 }, };
@@ -247,8 +247,11 @@ static void jazz16_port_setup(const uint u8 config;
switch (sbport) { + case 0x210: case 0x220: + case 0x230: case 0x240: + case 0x250: case 0x260: config = sbport & 0x70; jazz16_sb_port = sbport; @@ -508,7 +511,7 @@ static int __init jazz16pnp_init(void) if (jazz16pnp_verbose) printk(PFX_DEBUG "Scanning for Jazz16 cards...\n");
- for (base = 0x260; base >= 0x220; base -= 0x20) { + for (base = 0x260; base >= 0x210; base -= 0x10) { if (!request_region(base, 16, "Jazz16 PnP probe")) continue; if (jazz16pnp_verbose) @@ -522,7 +525,7 @@ static int __init jazz16pnp_init(void) if (jazz16pnp_count) break; } - if (base < 0x220) + if (base < 0x210) goto out_no_sbbase; if (!jazz16pnp_count) { err = -ENODEV;
diff --git a/drivers/pnp/jazz16pnp.c b/drivers/pnp/jazz16pnp.c index e665945..a7f173d 100644 --- a/drivers/pnp/jazz16pnp.c +++ b/drivers/pnp/jazz16pnp.c @@ -180,12 +180,18 @@ out_no_dev: return -ENOMEM; };
-static struct pnp_port jazz16pnp_ports[2] __initdata = { +static struct pnp_port jazz16pnp_ports[] __initdata = { + { .min = 0x220, .max = 0x220, .align = 0, .size = 0x10 }, + { .min = 0x330, .max = 0x330, .align = 0, .size = 0x02 }, { .min = 0x210, .max = 0x260, .align = 0x10, .size = 0x10 }, { .min = 0x300, .max = 0x330, .align = 0x10, .size = 0x02 }, };
-static struct pnp_irq jazz16pnp_irqs[2] __initdata = { +static struct pnp_irq jazz16pnp_irqs[] __initdata = { + { .map[0] = (1 << 5), + .flags = IORESOURCE_IRQ_HIGHEDGE }, + { .map[0] = (1 << 9), + .flags = IORESOURCE_IRQ_HIGHEDGE }, { .map[0] = (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9) | (1 << 10) | (1 << 15), .flags = IORESOURCE_IRQ_HIGHEDGE }, @@ -194,7 +200,9 @@ static struct pnp_irq jazz16pnp_irqs[2] .flags = IORESOURCE_IRQ_HIGHEDGE }, };
-static struct pnp_dma jazz16pnp_dmas[2] __initdata = { +static struct pnp_dma jazz16pnp_dmas[] __initdata = { + { .map = (1 << 1), .flags = IORESOURCE_DMA_8BIT, }, + { .map = (1 << 5), .flags = IORESOURCE_DMA_16BIT, }, { .map = (1 << 1) | (1 << 3), .flags = IORESOURCE_DMA_8BIT, }, { .map = (1 << 5) | (1 << 7), .flags = IORESOURCE_DMA_16BIT, }, }; @@ -215,9 +223,14 @@ static int __init jazz16pnp_add_sb(void) jazz16pnp_dmas, 2)) goto out_no_sboption; if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE, - jazz16pnp_ports, 2, - jazz16pnp_irqs, 1, - jazz16pnp_dmas, 2)) + &jazz16pnp_ports[2], 2, + &jazz16pnp_irqs[2], 2, + &jazz16pnp_dmas[2], 2)) + goto out_no_sboption; + if (!jazz16pnp_easy_option(sbdev, PNP_RES_PRIORITY_ACCEPTABLE, + &jazz16pnp_ports[2], 2, + &jazz16pnp_irqs[2], 1, + &jazz16pnp_dmas[2], 2)) goto out_no_sboption; memcpy(sbid->id, "PNPb00f", PNP_ID_LEN); pnp_add_id(sbid, sbdev);
On Thu, Mar 29, 2007 at 11:46:36PM +0200, Rene Herman wrote:
I checked the MPU IRQs (you allow 2/9, 3, 5, 7, 10, 15 while the DOS driver only allows 2/9, 3, 5, 7).
Thanks for your testing. Could you also test playback of 16-bit sounds through an 8-bit DMA channel in DOS?
All of 2/9, 3, 5, 7, and 10 work fine here and 15 does not work. 15 also doesn't work here for the Jazz IRQ though while the DOS driver does allow 15 for that one, so I expect that's a local problem (no, nothing evident; no IDE, 15 reserved for ISA, ...). If you need me to I'll try in a different machine, but if 15 works fine for the Jazz IRQ for you, I'd write it not working for either IRQ for me off as an uninteresting glitch.
While IRQ 15 works fine for me with an AD1816A card, I can not get IRQ 15 to work with the Jazz on the same machine. Over the weekend I'll try to use autoprobing to figure out exactly what is and isn't supported. I'll also look at circuit board traces and the ISA bus connector pinout for clues.
I also checked the 210, 230 and 250 base values the DOS driver allows me to set the "Jazz16 I/O Port" to and all of those work fine. A change to jazz16pnp is attached as the first attachment. Has been tested, works fine.
I also tried 0x270, but it didn't work. Maybe due to worries about the possibility of a parallel port at 0x278. I also tried 0x340, 0x350, 0x360 and 0x370 for the MPU port, but also with no luck.
Lastly, how would you feel about setting the DOS/Windows default resource values as the preffered values and all the others as mere acceptable?
I'll leave that up to Adam Belany. Personally, I have never understood the point of having a preferred option with the default values and an acceptable one with all the possible ones. A naive PnP stack risks that the defaults take required resources away from another card while a sofisticated PnP stack will most likely overrule the defaults anyway to prevent resource starvation.
@@ -194,7 +200,9 @@ static struct pnp_irq jazz16pnp_irqs[2] .flags = IORESOURCE_IRQ_HIGHEDGE }, };
-static struct pnp_dma jazz16pnp_dmas[2] __initdata = { +static struct pnp_dma jazz16pnp_dmas[] __initdata = {
- { .map = (1 << 1), .flags = IORESOURCE_DMA_8BIT, },
- { .map = (1 << 5), .flags = IORESOURCE_DMA_16BIT, }, { .map = (1 << 1) | (1 << 3), .flags = IORESOURCE_DMA_8BIT, }, { .map = (1 << 5) | (1 << 7), .flags = IORESOURCE_DMA_16BIT, },
};
You can change the second last DMA definition to
{ .map = (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7), .flags = IORESOURCE_DMA_8AND16BIT, },
On 03/31/2007 06:22 PM, Rask Ingemann Lambertsen wrote:
Thanks for your testing. Could you also test playback of 16-bit sounds through an 8-bit DMA channel in DOS?
This works fine. With the "8 bit DMA" set to 1 and the "16 bit DMA" to 3, 8 and 16-bit wave files play without problem.
While IRQ 15 works fine for me with an AD1816A card, I can not get IRQ 15 to work with the Jazz on the same machine. Over the weekend I'll try to use autoprobing to figure out exactly what is and isn't supported. I'll also look at circuit board traces and the ISA bus connector pinout for clues.
I got IRQ 15 to work. From looking at the traces, I could identify jumpers J10 as the "CD-ROM IRQ", with it being set to IRQ15 (with possibilities 11, 12 and 15). When I set it to something else, IRQ15 starts working both for the Jazz and the MPU-401 IRQ. That is, all of 3, 5, 7, 9, 10 and 15 now work for both IRQs for me.
I also tried 0x270, but it didn't work. Maybe due to worries about the possibility of a parallel port at 0x278. I also tried 0x340, 0x350, 0x360 and 0x370 for the MPU port, but also with no luck.
As said, mine has dip-switches with two marked MAB0 and MAB1 (and one MPUDIS) and checking that, yes, the MPU-401 _is_ in fact on the bus without any initialization having been done, at the address (300, 310, 320, 330) configured by MAB0-1. So yes, having only two jumpers for that will mean those are the only options.
With DAB2-0 (those other switches) set to 000, the Jazz itself is not on the bus, and it's getting a bit late to test, but I expect that 6 out of the remaining 7 possible value will be 210, .., 260. Will test later.
Lastly, how would you feel about setting the DOS/Windows default resource values as the preffered values and all the others as mere acceptable?
I'll leave that up to Adam Belany. Personally, I have never understood the point of having a preferred option with the default values and an acceptable one with all the possible ones. A naive PnP stack risks that the defaults take required resources away from another card while a sofisticated PnP stack will most likely overrule the defaults anyway to prevent resource starvation.
I do believe there's a point; let's pretend it's 1995 and we're sharing this card with other Non-PnP ISA cards in the machine. Through jumpers and/or the DOS setup software, we've created a conflict-free setup and are using the default values for that -- some of those old games we still enjoy playing won't even allow anything other than 220 or 240. At 210 we placed an ISA radio card.
Now linux boots, doesn't know about the radio card, and sets our Jazz to 210. Crap!
You can change the second last DMA definition to
{ .map = (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7), .flags = IORESOURCE_DMA_8AND16BIT, },
Okay.
Rene.
On Sun, Apr 01, 2007 at 02:37:59AM +0200, Rene Herman wrote:
On 03/31/2007 06:22 PM, Rask Ingemann Lambertsen wrote:
Thanks for your testing. Could you also test playback of 16-bit sounds through an 8-bit DMA channel in DOS?
This works fine. With the "8 bit DMA" set to 1 and the "16 bit DMA" to 3, 8 and 16-bit wave files play without problem.
OK, I will see if DOSemu or so has facilities to log and pass through I/O-port access.
While IRQ 15 works fine for me with an AD1816A card, I can not get IRQ 15 to work with the Jazz on the same machine. Over the weekend I'll try to use autoprobing to figure out exactly what is and isn't supported. I'll also look at circuit board traces and the ISA bus connector pinout for clues.
I got IRQ 15 to work. From looking at the traces, I could identify jumpers J10 as the "CD-ROM IRQ", with it being set to IRQ15 (with possibilities 11, 12 and 15). When I set it to something else, IRQ15 starts working both for the Jazz and the MPU-401 IRQ. That is, all of 3, 5, 7, 9, 10 and 15 now work for both IRQs for me.
I looked at my board, and IRQ 15 is definitely connected to the Jazz16 chip. On to the probing with probe_irq_on() and probe_irq_mask(). If I turn off the secondary IDE port of the legacy-mode PIIX chip, I get
jazz16pnp: irq_config 0 -> irq_mask 000000. jazz16pnp: irq_config 1 -> irq_mask 000040 (bit 5 set). jazz16pnp: irq_config 2 -> irq_mask 001000 (bit 9 set). jazz16pnp: irq_config 3 -> irq_mask 000010 (bit 3 set). jazz16pnp: irq_config 4 -> irq_mask 000200 (bit 7 set). jazz16pnp: irq_config 5 -> irq_mask 002000 (bit 10 set). jazz16pnp: irq_config 6 -> irq_mask 000000. jazz16pnp: irq_config 7 -> irq_mask 000000.
Setting irq_config 8-15 works just like irq_config 0-7. It only gets weirder with the secondary IDE port enabled:
jazz16pnp: irq_config 0 -> irq_mask 0000000. jazz16pnp: irq_config 1 -> irq_mask 0000040 (bit 5 set). jazz16pnp: irq_config 2 -> irq_mask 0001000 (bit 9 set). jazz16pnp: irq_config 3 -> irq_mask 0000010 (bit 3 set). jazz16pnp: irq_config 4 -> irq_mask 0000200 (bit 7 set). jazz16pnp: irq_config 5 -> irq_mask 0002000 (bit 10 set). jazz16pnp: irq_config 6 -> irq_mask 0100000 (bit 15 set). jazz16pnp: irq_config 7 -> irq_mask 0000000.
Here IRQ 15 does work. I don't know what is going on.
Lastly, how would you feel about setting the DOS/Windows default resource values as the preffered values and all the others as mere acceptable?
I've decided to go with this, with the exception that I'll ask for just a 16-bit channel since there is currently little use for the 8-bit one.
On Wed, Mar 28, 2007 at 10:03:30PM +0200, Rask Ingemann Lambertsen wrote:
# echo 'set irq 10 dma 5 dma 1' > /sys/bus/pnp/devices/03:01/resources # modprobe snd-jazz16 $ cat /proc/asound/cards 0 [CMI8738 ]: CMI8738 - C-Media PCI CMI8738 C-Media PCI CMI8738 (model 37) at 0xd800, irq 9 1 [Jazz16 ]: Jazz16 - Media Vision Jazz16 Sound Blaster Pro (Jazz16) at 0x220, irq 10, dma8 5, dma16 1
Notice the dma16 = 1 setting.
[Trying to play 16-bit sound through an 8-bit DMA channel]
$ aplay -v -D hw:Jazz16,0 /tmp/male.wav Playing WAVE '/tmp/male.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono Hardware PCM card 1 'Media Vision Jazz16' device 0 subdevice 0 Its setup is: stream : PLAYBACK access : RW_INTERLEAVED format : S16_LE subformat : STD channels : 1 rate : 8000 exact rate : 8000 (1000000/125) msbits : 16 buffer_size : 4000 period_size : 1000 period_time : 125000 tick_time : 4000 tstamp_mode : NONE period_step : 1 sleep_min : 0 avail_min : 1000 xfer_align : 1000 start_threshold : 4000 stop_threshold : 4000 silence_threshold: 0 silence_size : 0 boundary : 2097152000 aplay: pcm_write:1257: write error: Ind/ud-fejl
No sound, no interrupts and this message from /var/log/kernel: kernel: playback write error (DMA or IRQ trouble?)
The root cause is that snd_sbdsp_create() only supports dma16 set to 5, 6 or 7. Any other value is changed to -1, which is what happens in this case. It is a hack to avoid trouble with recent SoundBlaster 16 cards (Vibra16VX) using two 8-bit DMA channels, which the SB16 doesn't support.
Fix: Use only dma8.
On 04/11/2007 10:00 PM, Rask Ingemann Lambertsen wrote:
The root cause is that snd_sbdsp_create() only supports dma16 set to 5, 6 or 7. Any other value is changed to -1, which is what happens in this case. It is a hack to avoid trouble with recent SoundBlaster 16 cards (Vibra16VX)
Well, let's call them "relatively" recent... :-)
using two 8-bit DMA channels, which the SB16 doesn't support.
Fix: Use only dma8.
Is it perhaps possible to cheese around it using
"if (hardware == SB_HW_JAZZ16)"
type constructs (and maybe some "if (dma > 3)" elsewhere if needed)? If this would be a small change, maybe's it's worth it. And maybe not.
I'm at the moment playing with a few different cards due to them having a mitsumi CD-ROM controller and me just having dug up a mitsumi CD-ROM but I'll wait for a next complete iteration of the jazz16 patch and then give it a once-over and some testing again (feel free to ask for specifc tests as well).
Then after that you/we should seriously start poking Belay...
Rene.
participants (3)
-
Rask Ingemann Lambertsen
-
Rene Herman
-
Takashi Iwai