diff options
57 files changed, 2454 insertions, 2695 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index fd9a2f67edf..50a59860cee 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1454,6 +1454,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for internal PC-Speaker. + nopcm - Disable PC-Speaker PCM sound. Only beeps remain. nforce_wa - enable NForce chipset workaround. Expect bad sound. This module supports system beeps, some kind of PCM playback and @@ -1631,7 +1632,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-sscape ----------------- - Module for ENSONIQ SoundScape PnP cards. + Module for ENSONIQ SoundScape cards. port - Port # (PnP setup) wss_port - WSS Port # (PnP setup) @@ -1639,10 +1640,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. mpu_irq - MPU-401 IRQ # (PnP setup) dma - DMA # (PnP setup) dma2 - 2nd DMA # (PnP setup, -1 to disable) + joystick - Enable gameport - 0 = disable (default), 1 = enable + + This module supports multiple cards. - This module supports multiple cards. ISA PnP must be enabled. - You need sscape_ctl tool in alsa-tools package for loading - the microcode. + The driver requires the firmware loader support on kernel. Module snd-sun-amd7930 (on sparc only) -------------------------------------- diff --git a/arch/sh/boards/mach-hp6xx/setup.c b/arch/sh/boards/mach-hp6xx/setup.c index 8f305b36358..e6dd5e96321 100644 --- a/arch/sh/boards/mach-hp6xx/setup.c +++ b/arch/sh/boards/mach-hp6xx/setup.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/irq.h> +#include <sound/sh_dac_audio.h> #include <asm/hd64461.h> #include <asm/io.h> #include <mach/hp6xx.h> @@ -51,9 +52,63 @@ static struct platform_device jornadakbd_device = { .id = -1, }; +static void dac_audio_start(struct dac_audio_pdata *pdata) +{ + u16 v; + u8 v8; + + /* HP Jornada 680/690 speaker on */ + v = inw(HD64461_GPADR); + v &= ~HD64461_GPADR_SPEAKER; + outw(v, HD64461_GPADR); + + /* HP Palmtop 620lx/660lx speaker on */ + v8 = inb(PKDR); + v8 &= ~PKDR_SPEAKER; + outb(v8, PKDR); + + sh_dac_enable(pdata->channel); +} + +static void dac_audio_stop(struct dac_audio_pdata *pdata) +{ + u16 v; + u8 v8; + + /* HP Jornada 680/690 speaker off */ + v = inw(HD64461_GPADR); + v |= HD64461_GPADR_SPEAKER; + outw(v, HD64461_GPADR); + + /* HP Palmtop 620lx/660lx speaker off */ + v8 = inb(PKDR); + v8 |= PKDR_SPEAKER; + outb(v8, PKDR); + + sh_dac_output(0, pdata->channel); + sh_dac_disable(pdata->channel); +} + +static struct dac_audio_pdata dac_audio_platform_data = { + .buffer_size = 64000, + .channel = 1, + .start = dac_audio_start, + .stop = dac_audio_stop, +}; + +static struct platform_device dac_audio_device = { + .name = "dac_audio", + .id = -1, + .dev = { + .platform_data = &dac_audio_platform_data, + } + +}; + static struct platform_device *hp6xx_devices[] __initdata = { &cf_ide_device, &jornadakbd_device, + &dac_audio_device, }; static void __init hp6xx_init_irq(void) diff --git a/arch/sh/include/mach-common/mach/hp6xx.h b/arch/sh/include/mach-common/mach/hp6xx.h index 0d4165a32dc..bcc301ac12f 100644 --- a/arch/sh/include/mach-common/mach/hp6xx.h +++ b/arch/sh/include/mach-common/mach/hp6xx.h @@ -29,6 +29,9 @@ #define PKDR_LED_GREEN 0x10 +/* HP Palmtop 620lx/660lx speaker on/off */ +#define PKDR_SPEAKER 0x20 + #define SCPDR_TS_SCAN_ENABLE 0x20 #define SCPDR_TS_SCAN_Y 0x02 #define SCPDR_TS_SCAN_X 0x01 @@ -42,6 +45,7 @@ #define ADC_CHANNEL_BACKUP 4 #define ADC_CHANNEL_CHARGE 5 +/* HP Jornada 680/690 speaker on/off */ #define HD64461_GPADR_SPEAKER 0x01 #define HD64461_GPADR_PCMCIA0 (0x02|0x08) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index a87a477c87f..b134553eb3b 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -195,6 +195,24 @@ config RADIO_MAESTRO To compile this driver as a module, choose M here: the module will be called radio-maestro. +config RADIO_MIROPCM20 + tristate "miroSOUND PCM20 radio" + depends on ISA && VIDEO_V4L2 + select SND_MIRO + ---help--- + Choose Y here if you have this FM radio card. You also need to enable + the ALSA sound system. This choice automatically selects the ALSA + sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this + is required for the radio-miropcm20. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-miropcm20. + config RADIO_SF16FMI tristate "SF16FMI Radio" depends on ISA && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 2a1be3bf4f7..8a63d543ae4 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o +obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ obj-$(CONFIG_USB_MR800) += radio-mr800.o diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c new file mode 100644 index 00000000000..4ff885445fd --- /dev/null +++ b/drivers/media/radio/radio-miropcm20.c @@ -0,0 +1,270 @@ +/* Miro PCM20 radio driver for Linux radio support + * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> + * Thanks to Norberto Pellici for the ACI device interface specification + * The API part is based on the radiotrack driver by M. Kirkwood + * This driver relies on the aci mixer provided by the snd-miro + * ALSA driver. + * Look there for further info... + */ + +/* What ever you think about the ACI, version 0x07 is not very well! + * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono + * conditions... Robert + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/videodev2.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <sound/aci.h> + +static int radio_nr = -1; +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); + +static int mono; +module_param(mono, bool, 0); +MODULE_PARM_DESC(mono, "Force tuner into mono mode."); + +struct pcm20 { + struct v4l2_device v4l2_dev; + struct video_device vdev; + unsigned long freq; + int muted; + struct snd_miro_aci *aci; +}; + +static struct pcm20 pcm20_card = { + .freq = 87*16000, + .muted = 1, +}; + +static int pcm20_mute(struct pcm20 *dev, unsigned char mute) +{ + dev->muted = mute; + return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1); +} + +static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo) +{ + return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1); +} + +static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) +{ + unsigned char freql; + unsigned char freqh; + struct snd_miro_aci *aci = dev->aci; + + dev->freq = freq; + + freq /= 160; + if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0)) + freq /= 10; /* I don't know exactly which version + * needs this hack */ + freql = freq & 0xff; + freqh = freq >> 8; + + pcm20_stereo(dev, !mono); + return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh); +} + +static const struct v4l2_file_operations pcm20_fops = { + .owner = THIS_MODULE, + .ioctl = video_ioctl2, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "Miro PCM20", sizeof(v->driver)); + strlcpy(v->card, "Miro PCM20", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = 0x1; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + if (v->index) /* Only 1 tuner */ + return -EINVAL; + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 87*16000; + v->rangehigh = 108*16000; + v->signal = 0xffff; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct pcm20 *dev = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + + f->type = V4L2_TUNER_RADIO; + f->frequency = dev->freq; + return 0; +} + + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct pcm20 *dev = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + dev->freq = f->frequency; + pcm20_setfreq(dev, f->frequency); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct pcm20 *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->muted; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct pcm20 *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + pcm20_mute(dev, ctrl->value); + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_ioctl_ops pcm20_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static int __init pcm20_init(void) +{ + struct pcm20 *dev = &pcm20_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; + + dev->aci = snd_aci_get_aci(); + if (dev->aci == NULL) { + v4l2_err(v4l2_dev, + "you must load the snd-miro driver first!\n"); + return -ENODEV; + } + strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name)); + + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); + return -EINVAL; + } + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &pcm20_fops; + dev->vdev.ioctl_ops = &pcm20_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) + goto fail; + + v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n"); + return 0; +fail: + v4l2_device_unregister(v4l2_dev); + return -EINVAL; +} + +MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt"); +MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); +MODULE_LICENSE("GPL"); + +static void __exit pcm20_cleanup(void) +{ + struct pcm20 *dev = &pcm20_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); +} + +module_init(pcm20_init); +module_exit(pcm20_cleanup); diff --git a/include/sound/Kbuild b/include/sound/Kbuild index fd054a34432..e9dd9369ecb 100644 --- a/include/sound/Kbuild +++ b/include/sound/Kbuild @@ -2,7 +2,6 @@ header-y += asound_fm.h header-y += hdsp.h header-y += hdspm.h header-y += sfnt_info.h -header-y += sscape_ioctl.h unifdef-y += asequencer.h unifdef-y += asound.h diff --git a/sound/isa/opti9xx/miro.h b/include/sound/aci.h index 6e1385b8e07..ee639d355ef 100644 --- a/sound/isa/opti9xx/miro.h +++ b/include/sound/aci.h @@ -1,5 +1,5 @@ -#ifndef _MIRO_H_ -#define _MIRO_H_ +#ifndef _ACI_H_ +#define _ACI_H_ #define ACI_REG_COMMAND 0 /* write register offset */ #define ACI_REG_STATUS 1 /* read register offset */ @@ -70,4 +70,21 @@ #define ACI_SET_EQ6 0x45 #define ACI_SET_EQ7 0x46 /* ... to Treble */ -#endif /* _MIRO_H_ */ +struct snd_miro_aci { + unsigned long aci_port; + int aci_vendor; + int aci_product; + int aci_version; + int aci_amp; + int aci_preamp; + int aci_solomode; + + struct mutex aci_mutex; +}; + +int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3); + +struct snd_miro_aci *snd_aci_get_aci(void); + +#endif /* _ACI_H_ */ + diff --git a/include/sound/cs4231-regs.h b/include/sound/cs4231-regs.h index 92647532c45..66d28c2cb53 100644 --- a/include/sound/cs4231-regs.h +++ b/include/sound/cs4231-regs.h @@ -70,7 +70,6 @@ #define AD1845_PWR_DOWN 0x1b /* power down control */ #define CS4235_LEFT_MASTER 0x1b /* left master output control */ #define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */ -#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */ #define AD1845_CLOCK 0x1d /* crystal clock select and total power down */ #define CS4235_RIGHT_MASTER 0x1d /* right master output control */ #define CS4231_REC_UPR_CNT 0x1e /* record upper count */ diff --git a/include/sound/sh_dac_audio.h b/include/sound/sh_dac_audio.h new file mode 100644 index 00000000000..f5deaf1ddb9 --- /dev/null +++ b/include/sound/sh_dac_audio.h @@ -0,0 +1,21 @@ +/* + * SH_DAC specific configuration, for the dac_audio platform_device + * + * Copyright (C) 2009 Rafael Ignacio Zurita <rizurita@yahoo.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef __INCLUDE_SH_DAC_AUDIO_H +#define __INCLUDE_SH_DAC_AUDIO_H + +struct dac_audio_pdata { + int buffer_size; + int channel; + void (*start)(struct dac_audio_pdata *pd); + void (*stop)(struct dac_audio_pdata *pd); +}; + +#endif /* __INCLUDE_SH_DAC_AUDIO_H */ diff --git a/include/sound/sscape_ioctl.h b/include/sound/sscape_ioctl.h deleted file mode 100644 index 0d8885969c6..00000000000 --- a/include/sound/sscape_ioctl.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SSCAPE_IOCTL_H -#define SSCAPE_IOCTL_H - - -struct sscape_bootblock -{ - unsigned char code[256]; - unsigned version; -}; - -#define SSCAPE_MICROCODE_SIZE 65536 - -struct sscape_microcode -{ - unsigned char __user *code; -}; - -#define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock) -#define SND_SSCAPE_LOAD_MCODE _IOW ('P', 101, struct sscape_microcode) - -#endif diff --git a/include/sound/wss.h b/include/sound/wss.h index 6d65f322f1d..fd01f22825c 100644 --- a/include/sound/wss.h +++ b/include/sound/wss.h @@ -154,7 +154,6 @@ int snd_wss_create(struct snd_card *card, unsigned short hardware, unsigned short hwshare, struct snd_wss **rchip); -int snd_wss_free(struct snd_wss *chip); int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm); int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer); int snd_wss_mixer(struct snd_wss *chip); diff --git a/sound/Kconfig b/sound/Kconfig index 439e15c8faa..b3e53e616ec 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM Please read Documentation/feature-removal-schedule.txt for details. - If unusre, say Y. + If unsure, say Y. source "sound/oss/dmasound/Kconfig" diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 6c160a038b2..eb715e73210 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -18,10 +18,7 @@ #include <linux/interrupt.h> #include <linux/err.h> #include <linux/amba/bus.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/sizes.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/initval.h> @@ -538,7 +535,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream) struct aaci_runtime *aacirun = runtime->private_data; aacirun->start = (void *)runtime->dma_area; - aacirun->end = aacirun->start + runtime->dma_bytes; + aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream); aacirun->ptr = aacirun->start; aacirun->period = aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); diff --git a/sound/core/control.c b/sound/core/control.c index a8b7fabe645..b586019faf3 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1120,7 +1120,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, goto __kctl_end; } if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - if (file && vd->owner != NULL && vd->owner != file) { + if (vd->owner != NULL && vd->owner != file) { err = -EPERM; goto __kctl_end; } diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 79f0f16af33..950e19ba91f 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -85,16 +85,24 @@ EXPORT_SYMBOL(snd_dma_disable); unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) { unsigned long flags; - unsigned int result; + unsigned int result, result1; flags = claim_dma_lock(); clear_dma_ff(dma); if (!isa_dma_bridge_buggy) disable_dma(dma); result = get_dma_residue(dma); + /* + * HACK - read the counter again and choose higher value in order to + * avoid reading during counter lower byte roll over if the + * isa_dma_bridge_buggy is set. + */ + result1 = get_dma_residue(dma); if (!isa_dma_bridge_buggy) enable_dma(dma); release_dma_lock(flags); + if (unlikely(result < result1)) + result = result1; #ifdef CONFIG_SND_DEBUG if (result > size) snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size); diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index b60cef257b5..f165c77d627 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -26,6 +26,7 @@ MODULE_ALIAS("platform:pcspkr"); static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */ +static int nopcm; /* Disable PCM capability of the driver */ module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for pcsp soundcard."); @@ -33,6 +34,8 @@ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for pcsp soundcard."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable PC-Speaker sound."); +module_param(nopcm, bool, 0444); +MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain."); struct snd_pcsp pcsp_chip; @@ -43,13 +46,16 @@ static int __devinit snd_pcsp_create(struct snd_card *card) int err; int div, min_div, order; - hrtimer_get_res(CLOCK_MONOTONIC, &tp); - if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { - printk(KERN_ERR "PCSP: Timer resolution is not sufficient " - "(%linS)\n", tp.tv_nsec); - printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " - "enabled.\n"); - return -EIO; + if (!nopcm) { + hrtimer_get_res(CLOCK_MONOTONIC, &tp); + if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { + printk(KERN_ERR "PCSP: Timer resolution is not sufficient " + "(%linS)\n", tp.tv_nsec); + printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " + "enabled.\n"); + printk(KERN_ERR "PCSP: Turned into nopcm mode.\n"); + nopcm = 1; + } } if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS) @@ -107,12 +113,14 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) snd_card_free(card); return err; } - err = snd_pcsp_new_pcm(&pcsp_chip); - if (err < 0) { - snd_card_free(card); - return err; + if (!nopcm) { + err = snd_pcsp_new_pcm(&pcsp_chip); + if (err < 0) { + snd_card_free(card); + return err; + } } - err = snd_pcsp_new_mixer(&pcsp_chip); + err = snd_pcsp_new_mixer(&pcsp_chip, nopcm); if (err < 0) { snd_card_free(card); return err; diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index 174dd2ff0f2..1e123077923 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -83,6 +83,6 @@ extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); extern void pcsp_sync_stop(struct snd_pcsp *chip); extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); -extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); +extern int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm); #endif diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index 903bc846763..02e05552632 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -119,24 +119,43 @@ static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol, .put = pcsp_##ctl_type##_put, \ } -static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = { +static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = { PCSP_MIXER_CONTROL(enable, "Master Playback Switch"), PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"), +}; + +static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = { PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"), }; -int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip) +static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, + struct snd_kcontrol_new *ctls, int num) { - struct snd_card *card = chip->card; int i, err; + struct snd_card *card = chip->card; + for (i = 0; i < num; i++) { + err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip)); + if (err < 0) + return err; + } + return 0; +} + +int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) +{ + int err; + struct snd_card *card = chip->card; - for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(snd_pcsp_controls + i, - chip)); + if (!nopcm) { + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm, + ARRAY_SIZE(snd_pcsp_controls_pcm)); if (err < 0) return err; } + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr, + ARRAY_SIZE(snd_pcsp_controls_spkr)); + if (err < 0) + return err; strcpy(card->mixername, "PC-Speaker"); diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 020a5d51247..04ae8704cdc 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/bitrev.h> #include <asm/unaligned.h> #include <sound/core.h> #include <sound/control.h> @@ -55,18 +56,6 @@ struct cs8427 { struct cs8427_stream capture; }; -static unsigned char swapbits(unsigned char val) -{ - int bit; - unsigned char res = 0; - for (bit = 0; bit < 8; bit++) { - res <<= 1; - res |= val & 1; - val >>= 1; - } - return res; -} - int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg, unsigned char val) { @@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, } data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; for (idx = 0; idx < count; idx++) - data[idx + 1] = swapbits(ndata[idx]); + data[idx + 1] = bitrev8(ndata[idx]); if (snd_i2c_sendbytes(device, data, count + 1) != count + 1) return -EIO; return 1; diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 51a7e3777e1..02fe81ca88f 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -372,15 +372,21 @@ config SND_SGALAXY config SND_SSCAPE tristate "Ensoniq SoundScape driver" - select SND_HWDEP select SND_MPU401_UART select SND_WSS_LIB + select FW_LOADER help Say Y here to include support for Ensoniq SoundScape - soundcards. + and Ensoniq OEM soundcards. The PCM audio is supported on SoundScape Classic, Elite, PnP - and VIVO cards. The MIDI support is very experimental. + and VIVO cards. The supported OEM cards are SPEA Media FX and + Reveal SC-600. + The MIDI support is very experimental and requires binary + firmware files called "scope.cod" and "sndscape.co?" where the + ? is digit 0, 1, 2, 3 or 4. The firmware files can be found + in DOS or Windows driver packages. One has to put the firmware + files into the /lib/firmware directory. To compile this driver as a module, choose M here: the module will be called snd-sscape. diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index a076a6ce807..93fa6720d19 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) return -EBUSY; } - err = snd_wss_create(card, port[dev], cport[dev], + err = snd_cs4236_create(card, port[dev], cport[dev], irq[dev], dma1[dev], dma2[dev], WSS_HW_DETECT3, 0, &chip); if (err < 0) return err; + + acard->chip = chip; if (chip->hardware & WSS_HW_CS4236B_MASK) { - snd_wss_free(chip); - err = snd_cs4236_create(card, - port[dev], cport[dev], - irq[dev], dma1[dev], dma2[dev], - WSS_HW_DETECT, 0, &chip); - if (err < 0) - return err; - acard->chip = chip; err = snd_cs4236_pcm(chip, 0, &pcm); if (err < 0) @@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } else { - acard->chip = chip; err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) return err; diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 38835f31298..c5adca30063 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -87,6 +87,8 @@ #include <sound/core.h> #include <sound/wss.h> #include <sound/asoundef.h> +#include <sound/initval.h> +#include <sound/tlv.h> /* * @@ -264,7 +266,10 @@ static void snd_cs4236_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ - +/* + * This function does no fail if the chip is not CS4236B or compatible. + * It just an equivalent to the snd_wss_create() then. + */ int snd_cs4236_create(struct snd_card *card, unsigned long port, unsigned long cport, @@ -281,21 +286,17 @@ int snd_cs4236_create(struct snd_card *card, *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3; - if (cport < 0x100) { - snd_printk(KERN_ERR "please, specify control port " - "for CS4236+ chips\n"); - return -ENODEV; - } + err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err; - if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { - snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers " - "not available, hardware=0x%x\n", chip->hardware); - snd_device_free(card, chip); - return -ENODEV; + if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) { + snd_printd("chip is not CS4236+, hardware=0x%x\n", + chip->hardware); + *rchip = chip; + return 0; } #if 0 { @@ -308,9 +309,16 @@ int snd_cs4236_create(struct snd_card *card, idx, snd_cs4236_ctrl_in(chip, idx)); } #endif + if (cport < 0x100 || cport == SNDRV_AUTO_PORT) { + snd_printk(KERN_ERR "please, specify control port " + "for CS4236+ chips\n"); + snd_device_free(card, chip); + return -ENODEV; + } ver1 = snd_cs4236_ctrl_in(chip, 1); ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); - snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); + snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", + cport, ver1, ver2); if (ver1 != ver2) { snd_printk(KERN_ERR "CS4236+ chip detected, but " "control port 0x%lx is not valid\n", cport); @@ -321,13 +329,17 @@ int snd_cs4236_create(struct snd_card *card, snd_cs4236_ctrl_out(chip, 2, 0xff); snd_cs4236_ctrl_out(chip, 3, 0x00); snd_cs4236_ctrl_out(chip, 4, 0x80); - snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE); + reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | + IEC958_AES0_CON_EMPHASIS_NONE; + snd_cs4236_ctrl_out(chip, 5, reg); snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); snd_cs4236_ctrl_out(chip, 7, 0x00); - /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */ - /* is working with this setup, other hardware should have */ - /* different signal paths and this value should be selectable */ - /* in the future */ + /* + * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 + * output is working with this setup, other hardware should + * have different signal paths and this value should be + * selectable in the future + */ snd_cs4236_ctrl_out(chip, 8, 0x8c); chip->rate_constraint = snd_cs4236_xrate; chip->set_playback_format = snd_cs4236_playback_format; @@ -339,9 +351,10 @@ int snd_cs4236_create(struct snd_card *card, /* initialize extended registers */ for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) - snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); + snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), + snd_cs4236_ext_map[reg]); - /* initialize compatible but more featured registers */ + /* initialize compatible but more featured registers */ snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); @@ -387,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } +#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_single, \ + .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 16) & 0xff; @@ -490,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 24) & 0xff; @@ -560,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); @@ -619,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -#define CS4236_MASTER_DIGITAL(xname, xindex) \ +#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \ - .private_value = 71 << 24 } + .private_value = 71 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) { return (vol < 64) ? 63 - vol : 64 + (71 - vol); -} +} static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -661,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s return change; } -#define CS4235_OUTPUT_ACCU(xname, xindex) \ +#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \ - .private_value = 3 << 24 } + .private_value = 3 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4235_mixer_output_accu_get_volume(int vol) { @@ -720,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ return change; } +static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); + static struct snd_kcontrol_new snd_cs4236_controls[] = { CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), +CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit), -CS4236_DOUBLE("Capture Boost Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Boost Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), -CS4236_DOUBLE("DSP Playback Volume", 0, - CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("DSP Playback Volume", 0, + CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("FM Playback Volume", 0, - CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("FM Playback Volume", 0, + CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Playback Volume", 0, - CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1, + db_scale_6bit_12db_max), WSS_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Synth Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), WSS_DOUBLE("Synth Capture Bypass", 0, @@ -764,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), -CS4236_DOUBLE("Mic Playback Boost", 0, +CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, + 0, 0, 31, 1, db_scale_5bit_22db_max), +CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Line Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), WSS_DOUBLE("Line Capture Bypass", 0, @@ -779,57 +842,63 @@ WSS_DOUBLE("Line Capture Bypass", 0, WSS_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("CD Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("CD Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), -CS4236_DOUBLE1("Mono Playback Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), +WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, + 0, 0, 15, 0, db_scale_rec_gain), WSS_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), -WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, - CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) +WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0, + CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1, + db_scale_6bit), }; +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0); + static struct snd_kcontrol_new snd_cs4235_controls[] = { -WSS_DOUBLE("Master Switch", 0, +WSS_DOUBLE("Master Playback Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -WSS_DOUBLE("Master Volume", 0, - CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), - -CS4235_OUTPUT_ACCU("Playback Volume", 0), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1, + db_scale_5bit_6db_max), -CS4236_DOUBLE("Master Digital Playback Switch", 0, - CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, - CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), +CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max), -WSS_DOUBLE("Master Digital Playback Switch", 1, +WSS_DOUBLE("Synth Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Master Digital Capture Switch", 1, +WSS_DOUBLE("Synth Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -WSS_DOUBLE("Master Digital Volume", 1, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), -CS4236_DOUBLE("Capture Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), -WSS_DOUBLE("PCM Switch", 0, +WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("PCM Capture Switch", 0, + CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), +WSS_DOUBLE_TLV("PCM Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), @@ -842,29 +911,29 @@ CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), -CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), -CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0), +CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1, + db_scale_5bit_22db_max), +CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), -WSS_DOUBLE("Aux Playback Switch", 0, +WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 0, +WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), -WSS_DOUBLE("Aux Playback Switch", 1, +WSS_DOUBLE("CD Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 1, +WSS_DOUBLE("CD Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), - -CS4236_DOUBLE1("Master Mono Switch", 0, - CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), +WSS_DOUBLE_TLV("CD Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), -CS4236_DOUBLE1("Mono Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), WSS_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 8cfbff73a83..06e871e66c9 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -102,8 +102,6 @@ struct snd_es18xx { unsigned long port; /* port of ESS chip */ - unsigned long mpu_port; /* MPU-401 port of ESS chip */ - unsigned long fm_port; /* FM port */ unsigned long ctrl_port; /* Control port of ESS chip */ struct resource *res_port; struct resource *res_mpu_port; @@ -116,12 +114,9 @@ struct snd_es18xx { unsigned short audio2_vol; /* volume level of audio2 */ unsigned short active; /* active channel mask */ - unsigned int dma1_size; - unsigned int dma2_size; unsigned int dma1_shift; unsigned int dma2_shift; - struct snd_card *card; struct snd_pcm *pcm; struct snd_pcm_substream *playback_a_substream; struct snd_pcm_substream *capture_a_substream; @@ -136,14 +131,9 @@ struct snd_es18xx { spinlock_t reg_lock; spinlock_t mixer_lock; - spinlock_t ctrl_lock; #ifdef CONFIG_PM unsigned char pm_reg; #endif -}; - -struct snd_audiodrive { - struct snd_es18xx *chip; #ifdef CONFIG_PNP struct pnp_dev *dev; struct pnp_dev *devc; @@ -359,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch } -static int snd_es18xx_reset(struct snd_es18xx *chip) +static int __devinit snd_es18xx_reset(struct snd_es18xx *chip) { int i; outb(0x03, chip->port + 0x06); @@ -495,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma2_size = size; - snd_es18xx_rate_set(chip, substream, DAC2); /* Transfer Count Reload */ @@ -596,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream) unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -664,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -755,7 +739,8 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream, static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) { - struct snd_es18xx *chip = dev_id; + struct snd_card *card = dev_id; + struct snd_es18xx *chip = card->private_data; unsigned char status; if (chip->caps & ES18XX_CONTROL) { @@ -805,12 +790,16 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) int split = 0; if (chip->caps & ES18XX_HWV) { split = snd_es18xx_mixer_read(chip, 0x64) & 0x80; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hw_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hw_volume->id); } if (!split) { - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); } /* ack interrupt */ snd_es18xx_mixer_write(chip, 0x66, 0x00); @@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) { if (!(chip->active & DAC2)) return 0; - pos = snd_dma_pointer(chip->dma2, chip->dma2_size); + pos = snd_dma_pointer(chip->dma2, size); return pos >> chip->dma2_shift; } else { if (!(chip->active & DAC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } } @@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (!(chip->active & ADC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } @@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream) static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts4Source[4] = { - "Mic", "CD", "Line", "Master" - }; static char *texts5Source[5] = { "Mic", "CD", "Line", "Master", "Mix" }; @@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]); + strcpy(uinfo->value.enumerated.name, + texts5Source[uinfo->value.enumerated.item]); break; case 0x1887: case 0x1888: @@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { int data; - unsigned long flags; - spin_lock_irqsave(&chip->ctrl_lock, flags); + outb(reg, chip->ctrl_port); data = inb(chip->ctrl_port + 1); - spin_unlock_irqrestore(&chip->ctrl_lock, flags); return data; } @@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, #endif } -static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) +static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { int mask = 0; @@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) if (chip->caps & ES18XX_CONTROL) { /* Hardware volume IRQ */ snd_es18xx_config_write(chip, 0x27, chip->irq); - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { /* FM I/O */ - snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8); - snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff); + snd_es18xx_config_write(chip, 0x62, fm_port >> 8); + snd_es18xx_config_write(chip, 0x63, fm_port & 0xff); } - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU-401 I/O */ - snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8); - snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff); + snd_es18xx_config_write(chip, 0x64, mpu_port >> 8); + snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff); /* MPU-401 IRQ */ snd_es18xx_config_write(chip, 0x28, chip->irq); } @@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) snd_es18xx_mixer_write(chip, 0x7A, 0x68); /* Enable and set hardware volume interrupt */ snd_es18xx_mixer_write(chip, 0x64, 0x06); - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU401 share irq with audio Joystick enabled FM enabled */ - snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1); + snd_es18xx_mixer_write(chip, 0x40, + 0x43 | (mpu_port & 0xf0) >> 1); } snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01); } @@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip) return 0; } -static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) +static int __devinit snd_es18xx_probe(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { if (snd_es18xx_identify(chip) < 0) { snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port); @@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV; break; case 0x1887: - chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; - break; case 0x1888: chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; break; @@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) if (chip->dma1 == chip->dma2) chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME); - return snd_es18xx_initialize(chip); + return snd_es18xx_initialize(chip, mpu_port, fm_port); } static struct snd_pcm_ops snd_es18xx_playback_ops = { @@ -1691,8 +1681,10 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { .pointer = snd_es18xx_capture_pointer, }; -static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm) +static int __devinit snd_es18xx_pcm(struct snd_card *card, int device, + struct snd_pcm **rpcm) { + struct snd_es18xx *chip = card->private_data; struct snd_pcm *pcm; char str[16]; int err; @@ -1701,9 +1693,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct *rpcm = NULL; sprintf(str, "ES%x", chip->version); if (chip->caps & ES18XX_PCM2) - err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm); + err = snd_pcm_new(card, str, device, 2, 1, &pcm); else - err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm); + err = snd_pcm_new(card, str, device, 1, 1, &pcm); if (err < 0) return err; @@ -1734,10 +1726,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct #ifdef CONFIG_PM static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); @@ -1752,24 +1743,25 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) static int snd_es18xx_resume(struct snd_card *card) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; /* restore PM register, we won't wake till (not 0x07) i/o activity though */ snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM); - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* CONFIG_PM */ -static int snd_es18xx_free(struct snd_es18xx *chip) +static int snd_es18xx_free(struct snd_card *card) { + struct snd_es18xx *chip = card->private_data; + release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_ctrl_port); release_and_free_resource(chip->res_mpu_port); if (chip->irq >= 0) - free_irq(chip->irq, (void *) chip); + free_irq(chip->irq, (void *) card); if (chip->dma1 >= 0) { disable_dma(chip->dma1); free_dma(chip->dma1); @@ -1778,93 +1770,82 @@ static int snd_es18xx_free(struct snd_es18xx *chip) disable_dma(chip->dma2); free_dma(chip->dma2); } - kfree(chip); return 0; } static int snd_es18xx_dev_free(struct snd_device *device) { - struct snd_es18xx *chip = device->device_data; - return snd_es18xx_free(chip); + return snd_es18xx_free(device->card); } static int __devinit snd_es18xx_new_device(struct snd_card *card, unsigned long port, unsigned long mpu_port, unsigned long fm_port, - int irq, int dma1, int dma2, - struct snd_es18xx ** rchip) + int irq, int dma1, int dma2) { - struct snd_es18xx *chip; + struct snd_es18xx *chip = card->private_data; static struct snd_device_ops ops = { .dev_free = snd_es18xx_dev_free, }; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); - spin_lock_init(&chip->ctrl_lock); - chip->card = card; chip->port = port; - chip->mpu_port = mpu_port; - chip->fm_port = fm_port; chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; chip->audio2_vol = 0x00; chip->active = 0; - if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) { - snd_es18xx_free(chip); + chip->res_port = request_region(port, 16, "ES18xx"); + if (chip->res_port == NULL) { + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); return -EBUSY; } - if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) chip)) { - snd_es18xx_free(chip); + if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", + (void *) card)) { + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq); return -EBUSY; } chip->irq = irq; if (request_dma(dma1, "ES18xx DMA 1")) { - snd_es18xx_free(chip); + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1); return -EBUSY; } chip->dma1 = dma1; if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) { - snd_es18xx_free(chip); + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2); return -EBUSY; } chip->dma2 = dma2; - if (snd_es18xx_probe(chip) < 0) { - snd_es18xx_free(chip); - return -ENODEV; - } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_es18xx_free(chip); + if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) { + snd_es18xx_free(card); + return -ENODEV; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_es18xx_free(card); return err; } - *rchip = chip; return 0; } -static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip) +static int __devinit snd_es18xx_mixer(struct snd_card *card) { - struct snd_card *card; + struct snd_es18xx *chip = card->private_data; int err; unsigned int idx; - card = chip->card; - strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) { @@ -1986,7 +1967,7 @@ 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_ISAPNP; /* Enable this card */ #ifdef CONFIG_PNP -static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; +static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; #endif static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ #ifndef CONFIG_PNP @@ -2063,11 +2044,11 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) return 0; } -static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, +static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip, struct pnp_dev *pdev) { - acard->dev = pdev; - if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) + chip->dev = pdev; + if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) return -EBUSY; return 0; } @@ -2093,26 +2074,26 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); -static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, +static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip, struct pnp_card_link *card, const struct pnp_card_device_id *id) { - acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); - if (acard->dev == NULL) + chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL); + if (chip->dev == NULL) return -EBUSY; - acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL); - if (acard->devc == NULL) + chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL); + if (chip->devc == NULL) return -EBUSY; /* Control port initialization */ - if (pnp_activate_dev(acard->devc) < 0) { + if (pnp_activate_dev(chip->devc) < 0) { snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); return -EAGAIN; } snd_printdd("pnp: port=0x%llx\n", - (unsigned long long)pnp_port_start(acard->devc, 0)); - if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) + (unsigned long long)pnp_port_start(chip->devc, 0)); + if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) return -EBUSY; return 0; @@ -2128,24 +2109,20 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, static int snd_es18xx_card_new(int dev, struct snd_card **cardp) { return snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct snd_audiodrive), cardp); + sizeof(struct snd_es18xx), cardp); } static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip; + struct snd_es18xx *chip = card->private_data; struct snd_opl3 *opl3; int err; - if ((err = snd_es18xx_new_device(card, - port[dev], - mpu_port[dev], - fm_port[dev], - irq[dev], dma1[dev], dma2[dev], - &chip)) < 0) + err = snd_es18xx_new_device(card, + port[dev], mpu_port[dev], fm_port[dev], + irq[dev], dma1[dev], dma2[dev]); + if (err < 0) return err; - acard->chip = chip; sprintf(card->driver, "ES%x", chip->version); @@ -2161,26 +2138,32 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) chip->port, irq[dev], dma1[dev]); - if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0) + err = snd_es18xx_pcm(card, 0, NULL); + if (err < 0) return err; - if ((err = snd_es18xx_mixer(chip)) < 0) + err = snd_es18xx_mixer(card); + if (err < 0) return err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { - if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port); + if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, + OPL3_HW_OPL3, 0, &opl3) < 0) { + snd_printk(KERN_WARNING PFX + "opl3 not detected at 0x%lx\n", + fm_port[dev]); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) return err; } } if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, - chip->mpu_port, 0, - irq[dev], 0, - &chip->rmidi)) < 0) + err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, + mpu_port[dev], 0, + irq[dev], 0, &chip->rmidi); + if (err < 0) return err; } diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 02e30d7c6a9..6123c753111 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/isa.h> +#include <linux/pnp.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/ioport.h> @@ -40,7 +41,7 @@ #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include <sound/initval.h> -#include "miro.h" +#include <sound/aci.h> MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>"); MODULE_LICENSE("GPL"); @@ -60,6 +61,9 @@ static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int wss; static int ide; +#ifdef CONFIG_PNP +static int isapnp = 1; /* Enable ISA PnP detection */ +#endif module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for miro soundcard."); @@ -83,6 +87,10 @@ module_param(wss, int, 0444); MODULE_PARM_DESC(wss, "wss mode"); module_param(ide, int, 0444); MODULE_PARM_DESC(ide, "enable ide port"); +#ifdef CONFIG_PNP +module_param(isapnp, bool, 0444); +MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); +#endif #define OPTi9XX_HW_DETECT 0 #define OPTi9XX_HW_82C928 1 @@ -96,7 +104,6 @@ MODULE_PARM_DESC(ide, "enable ide port"); #define OPTi9XX_MC_REG(n) n - struct snd_miro { unsigned short hardware; unsigned char password; @@ -110,7 +117,6 @@ struct snd_miro { unsigned long pwd_reg; spinlock_t lock; - struct snd_card *card; struct snd_pcm *pcm; long wss_base; @@ -118,23 +124,13 @@ struct snd_miro { int dma1; int dma2; - long fm_port; - long mpu_port; int mpu_irq; - unsigned long aci_port; - int aci_vendor; - int aci_product; - int aci_version; - int aci_amp; - int aci_preamp; - int aci_solomode; - - struct mutex aci_mutex; + struct snd_miro_aci *aci; }; -static void snd_miro_proc_init(struct snd_miro * miro); +static struct snd_miro_aci aci_device; static char * snd_opti9xx_names[] = { "unkown", @@ -143,17 +139,33 @@ static char * snd_opti9xx_names[] = { "82C930", "82C931", "82C933" }; +static int snd_miro_pnp_is_probed; + +#ifdef CONFIG_PNP + +static struct pnp_card_device_id snd_miro_pnpids[] = { + /* PCM20 and PCM12 in PnP mode */ + { .id = "MIR0924", + .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, }, + { .id = "" } +}; + +MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids); + +#endif /* CONFIG_PNP */ + /* * ACI control */ -static int aci_busy_wait(struct snd_miro * miro) +static int aci_busy_wait(struct snd_miro_aci *aci) { long timeout; unsigned char byte; - for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) { - if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) { + for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) { + byte = inb(aci->aci_port + ACI_REG_BUSY); + if ((byte & 1) == 0) { if (timeout >= ACI_MINTIME) snd_printd("aci ready in round %ld.\n", timeout-ACI_MINTIME); @@ -179,10 +191,10 @@ static int aci_busy_wait(struct snd_miro * miro) return -EBUSY; } -static inline int aci_write(struct snd_miro * miro, unsigned char byte) +static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte) { - if (aci_busy_wait(miro) >= 0) { - outb(byte, miro->aci_port + ACI_REG_COMMAND); + if (aci_busy_wait(aci) >= 0) { + outb(byte, aci->aci_port + ACI_REG_COMMAND); return 0; } else { snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte); @@ -190,12 +202,12 @@ static inline int aci_write(struct snd_miro * miro, unsigned char byte) } } -static inline int aci_read(struct snd_miro * miro) +static inline int aci_read(struct snd_miro_aci *aci) { unsigned char byte; - if (aci_busy_wait(miro) >= 0) { - byte=inb(miro->aci_port + ACI_REG_STATUS); + if (aci_busy_wait(aci) >= 0) { + byte = inb(aci->aci_port + ACI_REG_STATUS); return byte; } else { snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n"); @@ -203,39 +215,49 @@ static inline int aci_read(struct snd_miro * miro) } } -static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3) +int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3) { int write[] = {write1, write2, write3}; int value, i; - if (mutex_lock_interruptible(&miro->aci_mutex)) + if (mutex_lock_interruptible(&aci->aci_mutex)) return -EINTR; for (i=0; i<3; i++) { if (write[i]< 0 || write[i] > 255) break; else { - value = aci_write(miro, write[i]); + value = aci_write(aci, write[i]); if (value < 0) goto out; } } - value = aci_read(miro); + value = aci_read(aci); -out: mutex_unlock(&miro->aci_mutex); +out: mutex_unlock(&aci->aci_mutex); return value; } +EXPORT_SYMBOL(snd_aci_cmd); + +static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index) +{ + return snd_aci_cmd(aci, ACI_STATUS, index, -1); +} -static int aci_getvalue(struct snd_miro * miro, unsigned char index) +static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index, + int value) { - return aci_cmd(miro, ACI_STATUS, index, -1); + return snd_aci_cmd(aci, index, value, -1); } -static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value) +struct snd_miro_aci *snd_aci_get_aci(void) { - return aci_cmd(miro, index, value, -1); + if (aci_device.aci_port == 0) + return NULL; + return &aci_device; } +EXPORT_SYMBOL(snd_aci_get_aci); /* * MIXER part @@ -249,8 +271,10 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_S_GENERAL); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", + value); return value; } @@ -267,13 +291,15 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol, value = !(ucontrol->value.integer.value[0]); - if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", + error); return error; } - change = (value != miro->aci_solomode); - miro->aci_solomode = value; + change = (value != miro->aci->aci_solomode); + miro->aci->aci_solomode = value; return change; } @@ -295,7 +321,7 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if (miro->aci_version <= 176) { + if (miro->aci->aci_version <= 176) { /* OSS says it's not readable with versions < 176. @@ -303,12 +329,14 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, which is a PCM12 with aci_version = 176. */ - ucontrol->value.integer.value[0] = miro->aci_preamp; + ucontrol->value.integer.value[0] = miro->aci->aci_preamp; return 0; } - if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_GET_PREAMP); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", + value); return value; } @@ -325,13 +353,15 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", + error); return error; } - change = (value != miro->aci_preamp); - miro->aci_preamp = value; + change = (value != miro->aci->aci_preamp); + miro->aci->aci_preamp = value; return change; } @@ -342,7 +372,7 @@ static int snd_miro_get_amp(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = miro->aci_amp; + ucontrol->value.integer.value[0] = miro->aci->aci_amp; return 0; } @@ -355,13 +385,14 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) { + error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value); + if (error < 0) { snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error); return error; } - change = (value != miro->aci_amp); - miro->aci_amp = value; + change = (value != miro->aci->aci_amp); + miro->aci->aci_amp = value; return change; } @@ -410,12 +441,14 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol, int right_reg = kcontrol->private_value & 0xff; int left_reg = right_reg + 1; - if ((right_val = aci_getvalue(miro, right_reg)) < 0) { + right_val = aci_getvalue(miro->aci, right_reg); + if (right_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val); return right_val; } - if ((left_val = aci_getvalue(miro, left_reg)) < 0) { + left_val = aci_getvalue(miro->aci, left_reg); + if (left_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val); return left_val; } @@ -451,6 +484,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); + struct snd_miro_aci *aci = miro->aci; int left, right, left_old, right_old; int setreg_left, setreg_right, getreg_left, getreg_right; int change, error; @@ -459,21 +493,21 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right = ucontrol->value.integer.value[1]; setreg_right = (kcontrol->private_value >> 8) & 0xff; - if (setreg_right == ACI_SET_MASTER) { - setreg_left = setreg_right + 1; - } else { - setreg_left = setreg_right + 8; - } + setreg_left = setreg_right + 8; + if (setreg_right == ACI_SET_MASTER) + setreg_left -= 7; getreg_right = kcontrol->private_value & 0xff; getreg_left = getreg_right + 1; - if ((left_old = aci_getvalue(miro, getreg_left)) < 0) { + left_old = aci_getvalue(aci, getreg_left); + if (left_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old); return left_old; } - if ((right_old = aci_getvalue(miro, getreg_right)) < 0) { + right_old = aci_getvalue(aci, getreg_right); + if (right_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old); return right_old; } @@ -492,13 +526,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right_old = 0x80 - right_old; if (left >= 0) { - if ((error = aci_setvalue(miro, setreg_left, left)) < 0) { + error = aci_setvalue(aci, setreg_left, left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", left, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x80 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - left, error); return error; @@ -506,13 +542,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, } if (right >= 0) { - if ((error = aci_setvalue(miro, setreg_right, right)) < 0) { + error = aci_setvalue(aci, setreg_right, right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", right, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x80 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - right, error); return error; @@ -530,12 +568,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, left_old = 0x20 - left_old; right_old = 0x20 - right_old; - if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x20 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - left, error); return error; } - if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x20 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - right, error); return error; @@ -633,11 +673,13 @@ static unsigned char aci_init_values[][2] __devinitdata = { static int __devinit snd_set_aci_init_values(struct snd_miro *miro) { int idx, error; + struct snd_miro_aci *aci = miro->aci; /* enable WSS on PCM1 */ - if ((miro->aci_product == 'A') && wss) { - if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) { + if ((aci->aci_product == 'A') && wss) { + error = aci_setvalue(aci, ACI_SET_WSS, wss); + if (error < 0) { snd_printk(KERN_ERR "enabling WSS mode failed\n"); return error; } @@ -646,7 +688,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* enable IDE port */ if (ide) { - if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) { + error = aci_setvalue(aci, ACI_SET_IDE, ide); + if (error < 0) { snd_printk(KERN_ERR "enabling IDE port failed\n"); return error; } @@ -654,32 +697,31 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* set common aci values */ - for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) - if ((error = aci_setvalue(miro, aci_init_values[idx][0], - aci_init_values[idx][1])) < 0) { + for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) { + error = aci_setvalue(aci, aci_init_values[idx][0], + aci_init_values[idx][1]); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", aci_init_values[idx][0], error); return error; } - - miro->aci_amp = 0; - miro->aci_preamp = 0; - miro->aci_solomode = 1; + } + aci->aci_amp = 0; + aci->aci_preamp = 0; + aci->aci_solomode = 1; return 0; } -static int __devinit snd_miro_mixer(struct snd_miro *miro) +static int __devinit snd_miro_mixer(struct snd_card *card, + struct snd_miro *miro) { - struct snd_card *card; unsigned int idx; int err; - if (snd_BUG_ON(!miro || !miro->card)) + if (snd_BUG_ON(!miro || !card)) return -EINVAL; - card = miro->card; - switch (miro->hardware) { case OPTi9XX_HW_82C924: strcpy(card->mixername, "ACI & OPTi924"); @@ -697,7 +739,8 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro) return err; } - if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) { + if ((miro->aci->aci_product == 'A') || + (miro->aci->aci_product == 'B')) { /* PCM1/PCM12 with power-amp and Line 2 */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0) return err; @@ -705,16 +748,17 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro) return err; } - if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) { + if ((miro->aci->aci_product == 'B') || + (miro->aci->aci_product == 'C')) { /* PCM12/PCM20 with mic-preamp */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0) return err; - if (miro->aci_version >= 176) + if (miro->aci->aci_version >= 176) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0) return err; } - if (miro->aci_product == 'C') { + if (miro->aci->aci_product == 'C') { /* PCM20 with radio and 7 band equalizer */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0) return err; @@ -757,21 +801,26 @@ static int __devinit snd_miro_init(struct snd_miro *chip, chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; - chip->fm_port = -1; chip->mpu_port = -1; chip->mpu_irq = -1; + chip->pwd_reg = 3; + +#ifdef CONFIG_PNP + if (isapnp && chip->mc_base) + /* PnP resource gives the least 10 bits */ + chip->mc_base |= 0xc00; + else +#endif + chip->mc_base = 0xf8c; + switch (hardware) { case OPTi9XX_HW_82C929: - chip->mc_base = 0xf8c; chip->password = 0xe3; - chip->pwd_reg = 3; break; case OPTi9XX_HW_82C924: - chip->mc_base = 0xf8c; chip->password = 0xe5; - chip->pwd_reg = 3; break; default: @@ -853,14 +902,15 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { struct snd_miro *miro = (struct snd_miro *) entry->private_data; + struct snd_miro_aci *aci = miro->aci; char* model = "unknown"; /* miroSOUND PCM1 pro, early PCM12 */ if ((miro->hardware == OPTi9XX_HW_82C929) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'A')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'A')) { + switch (aci->aci_version) { case 3: model = "miroSOUND PCM1 pro"; break; @@ -873,9 +923,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'B')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'B')) { + switch (aci->aci_version) { case 4: model = "miroSOUND PCM12"; break; @@ -891,9 +941,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM20 radio */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'C')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'C')) { + switch (aci->aci_version) { case 7: model = "miroSOUND PCM20 radio (Rev. E)"; break; @@ -917,17 +967,17 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "ACI information:\n"); snd_iprintf(buffer, " vendor : "); - switch(miro->aci_vendor) { + switch (aci->aci_vendor) { case 'm': snd_iprintf(buffer, "Miro\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor); break; } snd_iprintf(buffer, " product : "); - switch(miro->aci_product) { + switch (aci->aci_product) { case 'A': snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n"); break; @@ -938,26 +988,27 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "miroSOUND PCM20 radio\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product); break; } snd_iprintf(buffer, " firmware: %d (0x%x)\n", - miro->aci_version, miro->aci_version); + aci->aci_version, aci->aci_version); snd_iprintf(buffer, " port : 0x%lx-0x%lx\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); snd_iprintf(buffer, " wss : 0x%x\n", wss); snd_iprintf(buffer, " ide : 0x%x\n", ide); - snd_iprintf(buffer, " solomode: 0x%x\n", miro->aci_solomode); - snd_iprintf(buffer, " amp : 0x%x\n", miro->aci_amp); - snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp); + snd_iprintf(buffer, " solomode: 0x%x\n", aci->aci_solomode); + snd_iprintf(buffer, " amp : 0x%x\n", aci->aci_amp); + snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp); } -static void __devinit snd_miro_proc_init(struct snd_miro * miro) +static void __devinit snd_miro_proc_init(struct snd_card *card, + struct snd_miro *miro) { struct snd_info_entry *entry; - if (! snd_card_proc_new(miro->card, "miro", &entry)) + if (!snd_card_proc_new(card, "miro", &entry)) snd_info_set_text_ops(entry, miro, snd_miro_proc_read); } @@ -974,37 +1025,40 @@ static int __devinit snd_miro_configure(struct snd_miro *chip) unsigned char mpu_irq_bits; unsigned long flags; + snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); + snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ + snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); + switch (chip->hardware) { case OPTi9XX_HW_82C924: snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; case OPTi9XX_HW_82C929: /* untested init commands for OPTi929 */ - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; default: snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware); return -EINVAL; } - switch (chip->wss_base) { - case 0x530: + /* PnP resource says it decodes only 10 bits of address */ + switch (chip->wss_base & 0x3ff) { + case 0x130: + chip->wss_base = 0x530; wss_base_bits = 0x00; break; - case 0x604: + case 0x204: + chip->wss_base = 0x604; wss_base_bits = 0x03; break; - case 0xe80: + case 0x280: + chip->wss_base = 0xe80; wss_base_bits = 0x01; break; - case 0xf40: + case 0x340: + chip->wss_base = 0xf40; wss_base_bits = 0x02; break; default: @@ -1122,75 +1176,92 @@ __skip_mpu: return 0; } +static int __devinit snd_miro_opti_check(struct snd_miro *chip) +{ + unsigned char value; + + chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, + "OPTi9xx MC"); + if (chip->res_mc_base == NULL) + return -ENOMEM; + + value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); + if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1))) + if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) + return 0; + + release_and_free_resource(chip->res_mc_base); + chip->res_mc_base = NULL; + + return -ENODEV; +} + static int __devinit snd_card_miro_detect(struct snd_card *card, struct snd_miro *chip) { int i, err; - unsigned char value; for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) { if ((err = snd_miro_init(chip, i)) < 0) return err; - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; - - value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); - if ((value != 0xff) && (value != inb(chip->mc_base + 1))) - if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) - return 1; - - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; - + err = snd_miro_opti_check(chip); + if (err == 0) + return 1; } return -ENODEV; } static int __devinit snd_card_miro_aci_detect(struct snd_card *card, - struct snd_miro * miro) + struct snd_miro *miro) { unsigned char regval; int i; + struct snd_miro_aci *aci = &aci_device; + + miro->aci = aci; - mutex_init(&miro->aci_mutex); + mutex_init(&aci->aci_mutex); /* get ACI port from OPTi9xx MC 4 */ - miro->mc_base = 0xf8c; regval=inb(miro->mc_base + 4); - miro->aci_port = (regval & 0x10) ? 0x344: 0x354; + aci->aci_port = (regval & 0x10) ? 0x344 : 0x354; - if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) { + miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci"); + if (miro->res_aci_port == NULL) { snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); return -ENOMEM; } /* force ACI into a known state */ for (i = 0; i < 3; i++) - if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) { + if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) { snd_printk(KERN_ERR "can't force aci into known state.\n"); return -ENXIO; } - if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 || - (miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) { - snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port); + aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + if (aci->aci_vendor < 0 || aci->aci_product < 0) { + snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", + aci->aci_port); return -ENXIO; } - if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) { + aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1); + if (aci->aci_version < 0) { snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n", - miro->aci_port); + aci->aci_port); return -ENXIO; } - if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { + if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { snd_printk(KERN_ERR "can't initialize aci.\n"); return -ENXIO; } @@ -1201,157 +1272,80 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card, static void snd_card_miro_free(struct snd_card *card) { struct snd_miro *miro = card->private_data; - + release_and_free_resource(miro->res_aci_port); + if (miro->aci) + miro->aci->aci_port = 0; release_and_free_resource(miro->res_mc_base); } -static int __devinit snd_miro_match(struct device *devptr, unsigned int n) -{ - return 1; -} - -static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) +static int __devinit snd_miro_probe(struct snd_card *card) { - static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; - static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; - static int possible_irqs[] = {11, 9, 10, 7, -1}; - static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; - static int possible_dma1s[] = {3, 1, 0, -1}; - static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}}; - int error; - struct snd_miro *miro; + struct snd_miro *miro = card->private_data; struct snd_wss *codec; struct snd_timer *timer; - struct snd_card *card; struct snd_pcm *pcm; struct snd_rawmidi *rmidi; - error = snd_card_create(index, id, THIS_MODULE, - sizeof(struct snd_miro), &card); - if (error < 0) - return error; - - card->private_free = snd_card_miro_free; - miro = card->private_data; - miro->card = card; - - if ((error = snd_card_miro_aci_detect(card, miro)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to detect aci chip\n"); - return -ENODEV; + if (!miro->res_mc_base) { + miro->res_mc_base = request_region(miro->mc_base, + miro->mc_base_size, + "miro (OPTi9xx MC)"); + if (miro->res_mc_base == NULL) { + snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); + return -ENOMEM; + } } - /* init proc interface */ - snd_miro_proc_init(miro); - - if ((error = snd_card_miro_detect(card, miro)) < 0) { + error = snd_card_miro_aci_detect(card, miro); + if (error < 0) { snd_card_free(card); - snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + snd_printk(KERN_ERR "unable to detect aci chip\n"); return -ENODEV; } - if (! miro->res_mc_base && - (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size, - "miro (OPTi9xx MC)")) == NULL) { - snd_card_free(card); - snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); - return -ENOMEM; - } - miro->wss_base = port; - miro->fm_port = fm_port; miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; miro->dma1 = dma1; miro->dma2 = dma2; - if (miro->wss_base == SNDRV_AUTO_PORT) { - if ((miro->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free WSS port\n"); - return -EBUSY; - } - } - - if (miro->mpu_port == SNDRV_AUTO_PORT) { - if ((miro->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY; - } - } - if (miro->irq == SNDRV_AUTO_IRQ) { - if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free IRQ\n"); - return -EBUSY; - } - } - if (miro->mpu_irq == SNDRV_AUTO_IRQ) { - if ((miro->mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); - return -EBUSY; - } - } - if (miro->dma1 == SNDRV_AUTO_DMA) { - if ((miro->dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA1\n"); - return -EBUSY; - } - } - if (miro->dma2 == SNDRV_AUTO_DMA) { - if ((miro->dma2 = snd_legacy_find_free_dma(possible_dma2s[miro->dma1 % 4])) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA2\n"); - return -EBUSY; - } - } + /* init proc interface */ + snd_miro_proc_init(card, miro); error = snd_miro_configure(miro); - if (error) { - snd_card_free(card); + if (error) return error; - } error = snd_wss_create(card, miro->wss_base + 4, -1, - miro->irq, miro->dma1, miro->dma2, - WSS_HW_AD1845, 0, &codec); - if (error < 0) { - snd_card_free(card); + miro->irq, miro->dma1, miro->dma2, + WSS_HW_DETECT, 0, &codec); + if (error < 0) return error; - } error = snd_wss_pcm(codec, 0, &pcm); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_mixer(codec); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_timer(codec, 0, &timer); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } miro->pcm = pcm; - if ((error = snd_miro_mixer(miro)) < 0) { - snd_card_free(card); + error = snd_miro_mixer(card, miro); + if (error < 0) return error; - } - if (miro->aci_vendor == 'm') { + if (miro->aci->aci_vendor == 'm') { /* It looks like a miro sound card. */ - switch (miro->aci_product) { + switch (miro->aci->aci_product) { case 'A': sprintf(card->shortname, "miroSOUND PCM1 pro / PCM12"); @@ -1380,30 +1374,131 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) card->shortname, miro->name, pcm->name, miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2); - if (miro->mpu_port <= 0 || miro->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - miro->mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, - &rmidi))) - snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", miro->mpu_port); + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, + &rmidi); + if (error < 0) + snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", + mpu_port); + } - if (miro->fm_port > 0 && miro->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; struct snd_opl4 *opl4; - if (snd_opl4_create(card, miro->fm_port, miro->fm_port - 8, + + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) - snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", miro->fm_port); + snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", + fm_port); } - if ((error = snd_set_aci_init_values(miro)) < 0) { - snd_card_free(card); + error = snd_set_aci_init_values(miro); + if (error < 0) return error; + + return snd_card_register(card); +} + +static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) +{ +#ifdef CONFIG_PNP + if (snd_miro_pnp_is_probed) + return 0; + if (isapnp) + return 0; +#endif + return 1; +} + +static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n) +{ + static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; + static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; + static int possible_irqs[] = {11, 9, 10, 7, -1}; + static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; + static int possible_dma1s[] = {3, 1, 0, -1}; + static int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, + {0, -1} }; + + int error; + struct snd_miro *miro; + struct snd_card *card; + + error = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (error < 0) + return error; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + error = snd_card_miro_detect(card, miro); + if (error < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + return -ENODEV; + } + + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free WSS port\n"); + return -EBUSY; + } + } + + if (mpu_port == SNDRV_AUTO_PORT) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 port\n"); + return -EBUSY; + } + } + + if (irq == SNDRV_AUTO_IRQ) { + irq = snd_legacy_find_free_irq(possible_irqs); + if (irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free IRQ\n"); + return -EBUSY; + } + } + if (mpu_irq == SNDRV_AUTO_IRQ) { + mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs); + if (mpu_irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 IRQ\n"); + return -EBUSY; + } + } + if (dma1 == SNDRV_AUTO_DMA) { + dma1 = snd_legacy_find_free_dma(possible_dma1s); + if (dma1 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA1\n"); + return -EBUSY; + } + } + if (dma2 == SNDRV_AUTO_DMA) { + dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]); + if (dma2 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA2\n"); + return -EBUSY; + } } snd_card_set_dev(card, devptr); - if ((error = snd_card_register(card))) { + error = snd_miro_probe(card); + if (error < 0) { snd_card_free(card); return error; } @@ -1412,7 +1507,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return 0; } -static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) +static int __devexit snd_miro_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1422,23 +1518,164 @@ static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) #define DEV_NAME "miro" static struct isa_driver snd_miro_driver = { - .match = snd_miro_match, - .probe = snd_miro_probe, - .remove = __devexit_p(snd_miro_remove), + .match = snd_miro_isa_match, + .probe = snd_miro_isa_probe, + .remove = __devexit_p(snd_miro_isa_remove), /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME }, }; +#ifdef CONFIG_PNP + +static int __devinit snd_card_miro_pnp(struct snd_miro *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *pid) +{ + struct pnp_dev *pdev; + int err; + struct pnp_dev *devmpu; + struct pnp_dev *devmc; + + pdev = pnp_request_card_device(card, pid->devs[0].id, NULL); + if (pdev == NULL) + return -EBUSY; + + devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); + if (devmpu == NULL) + return -EBUSY; + + devmc = pnp_request_card_device(card, pid->devs[2].id, NULL); + if (devmc == NULL) + return -EBUSY; + + err = pnp_activate_dev(pdev); + if (err < 0) { + snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); + return err; + } + + err = pnp_activate_dev(devmc); + if (err < 0) { + snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n", + err); + return err; + } + + port = pnp_port_start(pdev, 1); + fm_port = pnp_port_start(pdev, 2) + 8; + + /* + * The MC(0) is never accessed and the miroSOUND PCM20 card does not + * include it in the PnP resource range. OPTI93x include it. + */ + chip->mc_base = pnp_port_start(devmc, 0) - 1; + chip->mc_base_size = pnp_port_len(devmc, 0) + 1; + + irq = pnp_irq(pdev, 0); + dma1 = pnp_dma(pdev, 0); + dma2 = pnp_dma(pdev, 1); + + if (mpu_port > 0) { + err = pnp_activate_dev(devmpu); + if (err < 0) { + snd_printk(KERN_ERR "MPU401 pnp configure failure\n"); + mpu_port = -1; + return err; + } + mpu_port = pnp_port_start(devmpu, 0); + mpu_irq = pnp_irq(devmpu, 0); + } + return 0; +} + +static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) +{ + struct snd_card *card; + int err; + struct snd_miro *miro; + + if (snd_miro_pnp_is_probed) + return -EBUSY; + if (!isapnp) + return -ENODEV; + err = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (err < 0) + return err; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + err = snd_card_miro_pnp(miro, pcard, pid); + if (err) { + snd_card_free(card); + return err; + } + + /* only miroSOUND PCM20 and PCM12 == OPTi924 */ + err = snd_miro_init(miro, OPTi9XX_HW_82C924); + if (err) { + snd_card_free(card); + return err; + } + + err = snd_miro_opti_check(miro); + if (err) { + snd_printk(KERN_ERR "OPTI chip not found\n"); + snd_card_free(card); + return err; + } + + snd_card_set_dev(card, &pcard->card->dev); + err = snd_miro_probe(card); + if (err < 0) { + snd_card_free(card); + return err; + } + pnp_set_card_drvdata(pcard, card); + snd_miro_pnp_is_probed = 1; + return 0; +} + +static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard) +{ + snd_card_free(pnp_get_card_drvdata(pcard)); + pnp_set_card_drvdata(pcard, NULL); + snd_miro_pnp_is_probed = 0; +} + +static struct pnp_card_driver miro_pnpc_driver = { + .flags = PNP_DRIVER_RES_DISABLE, + .name = "miro", + .id_table = snd_miro_pnpids, + .probe = snd_miro_pnp_probe, + .remove = __devexit_p(snd_miro_pnp_remove), +}; +#endif + static int __init alsa_card_miro_init(void) { +#ifdef CONFIG_PNP + pnp_register_card_driver(&miro_pnpc_driver); + if (snd_miro_pnp_is_probed) + return 0; + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif return isa_register_driver(&snd_miro_driver, 1); } static void __exit alsa_card_miro_exit(void) { - isa_unregister_driver(&snd_miro_driver); + if (!snd_miro_pnp_is_probed) { + isa_unregister_driver(&snd_miro_driver); + return; + } +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif } module_init(alsa_card_miro_init) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 66187122377..e2d5d2d3ed9 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -1,5 +1,5 @@ /* - * Low-level ALSA driver for the ENSONIQ SoundScape PnP + * Low-level ALSA driver for the ENSONIQ SoundScape * Copyright (c) by Chris Rankin * * This driver was written in part using information obtained from @@ -25,31 +25,36 @@ #include <linux/err.h> #include <linux/isa.h> #include <linux/delay.h> +#include <linux/firmware.h> #include <linux/pnp.h> #include <linux/spinlock.h> #include <linux/moduleparam.h> #include <asm/dma.h> #include <sound/core.h> -#include <sound/hwdep.h> #include <sound/wss.h> #include <sound/mpu401.h> #include <sound/initval.h> -#include <sound/sscape_ioctl.h> - MODULE_AUTHOR("Chris Rankin"); -MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver"); +MODULE_DESCRIPTION("ENSONIQ SoundScape driver"); MODULE_LICENSE("GPL"); - -static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX; -static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR; -static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; -static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; -static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; -static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; -static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; -static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; +MODULE_FIRMWARE("sndscape.co0"); +MODULE_FIRMWARE("sndscape.co1"); +MODULE_FIRMWARE("sndscape.co2"); +MODULE_FIRMWARE("sndscape.co3"); +MODULE_FIRMWARE("sndscape.co4"); +MODULE_FIRMWARE("scope.cod"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static bool joystick[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); @@ -75,6 +80,9 @@ MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); module_param_array(dma2, int, NULL, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver."); +module_param_array(joystick, bool, NULL, 0444); +MODULE_PARM_DESC(joystick, "Enable gameport."); + #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; @@ -101,14 +109,14 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids); #define RX_READY 0x01 #define TX_READY 0x02 -#define CMD_ACK 0x80 -#define CMD_SET_MIDI_VOL 0x84 -#define CMD_GET_MIDI_VOL 0x85 -#define CMD_XXX_MIDI_VOL 0x86 -#define CMD_SET_EXTMIDI 0x8a -#define CMD_GET_EXTMIDI 0x8b -#define CMD_SET_MT32 0x8c -#define CMD_GET_MT32 0x8d +#define CMD_ACK 0x80 +#define CMD_SET_MIDI_VOL 0x84 +#define CMD_GET_MIDI_VOL 0x85 +#define CMD_XXX_MIDI_VOL 0x86 +#define CMD_SET_EXTMIDI 0x8a +#define CMD_GET_EXTMIDI 0x8b +#define CMD_SET_MT32 0x8c +#define CMD_GET_MT32 0x8d enum GA_REG { GA_INTSTAT_REG = 0, @@ -127,7 +135,8 @@ enum GA_REG { enum card_type { - SSCAPE, + MEDIA_FX, /* Sequoia S-1000 */ + SSCAPE, /* Sequoia S-2000 */ SSCAPE_PNP, SSCAPE_VIVO, }; @@ -140,16 +149,7 @@ struct soundscape { struct resource *io_res; struct resource *wss_res; struct snd_wss *chip; - struct snd_mpu401 *mpu; - struct snd_hwdep *hw; - /* - * The MIDI device won't work until we've loaded - * its firmware via a hardware-dependent device IOCTL - */ - spinlock_t fwlock; - int hw_in_use; - unsigned long midi_usage; unsigned char midi_vol; }; @@ -161,28 +161,21 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c) return (struct soundscape *) (c->private_data); } -static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu) -{ - return (struct soundscape *) (mpu->private_data); -} - -static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw) -{ - return (struct soundscape *) (hw->private_data); -} - - /* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to * contiguous pages of physical memory. */ -static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size) +static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, + unsigned long size) { if (buf) { - if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), + if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), size, buf) < 0) { - snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size); + snd_printk(KERN_ERR "sscape: Failed to allocate " + "%lu bytes for DMA\n", + size); return NULL; } } @@ -199,13 +192,13 @@ static void free_dmabuf(struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } - /* * This function writes to the SoundScape's control registers, * but doesn't do any locking. It's up to the caller to do that. * This is why this function is "unsafe" ... */ -static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val) +static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, + unsigned char val) { outb(reg, ODIE_ADDR_IO(io_base)); outb(val, ODIE_DATA_IO(io_base)); @@ -215,7 +208,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsign * Write to the SoundScape's control registers, and do the * necessary locking ... */ -static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val) +static void sscape_write(struct soundscape *s, enum GA_REG reg, + unsigned char val) { unsigned long flags; @@ -228,7 +222,8 @@ static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char va * Read from the SoundScape's control registers, but leave any * locking to the caller. This is why the function is "unsafe" ... */ -static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg) +static inline unsigned char sscape_read_unsafe(unsigned io_base, + enum GA_REG reg) { outb(reg, ODIE_ADDR_IO(io_base)); return inb(ODIE_DATA_IO(io_base)); @@ -257,9 +252,8 @@ static inline void set_midi_mode_unsafe(unsigned io_base) static inline int host_read_unsafe(unsigned io_base) { int data = -1; - if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) { + if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) data = inb(HOST_DATA_IO(io_base)); - } return data; } @@ -301,7 +295,7 @@ static inline int host_write_unsafe(unsigned io_base, unsigned char data) * Also leaves all locking-issues to the caller ... */ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, - unsigned timeout) + unsigned timeout) { int err; @@ -320,7 +314,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, * * NOTE: This check is based upon observation, not documentation. */ -static inline int verify_mpu401(const struct snd_mpu401 * mpu) +static inline int verify_mpu401(const struct snd_mpu401 *mpu) { return ((inb(MPU401C(mpu)) & 0xc0) == 0x80); } @@ -328,7 +322,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu) /* * This is apparently the standard way to initailise an MPU-401 */ -static inline void initialise_mpu401(const struct snd_mpu401 * mpu) +static inline void initialise_mpu401(const struct snd_mpu401 *mpu) { outb(0, MPU401D(mpu)); } @@ -338,9 +332,10 @@ static inline void initialise_mpu401(const struct snd_mpu401 * mpu) * The AD1845 detection fails if we *don't* do this, so I * think that this is a good idea ... */ -static inline void activate_ad1845_unsafe(unsigned io_base) +static void activate_ad1845_unsafe(unsigned io_base) { - sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10); + unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG); + sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10); sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80); } @@ -359,24 +354,27 @@ static void soundscape_free(struct snd_card *c) * Tell the SoundScape to begin a DMA tranfer using the given channel. * All locking issues are left to the caller. */ -static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) +static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) { - sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01); - sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe); + sscape_write_unsafe(io_base, reg, + sscape_read_unsafe(io_base, reg) | 0x01); + sscape_write_unsafe(io_base, reg, + sscape_read_unsafe(io_base, reg) & 0xfe); } /* * Wait for a DMA transfer to complete. This is a "limited busy-wait", * and all locking issues are left to the caller. */ -static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout) +static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, + unsigned timeout) { while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) { udelay(100); --timeout; } /* while */ - return (sscape_read_unsafe(io_base, reg) & 0x01); + return sscape_read_unsafe(io_base, reg) & 0x01; } /* @@ -392,12 +390,12 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout) do { unsigned long flags; - unsigned char x; + int x; spin_lock_irqsave(&s->lock, flags); - x = inb(HOST_DATA_IO(s->io_base)); + x = host_read_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); - if ((x & 0xfe) == 0xfe) + if (x == 0xfe || x == 0xff) return 1; msleep(10); @@ -419,10 +417,10 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) do { unsigned long flags; - unsigned char x; + int x; spin_lock_irqsave(&s->lock, flags); - x = inb(HOST_DATA_IO(s->io_base)); + x = host_read_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); if (x == 0xfe) return 1; @@ -436,15 +434,15 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) /* * Upload a byte-stream into the SoundScape using DMA channel A. */ -static int upload_dma_data(struct soundscape *s, - const unsigned char __user *data, - size_t size) +static int upload_dma_data(struct soundscape *s, const unsigned char *data, + size_t size) { unsigned long flags; struct snd_dma_buffer dma; int ret; + unsigned char val; - if (!get_dmabuf(&dma, PAGE_ALIGN(size))) + if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; spin_lock_irqsave(&s->lock, flags); @@ -452,70 +450,57 @@ static int upload_dma_data(struct soundscape *s, /* * Reset the board ... */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f); /* * Enable the DMA channels and configure them ... */ - sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50); - sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT); + val = (s->chip->dma1 << 4) | DMA_8BIT; + sscape_write_unsafe(s->io_base, GA_DMAA_REG, val); sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); /* * Take the board out of reset ... */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80); /* - * Upload the user's data (firmware?) to the SoundScape + * Upload the firmware to the SoundScape * board through the DMA channel ... */ while (size != 0) { unsigned long len; - /* - * Apparently, copying to/from userspace can sleep. - * We are therefore forbidden from holding any - * spinlocks while we copy ... - */ - spin_unlock_irqrestore(&s->lock, flags); - - /* - * Remember that the data that we want to DMA - * comes from USERSPACE. We have already verified - * the userspace pointer ... - */ len = min(size, dma.bytes); - len -= __copy_from_user(dma.area, data, len); + memcpy(dma.area, data, len); data += len; size -= len; - /* - * Grab that spinlock again, now that we've - * finished copying! - */ - spin_lock_irqsave(&s->lock, flags); - snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { /* - * Don't forget to release this spinlock we're holding ... + * Don't forget to release this spinlock we're holding */ spin_unlock_irqrestore(&s->lock, flags); - snd_printk(KERN_ERR "sscape: DMA upload has timed out\n"); + snd_printk(KERN_ERR + "sscape: DMA upload has timed out\n"); ret = -EAGAIN; goto _release_dma; } } /* while */ set_host_mode_unsafe(s->io_base); + outb(0x0, s->io_base); /* * Boot the board ... (I think) */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40); spin_unlock_irqrestore(&s->lock, flags); /* @@ -525,10 +510,12 @@ static int upload_dma_data(struct soundscape *s, */ ret = 0; if (!obp_startup_ack(s, 5000)) { - snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n"); + snd_printk(KERN_ERR "sscape: No response " + "from on-board processor after upload\n"); ret = -EAGAIN; } else if (!host_startup_ack(s, 5000)) { - snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n"); + snd_printk(KERN_ERR + "sscape: SoundScape failed to initialise\n"); ret = -EAGAIN; } @@ -536,7 +523,7 @@ _release_dma: /* * NOTE!!! We are NOT holding any spinlocks at this point !!! */ - sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40)); + sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70)); free_dmabuf(&dma); return ret; @@ -546,167 +533,76 @@ _release_dma: * Upload the bootblock(?) into the SoundScape. The only * purpose of this block of code seems to be to tell * us which version of the microcode we should be using. - * - * NOTE: The boot-block data resides in USER-SPACE!!! - * However, we have already verified its memory - * addresses by the time we get here. */ -static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb) +static int sscape_upload_bootblock(struct snd_card *card) { + struct soundscape *sscape = get_card_soundscape(card); unsigned long flags; + const struct firmware *init_fw = NULL; int data = 0; int ret; - ret = upload_dma_data(sscape, bb->code, sizeof(bb->code)); - - spin_lock_irqsave(&sscape->lock, flags); - if (ret == 0) { - data = host_read_ctrl_unsafe(sscape->io_base, 100); - } - set_midi_mode_unsafe(sscape->io_base); - spin_unlock_irqrestore(&sscape->lock, flags); - - if (ret == 0) { - if (data < 0) { - snd_printk(KERN_ERR "sscape: timeout reading firmware version\n"); - ret = -EAGAIN; - } - else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) { - ret = -EFAULT; - } + ret = request_firmware(&init_fw, "scope.cod", card->dev); + if (ret < 0) { + snd_printk(KERN_ERR "sscape: Error loading scope.cod"); + return ret; } + ret = upload_dma_data(sscape, init_fw->data, init_fw->size); - return ret; -} - -/* - * Upload the microcode into the SoundScape. The - * microcode is 64K of data, and if we try to copy - * it into a local variable then we will SMASH THE - * KERNEL'S STACK! We therefore leave it in USER - * SPACE, and save ourselves from copying it at all. - */ -static int sscape_upload_microcode(struct soundscape *sscape, - const struct sscape_microcode __user *mc) -{ - unsigned long flags; - char __user *code; - int err; + release_firmware(init_fw); - /* - * We are going to have to copy this data into a special - * DMA-able buffer before we can upload it. We shall therefore - * just check that the data pointer is valid for now. - * - * NOTE: This buffer is 64K long! That's WAY too big to - * copy into a stack-temporary anyway. - */ - if ( get_user(code, &mc->code) || - !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) ) - return -EFAULT; + spin_lock_irqsave(&sscape->lock, flags); + if (ret == 0) + data = host_read_ctrl_unsafe(sscape->io_base, 100); - if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) { - snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); - } + if (data & 0x10) + sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f); - spin_lock_irqsave(&sscape->lock, flags); - set_midi_mode_unsafe(sscape->io_base); spin_unlock_irqrestore(&sscape->lock, flags); - initialise_mpu401(sscape->mpu); + data &= 0xf; + if (ret == 0 && data > 7) { + snd_printk(KERN_ERR + "sscape: timeout reading firmware version\n"); + ret = -EAGAIN; + } - return err; + return (ret == 0) ? data : ret; } /* - * Hardware-specific device functions, to implement special - * IOCTLs for the SoundScape card. This is how we upload - * the microcode into the card, for example, and so we - * must ensure that no two processes can open this device - * simultaneously, and that we can't open it at all if - * someone is using the MIDI device. + * Upload the microcode into the SoundScape. */ -static int sscape_hw_open(struct snd_hwdep * hw, struct file *file) +static int sscape_upload_microcode(struct snd_card *card, int version) { - register struct soundscape *sscape = get_hwdep_soundscape(hw); - unsigned long flags; + struct soundscape *sscape = get_card_soundscape(card); + const struct firmware *init_fw = NULL; + char name[14]; int err; - spin_lock_irqsave(&sscape->fwlock, flags); + snprintf(name, sizeof(name), "sndscape.co%d", version); - if ((sscape->midi_usage != 0) || sscape->hw_in_use) { - err = -EBUSY; - } else { - sscape->hw_in_use = 1; - err = 0; + err = request_firmware(&init_fw, name, card->dev); + if (err < 0) { + snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d", + version); + return err; } + err = upload_dma_data(sscape, init_fw->data, init_fw->size); + if (err == 0) + snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n", + init_fw->size >> 10); - spin_unlock_irqrestore(&sscape->fwlock, flags); - return err; -} - -static int sscape_hw_release(struct snd_hwdep * hw, struct file *file) -{ - register struct soundscape *sscape = get_hwdep_soundscape(hw); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - sscape->hw_in_use = 0; - spin_unlock_irqrestore(&sscape->fwlock, flags); - return 0; -} - -static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct soundscape *sscape = get_hwdep_soundscape(hw); - int err = -EBUSY; - - switch (cmd) { - case SND_SSCAPE_LOAD_BOOTB: - { - register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg; - - /* - * We are going to have to copy this data into a special - * DMA-able buffer before we can upload it. We shall therefore - * just check that the data pointer is valid for now ... - */ - if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) ) - return -EFAULT; - - /* - * Now check that we can write the firmware version number too... - */ - if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) ) - return -EFAULT; - - err = sscape_upload_bootblock(sscape, bb); - } - break; - - case SND_SSCAPE_LOAD_MCODE: - { - register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg; - - err = sscape_upload_microcode(sscape, mc); - } - break; - - default: - err = -EINVAL; - break; - } /* switch */ + release_firmware(init_fw); return err; } - /* * Mixer control for the SoundScape's MIDI device. */ static int sscape_midi_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; @@ -716,7 +612,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl, } static int sscape_midi_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) + struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; @@ -730,16 +626,18 @@ static int sscape_midi_get(struct snd_kcontrol *kctl, } static int sscape_midi_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) + struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; - register struct soundscape *s = get_card_soundscape(card); + struct soundscape *s = get_card_soundscape(card); unsigned long flags; int change; + unsigned char new_val; spin_lock_irqsave(&s->lock, flags); + new_val = uctl->value.integer.value[0] & 127; /* * We need to put the board into HOST mode before we * can send any volume-changing HOST commands ... @@ -752,15 +650,16 @@ static int sscape_midi_put(struct snd_kcontrol *kctl, * and then perform another volume-related command. Perhaps the * first command is an "open" and the second command is a "close"? */ - if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) { + if (s->midi_vol == new_val) { change = 0; goto __skip_change; } - change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) - && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100) - && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)); - s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127; - __skip_change: + change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, new_val, 100) + && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, new_val, 100); + s->midi_vol = new_val; +__skip_change: /* * Take the board out of HOST mode and back into MIDI mode ... @@ -784,20 +683,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = { * These IRQs are encoded as bit patterns so that they can be * written to the control registers. */ -static unsigned __devinit get_irq_config(int irq) +static unsigned __devinit get_irq_config(int sscape_type, int irq) { static const int valid_irq[] = { 9, 5, 7, 10 }; + static const int old_irq[] = { 9, 7, 5, 15 }; unsigned cfg; - for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) { - if (irq == valid_irq[cfg]) - return cfg; - } /* for */ + if (sscape_type == MEDIA_FX) { + for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg) + if (irq == old_irq[cfg]) + return cfg; + } else { + for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) + if (irq == valid_irq[cfg]) + return cfg; + } return INVALID_IRQ; } - /* * Perform certain arcane port-checks to see whether there * is a SoundScape board lurking behind the given ports. @@ -842,11 +746,38 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) goto _done; - d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + if (s->ic_type == IC_OPUS) + activate_ad1845_unsafe(s->io_base); if (s->type == SSCAPE_VIVO) wss_io += 4; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + + /* wait for WSS codec */ + for (d = 0; d < 500; d++) { + if ((inb(wss_io) & 0x80) == 0) + break; + spin_unlock_irqrestore(&s->lock, flags); + msleep(1); + spin_lock_irqsave(&s->lock, flags); + } + + if ((inb(wss_io) & 0x80) != 0) + goto _done; + + if (inb(wss_io + 2) == 0xff) + goto _done; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d); + + if ((inb(wss_io) & 0x80) != 0) + s->type = MEDIA_FX; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); /* wait for WSS codec */ for (d = 0; d < 500; d++) { if ((inb(wss_io) & 0x80) == 0) @@ -855,14 +786,13 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) msleep(1); spin_lock_irqsave(&s->lock, flags); } - snd_printd(KERN_INFO "init delay = %d ms\n", d); /* * SoundScape successfully detected! */ retval = 1; - _done: +_done: spin_unlock_irqrestore(&s->lock, flags); return retval; } @@ -873,63 +803,35 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) * to crash the machine. Also check that someone isn't using the hardware * IOCTL device. */ -static int mpu401_open(struct snd_mpu401 * mpu) +static int mpu401_open(struct snd_mpu401 *mpu) { - int err; - if (!verify_mpu401(mpu)) { - snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n"); - err = -ENODEV; - } else { - register struct soundscape *sscape = get_mpu401_soundscape(mpu); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - - if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) { - err = -EBUSY; - } else { - ++(sscape->midi_usage); - err = 0; - } - - spin_unlock_irqrestore(&sscape->fwlock, flags); + snd_printk(KERN_ERR "sscape: MIDI disabled, " + "please load firmware\n"); + return -ENODEV; } - return err; -} - -static void mpu401_close(struct snd_mpu401 * mpu) -{ - register struct soundscape *sscape = get_mpu401_soundscape(mpu); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - --(sscape->midi_usage); - spin_unlock_irqrestore(&sscape->fwlock, flags); + return 0; } /* * Initialse an MPU-401 subdevice for MIDI support on the SoundScape. */ -static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq) +static int __devinit create_mpu401(struct snd_card *card, int devnum, + unsigned long port, int irq) { struct soundscape *sscape = get_card_soundscape(card); struct snd_rawmidi *rawmidi; int err; - if ((err = snd_mpu401_uart_new(card, devnum, - MPU401_HW_MPU401, - port, MPU401_INFO_INTEGRATED, - irq, IRQF_DISABLED, - &rawmidi)) == 0) { - struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; + err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port, + MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED, + &rawmidi); + if (err == 0) { + struct snd_mpu401 *mpu = rawmidi->private_data; mpu->open_input = mpu401_open; mpu->open_output = mpu401_open; - mpu->close_input = mpu401_close; - mpu->close_output = mpu401_close; mpu->private_data = sscape; - sscape->mpu = mpu; initialise_mpu401(mpu); } @@ -950,32 +852,34 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, register struct soundscape *sscape = get_card_soundscape(card); struct snd_wss *chip; int err; + int codec_type = WSS_HW_DETECT; - if (sscape->type == SSCAPE_VIVO) - port += 4; + switch (sscape->type) { + case MEDIA_FX: + case SSCAPE: + /* + * There are some freak examples of early Soundscape cards + * with CS4231 instead of AD1848/CS4248. Unfortunately, the + * CS4231 works only in CS4248 compatibility mode on + * these cards so force it. + */ + if (sscape->ic_type != IC_OPUS) + codec_type = WSS_HW_AD1848; + break; - if (dma1 == dma2) - dma2 = -1; + case SSCAPE_VIVO: + port += 4; + break; + default: + break; + } err = snd_wss_create(card, port, -1, irq, dma1, dma2, - WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); + codec_type, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; struct snd_pcm *pcm; -/* - * It turns out that the PLAYBACK_ENABLE bit is set - * by the lowlevel driver ... - * -#define AD1845_IFACE_CONFIG \ - (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) - snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_wss_mce_down(chip); - */ - if (sscape->type != SSCAPE_VIVO) { /* * The input clock frequency on the SoundScape must @@ -1022,17 +926,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, } } - strcpy(card->driver, "SoundScape"); - strcpy(card->shortname, pcm->name); - snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", - pcm->name, chip->port, chip->irq, - chip->dma1, chip->dma2); - sscape->chip = chip; } - _error: +_error: return err; } @@ -1051,21 +948,8 @@ static int __devinit create_sscape(int dev, struct snd_card *card) struct resource *wss_res; unsigned long flags; int err; - - /* - * Check that the user didn't pass us garbage data ... - */ - irq_cfg = get_irq_config(irq[dev]); - if (irq_cfg == INVALID_IRQ) { - snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); - return -ENXIO; - } - - mpu_irq_cfg = get_irq_config(mpu_irq[dev]); - if (mpu_irq_cfg == INVALID_IRQ) { - printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); - return -ENXIO; - } + int val; + const char *name; /* * Grab IO ports that we will need to probe so that we @@ -1098,41 +982,51 @@ static int __devinit create_sscape(int dev, struct snd_card *card) } spin_lock_init(&sscape->lock); - spin_lock_init(&sscape->fwlock); sscape->io_res = io_res; sscape->wss_res = wss_res; sscape->io_base = port[dev]; if (!detect_sscape(sscape, wss_port[dev])) { - printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base); + printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", + sscape->io_base); err = -ENODEV; goto _release_dma; } - printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n", - sscape->io_base, irq[dev], dma[dev]); + switch (sscape->type) { + case MEDIA_FX: + name = "MediaFX/SoundFX"; + break; + case SSCAPE: + name = "Soundscape"; + break; + case SSCAPE_PNP: + name = "Soundscape PnP"; + break; + case SSCAPE_VIVO: + name = "Soundscape VIVO"; + break; + default: + name = "unknown Soundscape"; + break; + } - if (sscape->type != SSCAPE_VIVO) { - /* - * Now create the hardware-specific device so that we can - * load the microcode into the on-board processor. - * We cannot use the MPU-401 MIDI system until this firmware - * has been loaded into the card. - */ - err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw)); - if (err < 0) { - printk(KERN_ERR "sscape: Failed to create " - "firmware device\n"); - goto _release_dma; - } - strlcpy(sscape->hw->name, "SoundScape M68K", - sizeof(sscape->hw->name)); - sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; - sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; - sscape->hw->ops.open = sscape_hw_open; - sscape->hw->ops.release = sscape_hw_release; - sscape->hw->ops.ioctl = sscape_hw_ioctl; - sscape->hw->private_data = sscape; + printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n", + name, sscape->io_base, irq[dev], dma[dev]); + + /* + * Check that the user didn't pass us garbage data ... + */ + irq_cfg = get_irq_config(sscape->type, irq[dev]); + if (irq_cfg == INVALID_IRQ) { + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); + return -ENXIO; + } + + mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); + if (mpu_irq_cfg == INVALID_IRQ) { + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); + return -ENXIO; } /* @@ -1141,9 +1035,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) */ spin_lock_irqsave(&sscape->lock, flags); - activate_ad1845_unsafe(sscape->io_base); - - sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); @@ -1151,15 +1042,23 @@ static int __devinit create_sscape(int dev, struct snd_card *card) * Enable and configure the DMA channels ... */ sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); - dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40); + dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); - sscape_write_unsafe(sscape->io_base, - GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); + mpu_irq_cfg |= mpu_irq_cfg << 2; + val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; + if (joystick[dev]) + val |= 8; + sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); + sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); + /* + * Enable the master IRQ ... + */ + sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); spin_unlock_irqrestore(&sscape->lock, flags); @@ -1170,32 +1069,56 @@ static int __devinit create_sscape(int dev, struct snd_card *card) err = create_ad1845(card, wss_port[dev], irq[dev], dma[dev], dma2[dev]); if (err < 0) { - printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n", - wss_port[dev], irq[dev]); + snd_printk(KERN_ERR + "sscape: No AD1845 device at 0x%lx, IRQ %d\n", + wss_port[dev], irq[dev]); goto _release_dma; } + strcpy(card->driver, "SoundScape"); + strcpy(card->shortname, name); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", + name, sscape->chip->port, sscape->chip->irq, + sscape->chip->dma1, sscape->chip->dma2); + #define MIDI_DEVNUM 0 if (sscape->type != SSCAPE_VIVO) { - err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]); - if (err < 0) { - printk(KERN_ERR "sscape: Failed to create " - "MPU-401 device at 0x%lx\n", - port[dev]); - goto _release_dma; - } + err = sscape_upload_bootblock(card); + if (err >= 0) + err = sscape_upload_microcode(card, err); - /* - * Enable the master IRQ ... - */ - sscape_write(sscape, GA_INTENA_REG, 0x80); + if (err == 0) { + err = create_mpu401(card, MIDI_DEVNUM, port[dev], + mpu_irq[dev]); + if (err < 0) { + snd_printk(KERN_ERR "sscape: Failed to create " + "MPU-401 device at 0x%lx\n", + port[dev]); + goto _release_dma; + } - /* - * Initialize mixer - */ - sscape->midi_vol = 0; - host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); - host_write_ctrl_unsafe(sscape->io_base, 0, 100); - host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + /* + * Initialize mixer + */ + spin_lock_irqsave(&sscape->lock, flags); + sscape->midi_vol = 0; + host_write_ctrl_unsafe(sscape->io_base, + CMD_SET_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, + sscape->midi_vol, 100); + host_write_ctrl_unsafe(sscape->io_base, + CMD_XXX_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, + sscape->midi_vol, 100); + host_write_ctrl_unsafe(sscape->io_base, + CMD_SET_EXTMIDI, 100); + host_write_ctrl_unsafe(sscape->io_base, + 0, 100); + host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); + + set_midi_mode_unsafe(sscape->io_base); + spin_unlock_irqrestore(&sscape->lock, flags); + } } /* @@ -1231,7 +1154,8 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i) mpu_irq[i] == SNDRV_AUTO_IRQ || dma[i] == SNDRV_AUTO_DMA) { printk(KERN_INFO - "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n"); + "sscape: insufficient parameters, " + "need IO, IRQ, MPU-IRQ and DMA\n"); return 0; } @@ -1253,13 +1177,15 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) sscape->type = SSCAPE; dma[dev] &= 0x03; + snd_card_set_dev(card, pdev); + ret = create_sscape(dev, card); if (ret < 0) goto _release_card; - snd_card_set_dev(card, pdev); - if ((ret = snd_card_register(card)) < 0) { - printk(KERN_ERR "sscape: Failed to register sound card\n"); + ret = snd_card_register(card); + if (ret < 0) { + snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } dev_set_drvdata(pdev, card); @@ -1311,36 +1237,20 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, * Allow this function to fail *quietly* if all the ISA PnP * devices were configured using module parameters instead. */ - if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS) + idx = get_next_autoindex(idx); + if (idx >= SNDRV_CARDS) return -ENOSPC; /* - * We have found a candidate ISA PnP card. Now we - * have to check that it has the devices that we - * expect it to have. - * - * We will NOT try and autoconfigure all of the resources - * needed and then activate the card as we are assuming that - * has already been done at boot-time using /proc/isapnp. - * We shall simply try to give each active card the resources - * that it wants. This is a sensible strategy for a modular - * system where unused modules are unloaded regularly. - * - * This strategy is utterly useless if we compile the driver - * into the kernel, of course. - */ - // printk(KERN_INFO "sscape: %s\n", card->name); - - /* * Check that we still have room for another sound card ... */ dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL); - if (! dev) + if (!dev) return -ENODEV; if (!pnp_is_active(dev)) { if (pnp_activate_dev(dev) < 0) { - printk(KERN_INFO "sscape: device is inactive\n"); + snd_printk(KERN_INFO "sscape: device is inactive\n"); return -EBUSY; } } @@ -1378,14 +1288,15 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, wss_port[idx] = pnp_port_start(dev, 1); dma2[idx] = pnp_dma(dev, 1); } + snd_card_set_dev(card, &pcard->card->dev); ret = create_sscape(idx, card); if (ret < 0) goto _release_card; - snd_card_set_dev(card, &pcard->card->dev); - if ((ret = snd_card_register(card)) < 0) { - printk(KERN_ERR "sscape: Failed to register sound card\n"); + ret = snd_card_register(card); + if (ret < 0) { + snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5d2ba1b749a..5b9d6c18bc4 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ -int snd_wss_free(struct snd_wss *chip) +static int snd_wss_free(struct snd_wss *chip) { release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_cport); @@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip) kfree(chip); return 0; } -EXPORT_SYMBOL(snd_wss_free); static int snd_wss_dev_free(struct snd_device *device) { @@ -2198,84 +2197,61 @@ EXPORT_SYMBOL(snd_wss_put_double); static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static struct snd_kcontrol_new snd_ad1848_controls[] = { -WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, - 7, 7, 1, 1), +static struct snd_kcontrol_new snd_wss_controls[] = { +WSS_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, - db_scale_6bit), + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), WSS_DOUBLE("Aux Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Aux Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Aux Playback Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0, db_scale_rec_gain), { - .name = "Capture Source", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", .info = snd_wss_info_mux, .get = snd_wss_get_mux, .put = snd_wss_put_mux, }, -WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0, - db_scale_6bit), -}; - -static struct snd_kcontrol_new snd_wss_controls[] = { -WSS_DOUBLE("PCM Playback Switch", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("Mic Boost (+20dB)", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), +WSS_SINGLE("Loopback Capture Switch", 0, + CS4231_LOOPBACK, 0, 1, 0), +WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1, + db_scale_6bit), WSS_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -WSS_DOUBLE("Aux Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -WSS_DOUBLE("Aux Playback Switch", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -WSS_SINGLE("Mono Playback Switch", 0, +WSS_DOUBLE_TLV("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), +WSS_SINGLE("Beep Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, - CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE_TLV("Beep Playback Volume", 0, + CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), WSS_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), -WSS_SINGLE("Mono Output Playback Bypass", 0, +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_wss_info_mux, - .get = snd_wss_get_mux, - .put = snd_wss_put_mux, -}, -WSS_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -WSS_SINGLE("Loopback Capture Switch", 0, - CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE("Loopback Capture Volume", 0, - CS4231_LOOPBACK, 2, 63, 1) }; static struct snd_kcontrol_new snd_opti93x_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, + db_scale_6bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE("PCM Playback Volume", 0, @@ -2334,22 +2310,21 @@ int snd_wss_mixer(struct snd_wss *chip) if (err < 0) return err; } - else if (chip->hardware & WSS_HW_AD1848_MASK) - for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_ad1848_controls[idx], - chip)); - if (err < 0) - return err; - } - else - for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) { + else { + int count = ARRAY_SIZE(snd_wss_controls); + + /* Use only the first 11 entries on AD1848 */ + if (chip->hardware & WSS_HW_AD1848_MASK) + count = 11; + + for (idx = 0; idx < count; idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_wss_controls[idx], chip)); if (err < 0) return err; } + } return 0; } EXPORT_SYMBOL(snd_wss_mixer); diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index bcf2a0698d5..135a2b77cc4 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -287,18 +287,6 @@ config SOUND_DMAP Say Y unless you have 16MB or more RAM or a PCI sound card. -config SOUND_SSCAPE - tristate "Ensoniq SoundScape support" - help - Answer Y if you have a sound card based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, Spea - and Reveal (Reveal makes also other cards). - - If you compile the driver into the kernel, you have to add - "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command - line. - - config SOUND_VMIDI tristate "Loopback MIDI device support" help diff --git a/sound/oss/Makefile b/sound/oss/Makefile index e0ae4d4d6a5..567b8a74178 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o diff --git a/sound/oss/audio.c b/sound/oss/audio.c index b69c05b7ea7..7df48a25c4e 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) if ((err = audio_devs[dev]->d->prepare_for_input(dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) { spin_unlock_irqrestore(&dmap_in->lock,flags); - return -err; + return err; } dmap_in->dma_mode = DMODE_INPUT; audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 9e450988ed3..3bc7104c537 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c @@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode) int err; struct midi_input_info *inc; - if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL) return -ENXIO; midi2synth[orig_dev] = dev; diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 734b8f9e2f7..0af9d24feb8 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg) midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL) return -ENXIO; devc = &dev_conf[midi_dev]; diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index b2ed8757542..4153752507e 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -164,9 +164,6 @@ static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, int free; int nbytes; - if (count < 0) - return -EINVAL; - if (!count) { dac_audio_sync(); return 0; diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c deleted file mode 100644 index 30c36d1f35d..00000000000 --- a/sound/oss/sscape.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * sound/oss/sscape.c - * - * Low level driver for Ensoniq SoundScape - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Sergey Smitienko : ensoniq p'n'p support - * Christoph Hellwig : adapted to module_init/module_exit - * Bartlomiej Zolnierkiewicz : added __init to attach_sscape() - * Chris Rankin : Specify that this module owns the coprocessor - * Arnaldo C. de Melo : added missing restore_flags in sscape_pnp_upload_file - */ - -#include <linux/init.h> -#include <linux/module.h> - -#include "sound_config.h" -#include "sound_firmware.h" - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/fcntl.h> -#include <linux/ctype.h> -#include <linux/stddef.h> -#include <linux/kmod.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/wait.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/mm.h> -#include <linux/spinlock.h> - -#include "coproc.h" - -#include "ad1848.h" -#include "mpu401.h" - -/* - * I/O ports - */ -#define MIDI_DATA 0 -#define MIDI_CTRL 1 -#define HOST_CTRL 2 -#define TX_READY 0x02 -#define RX_READY 0x01 -#define HOST_DATA 3 -#define ODIE_ADDR 4 -#define ODIE_DATA 5 - -/* - * Indirect registers - */ - -#define GA_INTSTAT_REG 0 -#define GA_INTENA_REG 1 -#define GA_DMAA_REG 2 -#define GA_DMAB_REG 3 -#define GA_INTCFG_REG 4 -#define GA_DMACFG_REG 5 -#define GA_CDCFG_REG 6 -#define GA_SMCFGA_REG 7 -#define GA_SMCFGB_REG 8 -#define GA_HMCTL_REG 9 - -/* - * DMA channel identifiers (A and B) - */ - -#define SSCAPE_DMA_A 0 -#define SSCAPE_DMA_B 1 - -#define PORT(name) (devc->base+name) - -/* - * Host commands recognized by the OBP microcode - */ - -#define CMD_GEN_HOST_ACK 0x80 -#define CMD_GEN_MPU_ACK 0x81 -#define CMD_GET_BOARD_TYPE 0x82 -#define CMD_SET_CONTROL 0x88 /* Old firmware only */ -#define CMD_GET_CONTROL 0x89 /* Old firmware only */ -#define CTL_MASTER_VOL 0 -#define CTL_MIC_MODE 2 -#define CTL_SYNTH_VOL 4 -#define CTL_WAVE_VOL 7 -#define CMD_SET_EXTMIDI 0x8a -#define CMD_GET_EXTMIDI 0x8b -#define CMD_SET_MT32 0x8c -#define CMD_GET_MT32 0x8d - -#define CMD_ACK 0x80 - -#define IC_ODIE 1 -#define IC_OPUS 2 - -typedef struct sscape_info -{ - int base, irq, dma; - - int codec, codec_irq; /* required to setup pnp cards*/ - int codec_type; - int ic_type; - char* raw_buf; - unsigned long raw_buf_phys; - int buffsize; /* -------------------------- */ - spinlock_t lock; - int ok; /* Properly detected */ - int failed; - int dma_allocated; - int codec_audiodev; - int opened; - int *osp; - int my_audiodev; -} sscape_info; - -static struct sscape_info adev_info = { - 0 -}; - -static struct sscape_info *devc = &adev_info; -static int sscape_mididev = -1; - -/* Some older cards have assigned interrupt bits differently than new ones */ -static char valid_interrupts_old[] = { - 9, 7, 5, 15 -}; - -static char valid_interrupts_new[] = { - 9, 5, 7, 10 -}; - -static char *valid_interrupts = valid_interrupts_new; - -/* - * See the bottom of the driver. This can be set by spea =0/1. - */ - -#ifdef REVEAL_SPEA -static char old_hardware = 1; -#else -static char old_hardware; -#endif - -static void sleep(unsigned howlong) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(howlong); -} - -static unsigned char sscape_read(struct sscape_info *devc, int reg) -{ - unsigned long flags; - unsigned char val; - - spin_lock_irqsave(&devc->lock,flags); - outb(reg, PORT(ODIE_ADDR)); - val = inb(PORT(ODIE_DATA)); - spin_unlock_irqrestore(&devc->lock,flags); - return val; -} - -static void __sscape_write(int reg, int data) -{ - outb(reg, PORT(ODIE_ADDR)); - outb(data, PORT(ODIE_DATA)); -} - -static void sscape_write(struct sscape_info *devc, int reg, int data) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - __sscape_write(reg, data); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg) -{ - unsigned char res; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - outb( reg, devc -> codec); - res = inb (devc -> codec + 1); - spin_unlock_irqrestore(&devc->lock,flags); - return res; - -} - -static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - outb( reg, devc -> codec); - outb( data, devc -> codec + 1); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void host_open(struct sscape_info *devc) -{ - outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */ -} - -static void host_close(struct sscape_info *devc) -{ - outb((0x03), PORT(HOST_CTRL)); /* Put the board to the MIDI mode */ -} - -static int host_write(struct sscape_info *devc, unsigned char *data, int count) -{ - unsigned long flags; - int i, timeout_val; - - spin_lock_irqsave(&devc->lock,flags); - /* - * Send the command and data bytes - */ - - for (i = 0; i < count; i++) - { - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb(PORT(HOST_CTRL)) & TX_READY) - break; - - if (timeout_val <= 0) - { - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - outb(data[i], PORT(HOST_DATA)); - } - spin_unlock_irqrestore(&devc->lock,flags); - return 1; -} - -static int host_read(struct sscape_info *devc) -{ - unsigned long flags; - int timeout_val; - unsigned char data; - - spin_lock_irqsave(&devc->lock,flags); - /* - * Read a byte - */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb(PORT(HOST_CTRL)) & RX_READY) - break; - - if (timeout_val <= 0) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -1; - } - data = inb(PORT(HOST_DATA)); - spin_unlock_irqrestore(&devc->lock,flags); - return data; -} - -#if 0 /* unused */ -static int host_command1(struct sscape_info *devc, int cmd) -{ - unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - return host_write(devc, buf, 1); -} -#endif /* unused */ - - -static int host_command2(struct sscape_info *devc, int cmd, int parm1) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - - return host_write(devc, buf, 2); -} - -static int host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - buf[2] = (unsigned char) (parm2 & 0xff); - return host_write(devc, buf, 3); -} - -static void set_mt32(struct sscape_info *devc, int value) -{ - host_open(devc); - host_command2(devc, CMD_SET_MT32, value ? 1 : 0); - if (host_read(devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */ - } - host_close(devc); -} - -static void set_control(struct sscape_info *devc, int ctrl, int value) -{ - host_open(devc); - host_command3(devc, CMD_SET_CONTROL, ctrl, value); - if (host_read(devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */ - } - host_close(devc); -} - -static void do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) -{ - unsigned char temp; - - if (dma_chan != SSCAPE_DMA_A) - { - printk(KERN_WARNING "soundscape: Tried to use DMA channel != A. Why?\n"); - return; - } - audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; - DMAbuf_start_dma(devc->codec_audiodev, buf, blk_size, mode); - audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; - - temp = devc->dma << 4; /* Setup DMA channel select bits */ - if (devc->dma <= 3) - temp |= 0x80; /* 8 bit DMA channel */ - - temp |= 1; /* Trigger DMA */ - sscape_write(devc, GA_DMAA_REG, temp); - temp &= 0xfe; /* Clear DMA trigger */ - sscape_write(devc, GA_DMAA_REG, temp); -} - -static int verify_mpu(struct sscape_info *devc) -{ - /* - * The SoundScape board could be in three modes (MPU, 8250 and host). - * If the card is not in the MPU mode, enabling the MPU driver will - * cause infinite loop (the driver believes that there is always some - * received data in the buffer. - * - * Detect this by looking if there are more than 10 received MIDI bytes - * (0x00) in the buffer. - */ - - int i; - - for (i = 0; i < 10; i++) - { - if (inb(devc->base + HOST_CTRL) & 0x80) - return 1; - - if (inb(devc->base) != 0x00) - return 1; - } - printk(KERN_WARNING "SoundScape: The device is not in the MPU-401 mode\n"); - return 0; -} - -static int sscape_coproc_open(void *dev_info, int sub_device) -{ - if (sub_device == COPR_MIDI) - { - set_mt32(devc, 0); - if (!verify_mpu(devc)) - return -EIO; - } - return 0; -} - -static void sscape_coproc_close(void *dev_info, int sub_device) -{ - struct sscape_info *devc = dev_info; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - if (devc->dma_allocated) - { - __sscape_write(GA_DMAA_REG, 0x20); /* DMA channel disabled */ - devc->dma_allocated = 0; - } - spin_unlock_irqrestore(&devc->lock,flags); - return; -} - -static void sscape_coproc_reset(void *dev_info) -{ -} - -static int sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag) -{ - unsigned long flags; - unsigned char temp; - volatile int done, timeout_val; - static unsigned char codec_dma_bits; - - if (flag & CPF_FIRST) - { - /* - * First block. Have to allocate DMA and to reset the board - * before continuing. - */ - - spin_lock_irqsave(&devc->lock,flags); - codec_dma_bits = sscape_read(devc, GA_CDCFG_REG); - - if (devc->dma_allocated == 0) - devc->dma_allocated = 1; - - spin_unlock_irqrestore(&devc->lock,flags); - - sscape_write(devc, GA_HMCTL_REG, - (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - sscape_read(devc, GA_HMCTL_REG); /* Delay */ - - /* Take board out of reset */ - sscape_write(devc, GA_HMCTL_REG, - (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80); - } - /* - * Transfer one code block using DMA - */ - if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) - { - printk(KERN_WARNING "soundscape: DMA buffer not available\n"); - return 0; - } - memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); - - spin_lock_irqsave(&devc->lock,flags); - - /******** INTERRUPTS DISABLED NOW ********/ - - do_dma(devc, SSCAPE_DMA_A, - audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, - size, DMA_MODE_WRITE); - - /* - * Wait until transfer completes. - */ - - done = 0; - timeout_val = 30; - while (!done && timeout_val-- > 0) - { - int resid; - - if (HZ / 50) - sleep(HZ / 50); - clear_dma_ff(devc->dma); - if ((resid = get_dma_residue(devc->dma)) == 0) - done = 1; - } - - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - return 0; - - if (flag & CPF_LAST) - { - /* - * Take the board out of reset - */ - outb((0x00), PORT(HOST_CTRL)); - outb((0x00), PORT(MIDI_CTRL)); - - temp = sscape_read(devc, GA_HMCTL_REG); - temp |= 0x40; - sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */ - - /* - * Wait until the ODB wakes up - */ - spin_lock_irqsave(&devc->lock,flags); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - - sleep(1); - x = inb(PORT(HOST_DATA)); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - DDB(printk("Soundscape: Acknowledge = %x\n", x)); - done = 1; - } - } - sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); - - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - { - printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n"); - return 0; - } - spin_lock_irqsave(&devc->lock,flags); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - sleep(1); - if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ - done = 1; - } - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - { - printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); - return 0; - } - printk(KERN_INFO "SoundScape board initialized OK\n"); - set_control(devc, CTL_MASTER_VOL, 100); - set_control(devc, CTL_SYNTH_VOL, 100); - -#ifdef SSCAPE_DEBUG3 - /* - * Temporary debugging aid. Print contents of the registers after - * downloading the code. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); - } -#endif - - } - return 1; -} - -static int download_boot_block(void *dev_info, copr_buffer * buf) -{ - if (buf->len <= 0 || buf->len > sizeof(buf->data)) - return -EINVAL; - - if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) - { - printk(KERN_ERR "soundscape: Unable to load microcode block to the OBP.\n"); - return -EIO; - } - return 0; -} - -static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local) -{ - copr_buffer *buf; - int err; - - switch (cmd) - { - case SNDCTL_COPR_RESET: - sscape_coproc_reset(dev_info); - return 0; - - case SNDCTL_COPR_LOAD: - buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); - if (buf == NULL) - return -ENOSPC; - if (copy_from_user(buf, arg, sizeof(copr_buffer))) - { - vfree(buf); - return -EFAULT; - } - err = download_boot_block(dev_info, buf); - vfree(buf); - return err; - - default: - return -EINVAL; - } -} - -static coproc_operations sscape_coproc_operations = -{ - "SoundScape M68K", - THIS_MODULE, - sscape_coproc_open, - sscape_coproc_close, - sscape_coproc_ioctl, - sscape_coproc_reset, - &adev_info -}; - -static struct resource *sscape_ports; -static int sscape_is_pnp; - -static void __init attach_sscape(struct address_info *hw_config) -{ -#ifndef SSCAPE_REGS - /* - * Config register values for Spea/V7 Media FX and Ensoniq S-2000. - * These values are card - * dependent. If you have another SoundScape based card, you have to - * find the correct values. Do the following: - * - Compile this driver with SSCAPE_DEBUG1 defined. - * - Shut down and power off your machine. - * - Boot with DOS so that the SSINIT.EXE program is run. - * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed - * when detecting the SoundScape. - * - Modify the following list to use the values printed during boot. - * Undefine the SSCAPE_DEBUG1 - */ -#define SSCAPE_REGS { \ -/* I0 */ 0x00, \ -/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ -/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ -/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ -/* I4 */ 0xf5, /* Ignored */ \ -/* I5 */ 0x10, \ -/* I6 */ 0x00, \ -/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ -/* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \ -/* I9 */ 0x40 /* Ignored */ \ - } -#endif - - unsigned long flags; - static unsigned char regs[10] = SSCAPE_REGS; - - int i, irq_bits = 0xff; - - if (old_hardware) - { - valid_interrupts = valid_interrupts_old; - conf_printf("Ensoniq SoundScape (old)", hw_config); - } - else - conf_printf("Ensoniq SoundScape", hw_config); - - for (i = 0; i < 4; i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) - { - printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq); - release_region(devc->base, 2); - release_region(devc->base + 2, 6); - if (sscape_is_pnp) - release_region(devc->codec, 2); - return; - } - - if (!sscape_is_pnp) { - - spin_lock_irqsave(&devc->lock,flags); - /* Host interrupt enable */ - sscape_write(devc, 1, 0xf0); /* All interrupts enabled */ - /* DMA A status/trigger register */ - sscape_write(devc, 2, 0x20); /* DMA channel disabled */ - /* DMA B status/trigger register */ - sscape_write(devc, 3, 0x20); /* DMA channel disabled */ - /* Host interrupt config reg */ - sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits); - /* Don't destroy CD-ROM DMA config bits (0xc0) */ - sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0)); - /* CD-ROM config (WSS codec actually) */ - sscape_write(devc, 6, regs[6]); - sscape_write(devc, 7, regs[7]); - sscape_write(devc, 8, regs[8]); - /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ - sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08); - spin_unlock_irqrestore(&devc->lock,flags); - } -#ifdef SSCAPE_DEBUG2 - /* - * Temporary debugging aid. Print contents of the registers after - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); - } -#endif - - if (probe_mpu401(hw_config, sscape_ports)) - hw_config->always_detect = 1; - hw_config->name = "SoundScape"; - - hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401(hw_config, THIS_MODULE); - hw_config->irq *= -1; /* Restore it */ - - if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ - { - sscape_mididev = hw_config->slots[1]; - midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; - } - sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - devc->ok = 1; - devc->failed = 0; -} - -static int detect_ga(sscape_info * devc) -{ - unsigned char save; - - DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base)); - - /* - * First check that the address register of "ODIE" is - * there and that it has exactly 4 writable bits. - * First 4 bits - */ - - if ((save = inb(PORT(ODIE_ADDR))) & 0xf0) - { - DDB(printk("soundscape: Detect error A\n")); - return 0; - } - outb((0x00), PORT(ODIE_ADDR)); - if (inb(PORT(ODIE_ADDR)) != 0x00) - { - DDB(printk("soundscape: Detect error B\n")); - return 0; - } - outb((0xff), PORT(ODIE_ADDR)); - if (inb(PORT(ODIE_ADDR)) != 0x0f) - { - DDB(printk("soundscape: Detect error C\n")); - return 0; - } - outb((save), PORT(ODIE_ADDR)); - - /* - * Now verify that some indirect registers return zero on some bits. - * This may break the driver with some future revisions of "ODIE" but... - */ - - if (sscape_read(devc, 0) & 0x0c) - { - DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0))); - return 0; - } - if (sscape_read(devc, 1) & 0x0f) - { - DDB(printk("soundscape: Detect error E\n")); - return 0; - } - if (sscape_read(devc, 5) & 0x0f) - { - DDB(printk("soundscape: Detect error F\n")); - return 0; - } - return 1; -} - -static int sscape_read_host_ctrl(sscape_info* devc) -{ - return host_read(devc); -} - -static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b) -{ - host_command2(devc, a, b); -} - -static int sscape_alloc_dma(sscape_info *devc) -{ - char *start_addr, *end_addr; - int dma_pagesize; - int sz, size; - struct page *page; - - if (devc->raw_buf != NULL) return 0; /* Already done */ - dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024); - devc->raw_buf = NULL; - devc->buffsize = 8192*4; - if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize; - start_addr = NULL; - /* - * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. Don't accept smaller than 8k buffer for performance - * reasons. - */ - while (start_addr == NULL && devc->buffsize > PAGE_SIZE) { - for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); - devc->buffsize = PAGE_SIZE * (1 << sz); - start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); - if (start_addr == NULL) devc->buffsize /= 2; - } - - if (start_addr == NULL) { - printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n"); - return 0; - } else { - /* make some checks */ - end_addr = start_addr + devc->buffsize - 1; - /* now check if it fits into the same dma-pagesize */ - - if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) { - printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize); - return 0; - } - } - devc->raw_buf = start_addr; - devc->raw_buf_phys = virt_to_bus(start_addr); - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - SetPageReserved(page); - return 1; -} - -static void sscape_free_dma(sscape_info *devc) -{ - int sz, size; - unsigned long start_addr, end_addr; - struct page *page; - - if (devc->raw_buf == NULL) return; - for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); - start_addr = (unsigned long) devc->raw_buf; - end_addr = start_addr + devc->buffsize; - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - ClearPageReserved(page); - - free_pages((unsigned long) devc->raw_buf, sz); - devc->raw_buf = NULL; -} - -/* Intel version !!!!!!!!! */ - -static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode) -{ - unsigned long flags; - - flags = claim_dma_lock(); - disable_dma(chan); - clear_dma_ff(chan); - set_dma_mode(chan, dma_mode); - set_dma_addr(chan, physaddr); - set_dma_count(chan, count); - enable_dma(chan); - release_dma_lock(flags); - return 0; -} - -static void sscape_pnp_start_dma(sscape_info* devc, int arg ) -{ - int reg; - if (arg == 0) reg = 2; - else reg = 3; - - sscape_write(devc, reg, sscape_read( devc, reg) | 0x01); - sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE); -} - -static int sscape_pnp_wait_dma (sscape_info* devc, int arg ) -{ - int reg; - unsigned long i; - unsigned char d; - - if (arg == 0) reg = 2; - else reg = 3; - - sleep ( 1 ); - i = 0; - do { - d = sscape_read(devc, reg) & 1; - if ( d == 1) break; - i++; - } while (i < 500000); - d = sscape_read(devc, reg) & 1; - return d; -} - -static int sscape_pnp_alloc_dma(sscape_info* devc) -{ - /* printk(KERN_INFO "sscape: requesting dma\n"); */ - if (request_dma(devc -> dma, "sscape")) return 0; - /* printk(KERN_INFO "sscape: dma channel allocated\n"); */ - if (!sscape_alloc_dma(devc)) { - free_dma(devc -> dma); - return 0; - }; - return 1; -} - -static void sscape_pnp_free_dma(sscape_info* devc) -{ - sscape_free_dma( devc); - free_dma(devc -> dma ); - /* printk(KERN_INFO "sscape: dma released\n"); */ -} - -static int sscape_pnp_upload_file(sscape_info* devc, char* fn) -{ - int done = 0; - int timeout_val; - char* data,*dt; - int len,l; - unsigned long flags; - - sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F ); - sscape_write( devc, 2, (devc -> dma << 4) | 0x80 ); - sscape_write( devc, 3, 0x20 ); - sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 ); - - len = mod_firmware_load(fn, &data); - if (len == 0) { - printk(KERN_ERR "sscape: file not found: %s\n", fn); - return 0; - } - dt = data; - spin_lock_irqsave(&devc->lock,flags); - while ( len > 0 ) { - if (len > devc -> buffsize) l = devc->buffsize; - else l = len; - len -= l; - memcpy(devc->raw_buf, dt, l); dt += l; - sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48); - sscape_pnp_start_dma ( devc, 0 ); - if (sscape_pnp_wait_dma ( devc, 0 ) == 0) { - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - } - - spin_unlock_irqrestore(&devc->lock,flags); - vfree(data); - - outb(0, devc -> base + 2); - outb(0, devc -> base); - - sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40); - - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - sleep(1); - x = inb( devc -> base + 3); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); - done = 1; - } - } - timeout_val = 5 * HZ; - done = 0; - while (!done && timeout_val-- > 0) - { - unsigned char x; - sleep(1); - x = inb( devc -> base + 3); - if (x == 0xfe) /* OBP startup acknowledge */ - { - //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); - done = 1; - } - } - - if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); - - sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); - sscape_write( devc, 3, (devc -> dma << 4) + 0x80); - return 1; -} - -static void __init sscape_pnp_init_hw(sscape_info* devc) -{ - unsigned char midi_irq = 0, sb_irq = 0; - unsigned i; - static char code_file_name[23] = "/sndscape/sndscape.cox"; - - int sscape_joystic_enable = 0x7f; - int sscape_mic_enable = 0; - int sscape_ext_midi = 0; - - if ( !sscape_pnp_alloc_dma(devc) ) { - printk(KERN_ERR "sscape: faild to allocate dma\n"); - return; - } - - for (i = 0; i < 4; i++) { - if ( devc -> irq == valid_interrupts[i] ) - midi_irq = i; - if ( devc -> codec_irq == valid_interrupts[i] ) - sb_irq = i; - } - - sscape_write( devc, 5, 0x50); - sscape_write( devc, 7, 0x2e); - sscape_write( devc, 8, 0x00); - - sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); - sscape_write( devc, 3, ( devc -> dma << 4) | 0x80); - - sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); - - i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0); - if (sscape_joystic_enable) i |= 8; - - sscape_write (devc, 9, i); - sscape_write (devc, 6, 0x80); - sscape_write (devc, 1, 0x80); - - if (devc -> codec_type == 2) { - sscape_pnp_write_codec( devc, 0x0C, 0x50); - sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F); - sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0); - sscape_pnp_write_codec( devc, 29, 0x20); - } - - if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) { - printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n"); - sscape_pnp_free_dma(devc); - return; - } - - i = sscape_read_host_ctrl( devc ); - - if ( (i & 0x0F) > 7 ) { - printk(KERN_ERR "sscape: scope.cod faild\n"); - sscape_pnp_free_dma(devc); - return; - } - if ( i & 0x10 ) sscape_write( devc, 7, 0x2F); - code_file_name[21] = (char) ( i & 0x0F) + 0x30; - if (sscape_pnp_upload_file( devc, code_file_name) == 0) { - printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name); - sscape_pnp_free_dma(devc); - return; - } - - if (devc->ic_type != IC_ODIE) { - sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) | - ( sscape_mic_enable == 0 ? 0x00 : 0x80) ); - } - sscape_write_host_ctrl2( devc, 0x84, 0x64 ); /* MIDI volume */ - sscape_write_host_ctrl2( devc, 0x86, 0x64 ); /* MIDI volume?? */ - sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi); - - sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL - sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL - sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL - sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR - - if (devc -> codec_type == 1) { - sscape_pnp_write_codec ( devc, 4, 0x1F ); - sscape_pnp_write_codec ( devc, 5, 0x1F ); - sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable); - } else { - int t; - sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1); - sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1)); - - t = sscape_pnp_read_codec( devc, 0x00) & 0xDF; - if ( (sscape_mic_enable == 0)) t |= 0; - else t |= 0x20; - sscape_pnp_write_codec ( devc, 0x00, t); - t = sscape_pnp_read_codec( devc, 0x01) & 0xDF; - if ( (sscape_mic_enable == 0) ) t |= 0; - else t |= 0x20; - sscape_pnp_write_codec ( devc, 0x01, t); - sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20); - outb(0, devc -> codec); - } - if (devc -> ic_type == IC_OPUS ) { - int i = sscape_read( devc, 9 ); - sscape_write( devc, 9, i | 3 ); - sscape_write( devc, 3, 0x40); - - if (request_region(0x228, 1, "sscape setup junk")) { - outb(0, 0x228); - release_region(0x228,1); - } - sscape_write( devc, 3, (devc -> dma << 4) | 0x80); - sscape_write( devc, 9, i ); - } - - host_close ( devc ); - sscape_pnp_free_dma(devc); -} - -static int __init detect_sscape_pnp(sscape_info* devc) -{ - long i, irq_bits = 0xff; - unsigned int d; - - DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base)); - - if (!request_region(devc->codec, 2, "sscape codec")) { - printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec); - return 0; - } - - if ((inb(devc->base + 2) & 0x78) != 0) - goto fail; - - d = inb ( devc -> base + 4) & 0xF0; - if (d & 0x80) - goto fail; - - if (d == 0) { - devc->codec_type = 1; - devc->ic_type = IC_ODIE; - } else if ( (d & 0x60) != 0) { - devc->codec_type = 2; - devc->ic_type = IC_OPUS; - } else if ( (d & 0x40) != 0) { /* WTF? */ - devc->codec_type = 2; - devc->ic_type = IC_ODIE; - } else - goto fail; - - sscape_is_pnp = 1; - - outb(0xFA, devc -> base+4); - if ((inb( devc -> base+4) & 0x9F) != 0x0A) - goto fail; - outb(0xFE, devc -> base+4); - if ( (inb(devc -> base+4) & 0x9F) != 0x0E) - goto fail; - if ( (inb(devc -> base+5) & 0x9F) != 0x0E) - goto fail; - - if (devc->codec_type == 2) { - if (devc->codec != devc->base + 8) { - printk("soundscape warning: incorrect codec port specified\n"); - goto fail; - } - d = 0x10 | (sscape_read(devc, 9) & 0xCF); - sscape_write(devc, 9, d); - sscape_write(devc, 6, 0x80); - } else { - //todo: check codec is not base + 8 - } - - d = (sscape_read(devc, 9) & 0x3F) | 0xC0; - sscape_write(devc, 9, d); - - for (i = 0; i < 550000; i++) - if ( !(inb(devc -> codec) & 0x80) ) break; - - d = inb(devc -> codec); - if (d & 0x80) - goto fail; - if ( inb(devc -> codec + 2) == 0xFF) - goto fail; - - sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F ); - - d = inb(devc -> codec) & 0x80; - if ( d == 0) { - printk(KERN_INFO "soundscape: hardware detected\n"); - valid_interrupts = valid_interrupts_new; - } else { - printk(KERN_INFO "soundscape: board looks like media fx\n"); - valid_interrupts = valid_interrupts_old; - old_hardware = 1; - } - - sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9) & 0x3F) ); - - for (i = 0; i < 550000; i++) - if ( !(inb(devc -> codec) & 0x80)) - break; - - sscape_pnp_init_hw(devc); - - for (i = 0; i < 4; i++) - { - if (devc->codec_irq == valid_interrupts[i]) { - irq_bits = i; - break; - } - } - sscape_write(devc, GA_INTENA_REG, 0x00); - sscape_write(devc, GA_DMACFG_REG, 0x50); - sscape_write(devc, GA_DMAA_REG, 0x70); - sscape_write(devc, GA_DMAB_REG, 0x20); - sscape_write(devc, GA_INTCFG_REG, 0xf0); - sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1)); - - sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20); - sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20); - - return 1; -fail: - release_region(devc->codec, 2); - return 0; -} - -static int __init probe_sscape(struct address_info *hw_config) -{ - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - -#ifdef SSCAPE_DEBUG1 - /* - * Temporary debugging aid. Print contents of the registers before - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (old value)\n", i, sscape_read(devc, i)); - } -#endif - devc->failed = 1; - - sscape_ports = request_region(devc->base, 2, "mpu401"); - if (!sscape_ports) - return 0; - - if (!request_region(devc->base + 2, 6, "SoundScape")) { - release_region(devc->base, 2); - return 0; - } - - if (!detect_ga(devc)) { - if (detect_sscape_pnp(devc)) - return 1; - release_region(devc->base, 2); - release_region(devc->base + 2, 6); - return 0; - } - - if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ - { - unsigned char tmp; - int cc; - - if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0)) - { - sscape_write(devc, GA_HMCTL_REG, tmp | 0x80); - for (cc = 0; cc < 200000; ++cc) - inb(devc->base + ODIE_ADDR); - } - } - return 1; -} - -static int __init init_ss_ms_sound(struct address_info *hw_config) -{ - int i, irq_bits = 0xff; - int ad_flags = 0; - struct resource *ports; - - if (devc->failed) - { - printk(KERN_ERR "soundscape: Card not detected\n"); - return 0; - } - if (devc->ok == 0) - { - printk(KERN_ERR "soundscape: Invalid initialization order.\n"); - return 0; - } - for (i = 0; i < 4; i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - if (irq_bits == 0xff) { - printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq); - return 0; - } - - if (old_hardware) - ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ - else if (sscape_is_pnp) - ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */ - - ports = request_region(hw_config->io_base, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "soundscape: ports busy\n"); - return 0; - } - - if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) { - release_region(hw_config->io_base, 4); - return 0; - } - - if (!sscape_is_pnp) /*pnp is already setup*/ - { - /* - * Setup the DMA polarity. - */ - sscape_write(devc, GA_DMACFG_REG, 0x50); - - /* - * Take the gate-array off of the DMA channel. - */ - sscape_write(devc, GA_DMAB_REG, 0x20); - - /* - * Init the AD1848 (CD-ROM) config reg. - */ - sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1)); - } - - if (hw_config->irq == devc->irq) - printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); - - hw_config->slots[0] = ad1848_init( - sscape_is_pnp ? "SoundScape" : "SoundScape PNP", - ports, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp, - THIS_MODULE); - - - if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ - { - audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations; - devc->codec_audiodev = hw_config->slots[0]; - devc->my_audiodev = hw_config->slots[0]; - - /* Set proper routings here (what are they) */ - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - } - -#ifdef SSCAPE_DEBUG5 - /* - * Temporary debugging aid. Print contents of the registers - * after the AD1848 device has been initialized. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x\n", i, sscape_read(devc, i)); - } -#endif - return 1; -} - -static void __exit unload_sscape(struct address_info *hw_config) -{ - release_region(devc->base + 2, 6); - unload_mpu401(hw_config); - if (sscape_is_pnp) - release_region(devc->codec, 2); -} - -static void __exit unload_ss_ms_sound(struct address_info *hw_config) -{ - ad1848_unload(hw_config->io_base, - hw_config->irq, - devc->dma, - devc->dma, - 0); - sound_unload_audiodev(hw_config->slots[0]); -} - -static struct address_info cfg; -static struct address_info cfg_mpu; - -static int __initdata spea = -1; -static int mss = 0; -static int __initdata dma = -1; -static int __initdata irq = -1; -static int __initdata io = -1; -static int __initdata mpu_irq = -1; -static int __initdata mpu_io = -1; - -module_param(dma, int, 0); -module_param(irq, int, 0); -module_param(io, int, 0); -module_param(spea, int, 0); /* spea=0/1 set the old_hardware */ -module_param(mpu_irq, int, 0); -module_param(mpu_io, int, 0); -module_param(mss, int, 0); - -static int __init init_sscape(void) -{ - printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.irq = irq; - cfg.dma = dma; - cfg.io_base = io; - - cfg_mpu.irq = mpu_irq; - cfg_mpu.io_base = mpu_io; - /* WEH - Try to get right dma channel */ - cfg_mpu.dma = dma; - - devc->codec = cfg.io_base; - devc->codec_irq = cfg.irq; - devc->codec_type = 0; - devc->ic_type = 0; - devc->raw_buf = NULL; - spin_lock_init(&devc->lock); - - if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) { - printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n"); - return -EINVAL; - } - - if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) { - printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n"); - return -EINVAL; - } - - if(spea != -1) { - old_hardware = spea; - printk(KERN_INFO "Forcing %s hardware support.\n", - spea?"new":"old"); - } - if (probe_sscape(&cfg_mpu) == 0) - return -ENODEV; - - attach_sscape(&cfg_mpu); - - mss = init_ss_ms_sound(&cfg); - - return 0; -} - -static void __exit cleanup_sscape(void) -{ - if (mss) - unload_ss_ms_sound(&cfg); - unload_sscape(&cfg_mpu); -} - -module_init(init_sscape); -module_exit(cleanup_sscape); - -#ifndef MODULE -static int __init setup_sscape(char *str) -{ - /* io, irq, dma, mpu_io, mpu_irq */ - int ints[6]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - mpu_io = ints[4]; - mpu_irq = ints[5]; - - return 1; -} - -__setup("sscape=", setup_sscape); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 75c602b5b13..351654cf7b0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -570,6 +570,7 @@ config SND_ICE1712 tristate "ICEnsemble ICE1712 (Envy24)" select SND_MPU401_UART select SND_AC97_CODEC + select BITREVERSE help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c62b7d10ec6..15523e60351 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -304,7 +304,7 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { + if (reg < 0x40 && val <= 0xffffffff) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -405,7 +405,7 @@ static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) + if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3) snd_ca0106_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 75454648d50..cb65bd0dd35 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -240,7 +240,7 @@ static int select_rom(unsigned int pitch) } else if (pitch == 0x02000000) { /* pitch == 2 */ return 3; - } else if (pitch >= 0x0 && pitch <= 0x08000000) { + } else if (pitch <= 0x08000000) { /* 0 <= pitch <= 8 */ return 0; } else { diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 36e08bd2b3c..6b8ae7b5cd5 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1040,8 +1040,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) - && (channel_id >= 0) && (channel_id <= 2) ) + if (reg < 0x49 && val <= 0xffffffff && channel_id <= 2) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 216f9748aff..baa7cd508cd 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -451,7 +451,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) { + if (reg < 0x40 && val <= 0xffffffff) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -527,7 +527,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) ) + if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3) snd_ptr_write(emu, iobase, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index c1a5aa15af8..5ef7080e14d 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -256,7 +256,7 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ - if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ + if (value > 0x3f) /* 0 to 0x3f are values */ return 1; spin_lock_irqsave(&emu->emu_lock, flags); outl(reg, emu->port + A_IOCFG); diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9ae..f5020ad99a1 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -504,6 +504,31 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) } /* + * suspend/resume + * */ + +#ifdef CONFIG_PM +static int juli_resume(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + struct juli_spec *spec = ice->spec; + /* akm4358 un-reset, un-mute */ + snd_akm4xxx_reset(ak, 0); + /* reinit ak4114 */ + snd_ak4114_reinit(spec->ak4114); + return 0; +} + +static int juli_suspend(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + /* akm4358 reset and soft-mute */ + snd_akm4xxx_reset(ak, 1); + return 0; +} +#endif + +/* * initialize the chip */ @@ -646,6 +671,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice) ice->set_spdif_clock = juli_set_spdif_clock; ice->spdif.ops.open = juli_spdif_in_open; + +#ifdef CONFIG_PM + ice->pm_resume = juli_resume; + ice->pm_suspend = juli_suspend; + ice->pm_suspend_enabled = 1; +#endif + return 0; } diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index aac20fb4aad..b990143636f 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2063,6 +2063,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .type = AC97_TUNE_HP_ONLY }, { + .subvendor = 0x161f, + .subdevice = 0x203a, + .name = "Gateway 4525GZ", /* AD1981B */ + .type = AC97_TUNE_INV_EAPD + }, + { .subvendor = 0x1734, .subdevice = 0x0088, .name = "Fujitsu-Siemens D1522", /* AD1981 */ diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig index aed0f90c391..61139f3c161 100644 --- a/sound/sh/Kconfig +++ b/sound/sh/Kconfig @@ -19,5 +19,13 @@ config SND_AICA help ALSA Sound driver for the SEGA Dreamcast console. +config SND_SH_DAC_AUDIO + tristate "SuperH DAC audio support" + depends on SND + depends on CPU_SH3 && HIGH_RES_TIMERS + select SND_PCM + help + Say Y here to include support for the on-chip DAC. + endif # SND_SUPERH diff --git a/sound/sh/Makefile b/sound/sh/Makefile index 8fdcb6e26f0..7d09b5188cf 100644 --- a/sound/sh/Makefile +++ b/sound/sh/Makefile @@ -3,6 +3,8 @@ # snd-aica-objs := aica.o +snd-sh_dac_audio-objs := sh_dac_audio.o # Toplevel Module Dependency obj-$(CONFIG_SND_AICA) += snd-aica.o +obj-$(CONFIG_SND_SH_DAC_AUDIO) += snd-sh_dac_audio.o diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c new file mode 100644 index 00000000000..76d9ad27d91 --- /dev/null +++ b/sound/sh/sh_dac_audio.c @@ -0,0 +1,453 @@ +/* + * sh_dac_audio.c - SuperH DAC audio driver for ALSA + * + * Copyright (c) 2009 by Rafael Ignacio Zurita <rizurita@yahoo.com> + * + * + * Based on sh_dac_audio.c (Copyright (C) 2004, 2005 by Andriy Skulysh) + * + * 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/hrtimer.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/sh_dac_audio.h> +#include <asm/clock.h> +#include <asm/hd64461.h> +#include <mach/hp6xx.h> +#include <cpu/dac.h> + +MODULE_AUTHOR("Rafael Ignacio Zurita <rizurita@yahoo.com>"); +MODULE_DESCRIPTION("SuperH DAC audio driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{SuperH DAC audio support}}"); + +/* Module Parameters */ +static int index = SNDRV_DEFAULT_IDX1; +static char *id = SNDRV_DEFAULT_STR1; +module_param(index, int, 0444); +MODULE_PARM_DESC(index, "Index value for SuperH DAC audio."); +module_param(id, charp, 0444); +MODULE_PARM_DESC(id, "ID string for SuperH DAC audio."); + +/* main struct */ +struct snd_sh_dac { + struct snd_card *card; + struct snd_pcm_substream *substream; + struct hrtimer hrtimer; + ktime_t wakeups_per_second; + + int rate; + int empty; + char *data_buffer, *buffer_begin, *buffer_end; + int processed; /* bytes proccesed, to compare with period_size */ + int buffer_size; + struct dac_audio_pdata *pdata; +}; + + +static void dac_audio_start_timer(struct snd_sh_dac *chip) +{ + hrtimer_start(&chip->hrtimer, chip->wakeups_per_second, + HRTIMER_MODE_REL); +} + +static void dac_audio_stop_timer(struct snd_sh_dac *chip) +{ + hrtimer_cancel(&chip->hrtimer); +} + +static void dac_audio_reset(struct snd_sh_dac *chip) +{ + dac_audio_stop_timer(chip); + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; +} + +static void dac_audio_set_rate(struct snd_sh_dac *chip) +{ + chip->wakeups_per_second = ktime_set(0, 1000000000 / chip->rate); +} + + +/* PCM INTERFACE */ + +static struct snd_pcm_hardware snd_sh_dac_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_HALF_DUPLEX), + .formats = SNDRV_PCM_FMTBIT_U8, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = (48*1024), + .period_bytes_min = 1, + .period_bytes_max = (48*1024), + .periods_min = 1, + .periods_max = 1024, +}; + +static int snd_sh_dac_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw = snd_sh_dac_pcm_hw; + + chip->substream = substream; + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; + + chip->pdata->start(chip->pdata); + + return 0; +} + +static int snd_sh_dac_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + + chip->substream = NULL; + + dac_audio_stop_timer(chip); + chip->pdata->stop(chip->pdata); + + return 0; +} + +static int snd_sh_dac_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int snd_sh_dac_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_sh_dac_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = chip->substream->runtime; + + chip->buffer_size = runtime->buffer_size; + memset(chip->data_buffer, 0, chip->pdata->buffer_size); + + return 0; +} + +static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + dac_audio_start_timer(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; + dac_audio_stop_timer(chip); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t b_count = frames_to_bytes(runtime , count); + ssize_t b_pos = frames_to_bytes(runtime , pos); + + if (count < 0) + return -EINVAL; + + if (!count) + return 0; + + memcpy_toio(chip->data_buffer + b_pos, src, b_count); + chip->buffer_end = chip->data_buffer + b_pos + b_count; + + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } + + return 0; +} + +static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, + int channel, snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t b_count = frames_to_bytes(runtime , count); + ssize_t b_pos = frames_to_bytes(runtime , pos); + + if (count < 0) + return -EINVAL; + + if (!count) + return 0; + + memset_io(chip->data_buffer + b_pos, 0, b_count); + chip->buffer_end = chip->data_buffer + b_pos + b_count; + + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } + + return 0; +} + +static +snd_pcm_uframes_t snd_sh_dac_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + int pointer = chip->buffer_begin - chip->data_buffer; + + return pointer; +} + +/* pcm ops */ +static struct snd_pcm_ops snd_sh_dac_pcm_ops = { + .open = snd_sh_dac_pcm_open, + .close = snd_sh_dac_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_sh_dac_pcm_hw_params, + .hw_free = snd_sh_dac_pcm_hw_free, + .prepare = snd_sh_dac_pcm_prepare, + .trigger = snd_sh_dac_pcm_trigger, + .pointer = snd_sh_dac_pcm_pointer, + .copy = snd_sh_dac_pcm_copy, + .silence = snd_sh_dac_pcm_silence, + .mmap = snd_pcm_lib_mmap_iomem, +}; + +static int __devinit snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) +{ + int err; + struct snd_pcm *pcm; + + /* device should be always 0 for us */ + err = snd_pcm_new(chip->card, "SH_DAC PCM", device, 1, 0, &pcm); + if (err < 0) + return err; + + pcm->private_data = chip; + strcpy(pcm->name, "SH_DAC PCM"); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops); + + /* buffer size=48K */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 48 * 1024, + 48 * 1024); + + return 0; +} +/* END OF PCM INTERFACE */ + + +/* driver .remove -- destructor */ +static int snd_sh_dac_remove(struct platform_device *devptr) +{ + snd_card_free(platform_get_drvdata(devptr)); + platform_set_drvdata(devptr, NULL); + + return 0; +} + +/* free -- it has been defined by create */ +static int snd_sh_dac_free(struct snd_sh_dac *chip) +{ + /* release the data */ + kfree(chip->data_buffer); + kfree(chip); + + return 0; +} + +static int snd_sh_dac_dev_free(struct snd_device *device) +{ + struct snd_sh_dac *chip = device->device_data; + + return snd_sh_dac_free(chip); +} + +static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) +{ + struct snd_sh_dac *chip = container_of(handle, struct snd_sh_dac, + hrtimer); + struct snd_pcm_runtime *runtime = chip->substream->runtime; + ssize_t b_ps = frames_to_bytes(runtime, runtime->period_size); + + if (!chip->empty) { + sh_dac_output(*chip->buffer_begin, chip->pdata->channel); + chip->buffer_begin++; + + chip->processed++; + if (chip->processed >= b_ps) { + chip->processed -= b_ps; + snd_pcm_period_elapsed(chip->substream); + } + + if (chip->buffer_begin == (chip->data_buffer + + chip->buffer_size - 1)) + chip->buffer_begin = chip->data_buffer; + + if (chip->buffer_begin == chip->buffer_end) + chip->empty = 1; + + } + + if (!chip->empty) + hrtimer_start(&chip->hrtimer, chip->wakeups_per_second, + HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +/* create -- chip-specific constructor for the cards components */ +static int __devinit snd_sh_dac_create(struct snd_card *card, + struct platform_device *devptr, + struct snd_sh_dac **rchip) +{ + struct snd_sh_dac *chip; + int err; + + static struct snd_device_ops ops = { + .dev_free = snd_sh_dac_dev_free, + }; + + *rchip = NULL; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->card = card; + + hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->hrtimer.function = sh_dac_audio_timer; + + dac_audio_reset(chip); + chip->rate = 8000; + dac_audio_set_rate(chip); + + chip->pdata = devptr->dev.platform_data; + + chip->data_buffer = kmalloc(chip->pdata->buffer_size, GFP_KERNEL); + if (chip->data_buffer == NULL) { + kfree(chip); + return -ENOMEM; + } + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_sh_dac_free(chip); + return err; + } + + *rchip = chip; + + return 0; +} + +/* driver .probe -- constructor */ +static int __devinit snd_sh_dac_probe(struct platform_device *devptr) +{ + struct snd_sh_dac *chip; + struct snd_card *card; + int err; + + err = snd_card_create(index, id, THIS_MODULE, 0, &card); + if (err < 0) { + snd_printk(KERN_ERR "cannot allocate the card\n"); + return err; + } + + err = snd_sh_dac_create(card, devptr, &chip); + if (err < 0) + goto probe_error; + + err = snd_sh_dac_pcm(chip, 0); + if (err < 0) + goto probe_error; + + strcpy(card->driver, "snd_sh_dac"); + strcpy(card->shortname, "SuperH DAC audio driver"); + printk(KERN_INFO "%s %s", card->longname, card->shortname); + + err = snd_card_register(card); + if (err < 0) + goto probe_error; + + snd_printk("ALSA driver for SuperH DAC audio"); + + platform_set_drvdata(devptr, card); + return 0; + +probe_error: + snd_card_free(card); + return err; +} + +/* + * "driver" definition + */ +static struct platform_driver driver = { + .probe = snd_sh_dac_probe, + .remove = snd_sh_dac_remove, + .driver = { + .name = "dac_audio", + }, +}; + +static int __init sh_dac_init(void) +{ + return platform_driver_register(&driver); +} + +static void __exit sh_dac_exit(void) +{ + platform_driver_unregister(&driver); +} + +module_init(sh_dac_init); +module_exit(sh_dac_exit); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 90a0264f753..58ffb6de400 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -85,7 +85,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, * of data into val */ - if ((reg < 0 || reg > 9) && (reg != 15)) { + if (reg > 9 && reg != 15) { printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg); return -1; } diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8db0374e10d..b074a594c59 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2893,7 +2893,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { - if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) { + int err = snd_usbmidi_create(chip->card, iface, + &chip->midi_list, NULL); + if (err < 0) { snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); continue; } @@ -3038,12 +3040,11 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &uaxx_ep }; - if (chip->usb_id == USB_ID(0x0582, 0x002b)) - return snd_usb_create_midi_interface(chip, iface, - &ua700_quirk); - else - return snd_usb_create_midi_interface(chip, iface, - &uaxx_quirk); + const struct snd_usb_audio_quirk *quirk = + chip->usb_id == USB_ID(0x0582, 0x002b) + ? &ua700_quirk : &uaxx_quirk; + return snd_usbmidi_create(chip->card, iface, + &chip->midi_list, quirk); } if (altsd->bNumEndpoints != 1) @@ -3370,6 +3371,13 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, return 0; /* keep this altsetting */ } +static int create_any_midi_quirk(struct snd_usb_audio *chip, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk) +{ + return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); +} + /* * audio-interface quirks * @@ -3387,14 +3395,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, static const quirk_func_t quirk_funcs[] = { [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, [QUIRK_COMPOSITE] = create_composite_quirk, - [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, - [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, - [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, - [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, - [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, + [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, + [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, + [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, + [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, + [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, + [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, + [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index e9a3a9dca15..40ba8115fb8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -132,7 +132,6 @@ struct snd_usb_audio { int pcm_devs; struct list_head midi_list; /* list of midi interfaces */ - int next_midi_device; struct list_head mixer_list; /* list of mixer interfaces */ }; @@ -227,8 +226,10 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error); void snd_usb_mixer_disconnect(struct list_head *p); -int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk); +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface *iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 0eff19ceb7e..6e89b8368d9 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1,7 +1,7 @@ /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002-2007 Clemens Ladisch + * Copyright (c) 2002-2009 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -47,6 +47,7 @@ #include <linux/usb.h> #include <linux/wait.h> #include <sound/core.h> +#include <sound/control.h> #include <sound/rawmidi.h> #include <sound/asequencer.h> #include "usbaudio.h" @@ -101,7 +102,8 @@ struct usb_protocol_ops { }; struct snd_usb_midi { - struct snd_usb_audio *chip; + struct usb_device *dev; + struct snd_card *card; struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; @@ -109,13 +111,19 @@ struct snd_usb_midi { struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; + struct mutex mutex; + u32 usb_id; + int next_midi_device; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned int opened; unsigned char disconnected; + + struct snd_kcontrol *roland_load_ctl; }; struct snd_usb_midi_out_endpoint { @@ -255,7 +263,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) } } - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } @@ -296,7 +304,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->umidi->chip->shutdown) { + if (ep->umidi->disconnected) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } @@ -312,7 +320,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) dump_urb("sending", urb->transfer_buffer, urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) break; ep->active_urbs |= 1 << urb_index; @@ -349,7 +357,7 @@ static void snd_usbmidi_error_timer(unsigned long data) if (in && in->error_resubmit) { in->error_resubmit = 0; for (j = 0; j < INPUT_URBS; ++j) { - in->urbs[j]->dev = umidi->chip->dev; + in->urbs[j]->dev = umidi->dev; snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); } } @@ -369,7 +377,7 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, return -ENOMEM; dump_urb("sending", buf, len); if (ep->urbs[0].urb) - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe, + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, buf, len, NULL, 250); kfree(buf); return err; @@ -724,8 +732,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, if (!ep->ports[0].active) return; - count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH - ? 1 : 2; + count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; count = snd_rawmidi_transmit(ep->ports[0].substream, urb->transfer_buffer, count); @@ -879,6 +886,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { }; +static void update_roland_altsetting(struct snd_usb_midi* umidi) +{ + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + int is_light_load; + + intf = umidi->iface; + is_light_load = intf->cur_altsetting != intf->altsetting; + if (umidi->roland_load_ctl->private_value == is_light_load) + return; + hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; + intfd = get_iface_desc(hostif); + snd_usbmidi_input_stop(&umidi->list); + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + snd_usbmidi_input_start(&umidi->list); +} + +static void substream_open(struct snd_rawmidi_substream *substream, int open) +{ + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; + + mutex_lock(&umidi->mutex); + if (open) { + if (umidi->opened++ == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + update_roland_altsetting(umidi); + } + } else { + if (--umidi->opened == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + } + mutex_unlock(&umidi->mutex); +} + static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; @@ -898,11 +949,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) } substream->runtime->private_data = port; port->state = STATE_UNKNOWN; + substream_open(substream, 1); return 0; } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -912,7 +965,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, port->active = up; if (up) { - if (port->ep->umidi->chip->shutdown) { + if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ while (!snd_rawmidi_transmit_empty(substream)) @@ -954,11 +1007,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { + substream_open(substream, 1); return 0; } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -988,7 +1043,7 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, unsigned int buffer_length) { - usb_buffer_free(umidi->chip->dev, buffer_length, + usb_buffer_free(umidi->dev, buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } @@ -1035,24 +1090,24 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, } } if (ep_info->in_interval) - pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); + pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep); else - pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); - length = usb_maxpacket(umidi->chip->dev, pipe, 0); + pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep); + length = usb_maxpacket(umidi->dev, pipe, 0); for (i = 0; i < INPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, + buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL, &ep->urbs[i]->transfer_dma); if (!buffer) { snd_usbmidi_in_endpoint_delete(ep); return -ENOMEM; } if (ep_info->in_interval) - usb_fill_int_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep, ep_info->in_interval); else - usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep); ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; @@ -1062,15 +1117,6 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, return 0; } -static unsigned int snd_usbmidi_count_bits(unsigned int x) -{ - unsigned int bits; - - for (bits = 0; x; ++bits) - x &= x - 1; - return bits; -} - /* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. @@ -1113,15 +1159,15 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, ep->urbs[i].ep = ep; } if (ep_info->out_interval) - pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); else - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); - if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ + pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); + if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ ep->max_transfer = 4; else - ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); + ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); for (i = 0; i < OUTPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, + buffer = usb_buffer_alloc(umidi->dev, ep->max_transfer, GFP_KERNEL, &ep->urbs[i].urb->transfer_dma); if (!buffer) { @@ -1129,12 +1175,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; } if (ep_info->out_interval) - usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i], ep_info->out_interval); else - usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i]); @@ -1172,6 +1218,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } + mutex_destroy(&umidi->mutex); kfree(umidi); } @@ -1367,7 +1414,7 @@ static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) int i; for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { - if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && + if (snd_usbmidi_port_info[i].id == umidi->usb_id && snd_usbmidi_port_info[i].port == number) return &snd_usbmidi_port_info[i]; } @@ -1405,7 +1452,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, port_info = find_port_info(umidi, number); name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), - name_format, umidi->chip->card->shortname, number + 1); + name_format, umidi->card->shortname, number + 1); *rsubstream = substream; } @@ -1503,7 +1550,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].out_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].out_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) /* * Low speed bulk transfers don't exist, so * force interrupt transfers for devices like @@ -1523,7 +1570,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].in_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", @@ -1533,6 +1580,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, return 0; } +static int roland_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "High Load", "Light Load" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item > 1) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int roland_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int roland_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_usb_midi* umidi = kcontrol->private_data; + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + mutex_lock(&umidi->mutex); + changed = value->value.enumerated.item[0] != kcontrol->private_value; + if (changed) + kcontrol->private_value = value->value.enumerated.item[0]; + mutex_unlock(&umidi->mutex); + return changed; +} + +static struct snd_kcontrol_new roland_load_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI Input Mode", + .info = roland_load_info, + .get = roland_load_get, + .put = roland_load_put, + .private_value = 1, +}; + /* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. @@ -1556,8 +1649,12 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", intfd->bAlternateSetting); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); + + umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); + if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0) + umidi->roland_load_ctl = NULL; } /* @@ -1573,7 +1670,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) + if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) @@ -1760,12 +1857,12 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(umidi->chip->card, "USB MIDI", - umidi->chip->next_midi_device++, + err = snd_rawmidi_new(umidi->card, "USB MIDI", + umidi->next_midi_device++, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->chip->card->shortname); + strcpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -1804,7 +1901,7 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) return; for (i = 0; i < INPUT_URBS; ++i) { struct urb* urb = ep->urbs[i]; - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } } @@ -1825,9 +1922,10 @@ void snd_usbmidi_input_start(struct list_head* p) /* * Creates and registers everything needed for a MIDI streaming interface. */ -int snd_usb_create_midi_interface(struct snd_usb_audio* chip, - struct usb_interface* iface, - const struct snd_usb_audio_quirk* quirk) +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface* iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk* quirk) { struct snd_usb_midi* umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -1837,12 +1935,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; - umidi->chip = chip; + umidi->dev = interface_to_usbdev(iface); + umidi->card = card; umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); + mutex_init(&umidi->mutex); + umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), + le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1851,7 +1953,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); - if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ + if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ umidi->usb_protocol_ops = &snd_usbmidi_maudio_broken_running_status_ops; break; @@ -1887,7 +1989,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, * interface 0, so we have to make sure that the USB core looks * again at interface 0 by calling usb_set_interface() on it. */ - usb_set_interface(umidi->chip->dev, 0, 0); + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: @@ -1914,8 +2016,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, out_ports = 0; in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables); - in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables); + out_ports += hweight16(endpoints[i].out_cables); + in_ports += hweight16(endpoints[i].in_cables); } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { @@ -1933,14 +2035,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, return err; } - list_add(&umidi->list, &umidi->chip->midi_list); + list_add_tail(&umidi->list, midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } -EXPORT_SYMBOL(snd_usb_create_midi_interface); +EXPORT_SYMBOL(snd_usbmidi_create); EXPORT_SYMBOL(snd_usbmidi_input_stop); EXPORT_SYMBOL(snd_usbmidi_input_start); EXPORT_SYMBOL(snd_usbmidi_disconnect); diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f6f201eb24c..a892bda03df 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1563,6 +1563,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* has ID 0x00ea when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-1G", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 99f33766cd5..f71cd28eca6 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -59,11 +59,33 @@ static int us122l_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_US122L, .data = &quirk_data }; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 1); - return snd_usb_create_midi_interface(&US122L(card)->chip, - iface, &quirk); + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); +} + +static int us144_create_usbmidi(struct snd_card *card) +{ + static struct snd_usb_midi_endpoint_info quirk_data = { + .out_ep = 4, + .in_ep = 3, + .out_cables = 0x001, + .in_cables = 0x001 + }; + static struct snd_usb_audio_quirk quirk = { + .vendor_name = "US144", + .product_name = NAME_ALLCAPS, + .ifnum = 0, + .type = QUIRK_MIDI_US122L, + .data = &quirk_data + }; + struct usb_device *dev = US122L(card)->dev; + struct usb_interface *iface = usb_ifnum_to_if(dev, 0); + + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); } /* @@ -171,7 +193,12 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - iface = usb_ifnum_to_if(us122l->chip.dev, 1); + + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); + usb_autopm_get_interface(iface); + } + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_get_interface(iface); return 0; } @@ -179,8 +206,14 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) { struct us122l *us122l = hw->private_data; - struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1); + struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); + + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); + usb_autopm_put_interface(iface); + } + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_put_interface(iface); if (us122l->first == file) us122l->first = NULL; @@ -264,7 +297,7 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw, static void us122l_stop(struct us122l *us122l) { struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); usb_stream_stop(&us122l->sk); @@ -297,7 +330,7 @@ static bool us122l_start(struct us122l *us122l, unsigned use_packsize = 0; bool success = false; - if (us122l->chip.dev->speed == USB_SPEED_HIGH) { + if (us122l->dev->speed == USB_SPEED_HIGH) { /* The us-122l's descriptor defaults to iso max_packsize 78, which isn't needed for samplerates <= 48000. Lets save some memory: @@ -314,11 +347,11 @@ static bool us122l_start(struct us122l *us122l, break; } } - if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2, + if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2, rate, use_packsize, period_frames, 6)) goto out; - err = us122l_set_sample_rate(us122l->chip.dev, rate); + err = us122l_set_sample_rate(us122l->dev, rate); if (err < 0) { us122l_stop(us122l); snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); @@ -330,7 +363,7 @@ static bool us122l_start(struct us122l *us122l, snd_printk(KERN_ERR "us122l_start error %i \n", err); goto out; } - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); success = true; out: @@ -357,7 +390,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, err = -ENXIO; goto free; } - high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH; + high_speed = us122l->dev->speed == USB_SPEED_HIGH; if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000 && (!high_speed || (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) || @@ -417,7 +450,7 @@ static int usb_stream_hwdep_new(struct snd_card *card) { int err; struct snd_hwdep *hw; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw); if (err < 0) @@ -443,19 +476,29 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - err = usb_set_interface(us122l->chip.dev, 1, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error \n"); + return false; + } + } + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); return false; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); if (!us122l_start(us122l, 44100, 256)) return false; - err = us122l_create_usbmidi(card); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) + err = us144_create_usbmidi(card); + else + err = us122l_create_usbmidi(card); if (err < 0) { snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err); us122l_stop(us122l); @@ -465,7 +508,7 @@ static bool us122l_create_card(struct snd_card *card) if (err < 0) { /* release the midi resources */ struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_disconnect(p); us122l_stop(us122l); @@ -477,7 +520,7 @@ static bool us122l_create_card(struct snd_card *card) static void snd_us122l_free(struct snd_card *card) { struct us122l *us122l = US122L(card); - int index = us122l->chip.index; + int index = us122l->card_index; if (index >= 0 && index < SNDRV_CARDS) snd_us122l_card_used[index] = 0; } @@ -497,13 +540,12 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct us122l), &card); if (err < 0) return err; - snd_us122l_card_used[US122L(card)->chip.index = dev] = 1; + snd_us122l_card_used[US122L(card)->card_index = dev] = 1; card->private_free = snd_us122l_free; - US122L(card)->chip.dev = device; - US122L(card)->chip.card = card; + US122L(card)->dev = device; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); - INIT_LIST_HEAD(&US122L(card)->chip.midi_list); + INIT_LIST_HEAD(&US122L(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -511,8 +553,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0, - US122L(card)->chip.dev->bus->busnum, - US122L(card)->chip.dev->devnum + US122L(card)->dev->bus->busnum, + US122L(card)->dev->devnum ); *cardp = card; return 0; @@ -542,6 +584,7 @@ static int us122l_usb_probe(struct usb_interface *intf, return err; } + usb_get_intf(usb_ifnum_to_if(device, 0)); usb_get_dev(device); *cardp = card; return 0; @@ -550,9 +593,16 @@ static int us122l_usb_probe(struct usb_interface *intf, static int snd_us122l_probe(struct usb_interface *intf, const struct usb_device_id *id) { + struct usb_device *device = interface_to_usbdev(intf); struct snd_card *card; int err; + if (device->descriptor.idProduct == USB_ID_US144 + && device->speed == USB_SPEED_HIGH) { + snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); + return -ENODEV; + } + snd_printdd(KERN_DEBUG"%p:%i\n", intf, intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceNumber != 1) @@ -584,15 +634,15 @@ static void snd_us122l_disconnect(struct usb_interface *intf) mutex_lock(&us122l->mutex); us122l_stop(us122l); mutex_unlock(&us122l->mutex); - us122l->chip.shutdown = 1; /* release the midi resources */ - list_for_each(p, &us122l->chip.midi_list) { + list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } - usb_put_intf(intf); - usb_put_dev(us122l->chip.dev); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 0)); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); + usb_put_dev(us122l->dev); while (atomic_read(&us122l->mmap_count)) msleep(500); @@ -615,7 +665,7 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) if (!us122l) return 0; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); mutex_lock(&us122l->mutex); @@ -642,16 +692,23 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - err = usb_set_interface(us122l->chip.dev, 1, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error \n"); + goto unlock; + } + } + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); goto unlock; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); - err = us122l_set_sample_rate(us122l->chip.dev, + err = us122l_set_sample_rate(us122l->dev, us122l->sk.s->cfg.sample_rate); if (err < 0) { snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); @@ -661,7 +718,7 @@ static int snd_us122l_resume(struct usb_interface *intf) if (err) goto unlock; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); unlock: mutex_unlock(&us122l->mutex); @@ -675,11 +732,11 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { .idVendor = 0x0644, .idProduct = USB_ID_US122L }, -/* { */ /* US-144 maybe works when @USB1.1. Untested. */ -/* .match_flags = USB_DEVICE_ID_MATCH_DEVICE, */ -/* .idVendor = 0x0644, */ -/* .idProduct = USB_ID_US144 */ -/* }, */ + { /* US-144 only works at USB1.1! Disable module ehci-hcd. */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US144 + }, { /* terminator */ } }; diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 3d10c4b2a0f..4daf1982e82 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -3,7 +3,8 @@ struct us122l { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct usb_stream_kernel sk; @@ -12,6 +13,7 @@ struct us122l { unsigned second_periods_polled; struct file *master; struct file *slave; + struct list_head midi_list; atomic_t mmap_count; }; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 52e04b2f35d..1879b72c40f 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -114,7 +114,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, struct usX2Ydev *us428 = hw->private_data; int id = -1; - switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) { + switch (le16_to_cpu(us428->dev->descriptor.idProduct)) { case USB_ID_US122: id = USX2Y_TYPE_122; break; @@ -164,14 +164,14 @@ static int usX2Y_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_2 }; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); struct snd_usb_audio_quirk *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? &quirk_2 : &quirk_1; snd_printdd("usX2Y_create_usbmidi \n"); - return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); + return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk); } static int usX2Y_create_alsa_devices(struct snd_card *card) @@ -202,7 +202,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, snd_printdd( "dsp_load %s\n", dsp->name); if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { - struct usb_device* dev = priv->chip.dev; + struct usb_device* dev = priv->dev; char *buf; buf = memdup_user(dsp->image, dsp->length); diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index cb4bb8373ca..c42350eed2e 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -239,8 +239,8 @@ static void i_usX2Y_In04Int(struct urb *urb) for (j = 0; j < URBS_AsyncSeq && !err; ++j) if (0 == usX2Y->AS04.urb[j]->status) { struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. - usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, + usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol, p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, i_usX2Y_Out04Int, usX2Y); err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC); @@ -253,7 +253,7 @@ static void i_usX2Y_In04Int(struct urb *urb) if (err) snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; usb_submit_urb(urb, GFP_ATOMIC); } @@ -273,8 +273,8 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) err = -ENOMEM; break; } - usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), + usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); @@ -293,7 +293,7 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y) } init_waitqueue_head(&usX2Y->In04WaitQueue); - usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4), + usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); @@ -348,13 +348,12 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct usX2Ydev), &card); if (err < 0) return err; - snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1; + snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1; card->private_free = snd_usX2Y_card_private_free; - usX2Y(card)->chip.dev = device; - usX2Y(card)->chip.card = card; + usX2Y(card)->dev = device; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); - INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list); + INIT_LIST_HEAD(&usX2Y(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -362,7 +361,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0,//us428(card)->usbmidi.ifnum, - usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum + usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum ); *cardp = card; return 0; @@ -432,8 +431,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card) usb_free_urb(usX2Y(card)->In04urb); if (usX2Y(card)->us428ctls_sharedmem) snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem)); - if (usX2Y(card)->chip.index >= 0 && usX2Y(card)->chip.index < SNDRV_CARDS) - snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0; + if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) + snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; } /* @@ -445,13 +444,12 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) struct snd_card *card = ptr; struct usX2Ydev *usX2Y = usX2Y(card); struct list_head *p; - usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); usb_kill_urb(usX2Y->In04urb); snd_card_disconnect(card); /* release the midi resources */ - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 456b5fdbc33..1d174cea352 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -22,7 +22,8 @@ struct snd_usX2Y_urbSeq { #include "usx2yhwdeppcm.h" struct usX2Ydev { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct urb *In04urb; void *In04Buf; @@ -42,6 +43,9 @@ struct usX2Ydev { struct snd_usX2Y_substream *subs[4]; struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; + struct list_head midi_list; + struct list_head pcm_list; + int pcm_devs; }; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 9efd27f6b52..74a67a85aa8 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -199,7 +199,7 @@ static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, i return -ENODEV; urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks urb->hcpriv = NULL; - urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */ + urb->dev = subs->usX2Y->dev; /* we need to set this at each time */ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" "Most propably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); usX2Y_clients_stop(usX2Y); @@ -313,7 +313,7 @@ static void i_usX2Y_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -424,7 +424,7 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -500,7 +500,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == i) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; @@ -692,7 +692,7 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) } ((char*)(usbdata + i))[0] = ra[i].c1; ((char*)(usbdata + i))[1] = ra[i].c2; - usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4), + usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); #ifdef OLD_USB us->urb[i]->transfer_flags = USB_QUEUE_BULK; @@ -740,17 +740,17 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) alternate = 1; usX2Y->stride = 4; } - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); - if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) { + if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) { snd_printk(KERN_ERR "usb_set_interface error \n"); return err; } - usX2Y->In04urb->dev = usX2Y->chip.dev; + usX2Y->In04urb->dev = usX2Y->dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); } usX2Y->format = format; @@ -955,7 +955,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, struct snd_pcm *pcm; int err, i; struct snd_usX2Y_substream **usX2Y_substream = - usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs; + usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs; for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { @@ -971,7 +971,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; - err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs, + err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs, playback_endpoint ? 1 : 0, 1, &pcm); if (err < 0) { @@ -987,7 +987,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, pcm->private_free = snd_usX2Y_pcm_private_free; pcm->info_flags = 0; - sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs); + sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); if ((playback_endpoint && 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -1001,7 +1001,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, snd_usX2Y_pcm_private_free(pcm); return err; } - usX2Y(card)->chip.pcm_devs++; + usX2Y(card)->pcm_devs++; return 0; } @@ -1013,14 +1013,14 @@ int usX2Y_audio_create(struct snd_card *card) { int err = 0; - INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list); + INIT_LIST_HEAD(&usX2Y(card)->pcm_list); if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428) if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122) err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 4b2304c2e02..9ed6c3956ca 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -234,7 +234,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -318,7 +318,7 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -441,7 +441,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == u) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); @@ -741,7 +741,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) int err; struct snd_hwdep *hw; struct snd_pcm *pcm; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; if (1 != nr_of_packs()) return 0; |