1
0
Fork 0

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (252 commits)
  ASoC: Check progress when reporting periods from i.MX FIQ handler
  ASoC: Remove a unused variables from i.MX FIQ runtime data
  ALSA: hda - Add/fix ALC269 FSC and Quanta models
  ALSA: hda - Add ALC670 codec support
  OMAP4: PMIC: Add support for twl6030 codec
  ALSA: hda - remove unnecessary msleep on power state transitions
  usb/gadget/{f_audio,gmidi}.c: follow recent changes in audio.h
  ASoC: fsi: Modify over/under run error settlement
  ASoC: OMAP4: Add McPDM platform driver
  ASoC: OMAP4: Add support for McPDM
  ASoC: OMAP: data_type and sync_mode configurable in audio dma
  ALSA: hda - Add missing description in HD-Audio-Models.txt
  ALSA: add support for Macbook Air 2,1 internal speaker
  ALSA: usbaudio: consolidate header files
  ALSA: usbmixer: bail out early when parsing audio class v2 descriptors
  ALSA: usbaudio: implement basic set of class v2.0 parser
  ALSA: usbaudio: introduce new types for audio class v2
  ALSA: usbaudio: parse USB descriptors with structs
  ALSA: hda - enable snoop for Intel Cougar Point
  ALSA: hda - Remove identical definitions for macmini3 model
  ...
hifive-unleashed-5.1
Linus Torvalds 2010-03-01 08:58:44 -08:00
commit 524df55725
263 changed files with 27996 additions and 6153 deletions

View File

@ -482,6 +482,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
reference_rate - reference sample rate, 44100 or 48000 (default)
multiple - multiple to ref. sample rate, 1 or 2 (default)
subsystem - override the PCI SSID for probing; the value
consists of SSVID << 16 | SSDID. The default is
zero, which means no override.
This module supports multiple cards.
@ -1123,6 +1126,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple cards, autoprobe and ISA PnP.
Module snd-jazz16
-------------------
Module for Media Vision Jazz16 chipset. The chipset consists of 3 chips:
MVD1216 + MVA416 + MVA514.
port - port # for SB DSP chip (0x210,0x220,0x230,0x240,0x250,0x260)
irq - IRQ # for SB DSP chip (3,5,7,9,10,15)
dma8 - DMA # for SB DSP chip (1,3)
dma16 - DMA # for SB DSP chip (5,7)
mpu_port - MPU-401 port # (0x300,0x310,0x320,0x330)
mpu_irq - MPU-401 irq # (2,3,5,7)
This module supports multiple cards.
Module snd-korg1212
-------------------
@ -1791,6 +1809,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
Module snd-ua101
----------------
Module for the Edirol UA-101 audio/MIDI interface.
This module supports multiple devices, autoprobe and hotplugging.
Module snd-usb-audio
--------------------
@ -1923,7 +1948,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
-------------------
Module for sound cards based on the Asus AV100/AV200 chips,
i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST
i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST
(Deluxe) and Essence STX.
This module supports autoprobe and multiple cards.

View File

@ -124,6 +124,8 @@ ALC882/883/885/888/889
asus-a7m ASUS A7M
macpro MacPro support
mb5 Macbook 5,1
macmini3 Macmini 3,1
mba21 Macbook Air 2,1
mbp3 Macbook Pro rev3
imac24 iMac 24'' with jack detection
imac91 iMac 9,1
@ -279,13 +281,16 @@ Conexant 5051
laptop Basic Laptop config (default)
hp HP Spartan laptop
hp-dv6736 HP dv6736
hp-f700 HP Compaq Presario F700
lenovo-x200 Lenovo X200 laptop
toshiba Toshiba Satellite M300
Conexant 5066
=============
laptop Basic Laptop config (default)
dell-laptop Dell laptops
olpc-xo-1_5 OLPC XO 1.5
ideapad Lenovo IdeaPad U150
STAC9200
========

View File

@ -452,6 +452,33 @@ Similarly, the lines after `[verb]` are parsed as `init_verbs`
sysfs entries, and the lines after `[hint]` are parsed as `hints`
sysfs entries, respectively.
Another example to override the codec vendor id from 0x12345678 to
0xdeadbeef is like below:
------------------------------------------------------------------------
[codec]
0x12345678 0xabcd1234 2
[vendor_id]
0xdeadbeef
------------------------------------------------------------------------
In the similar way, you can override the codec subsystem_id via
`[subsystem_id]`, the revision id via `[revision_id]` line.
Also, the codec chip name can be rewritten via `[chip_name]` line.
------------------------------------------------------------------------
[codec]
0x12345678 0xabcd1234 2
[subsystem_id]
0xffff1111
[revision_id]
0x10
[chip_name]
My-own NEWS-0002
------------------------------------------------------------------------
The hd-audio driver reads the file via request_firmware(). Thus,
a patch file has to be located on the appropriate firmware path,
typically, /lib/firmware. For example, when you pass the option

View File

@ -13,3 +13,7 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
obj-$(CONFIG_MXC_ULPI) += ulpi.o
obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
ifdef CONFIG_SND_IMX_SOC
obj-y += ssi-fiq.o
obj-y += ssi-fiq-ksym.o
endif

View File

@ -0,0 +1,20 @@
/*
* Exported ksyms for the SSI FIQ handler
*
* Copyright (C) 2009, Sascha Hauer <s.hauer@pengutronix.de>
*
* 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.
*/
#include <linux/module.h>
#include <mach/ssi.h>
EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer);
EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer);
EXPORT_SYMBOL(imx_ssi_fiq_start);
EXPORT_SYMBOL(imx_ssi_fiq_end);
EXPORT_SYMBOL(imx_ssi_fiq_base);

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
*
* 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.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* r8 = bit 0-15: tx offset, bit 16-31: tx buffer size
* r9 = bit 0-15: rx offset, bit 16-31: rx buffer size
*/
#define SSI_STX0 0x00
#define SSI_SRX0 0x08
#define SSI_SISR 0x14
#define SSI_SIER 0x18
#define SSI_SACNT 0x38
#define SSI_SACNT_AC97EN (1 << 0)
#define SSI_SIER_TFE0_EN (1 << 0)
#define SSI_SISR_TFE0 (1 << 0)
#define SSI_SISR_RFF0 (1 << 2)
#define SSI_SIER_RFF0_EN (1 << 2)
.text
.global imx_ssi_fiq_start
.global imx_ssi_fiq_end
.global imx_ssi_fiq_base
.global imx_ssi_fiq_rx_buffer
.global imx_ssi_fiq_tx_buffer
imx_ssi_fiq_start:
ldr r12, imx_ssi_fiq_base
/* TX */
ldr r11, imx_ssi_fiq_tx_buffer
/* shall we send? */
ldr r13, [r12, #SSI_SIER]
tst r13, #SSI_SIER_TFE0_EN
beq 1f
/* TX FIFO empty? */
ldr r13, [r12, #SSI_SISR]
tst r13, #SSI_SISR_TFE0
beq 1f
mov r10, #0x10000
sub r10, #1
and r10, r10, r8 /* r10: current buffer offset */
add r11, r11, r10
ldrh r13, [r11]
strh r13, [r12, #SSI_STX0]
ldrh r13, [r11, #2]
strh r13, [r12, #SSI_STX0]
ldrh r13, [r11, #4]
strh r13, [r12, #SSI_STX0]
ldrh r13, [r11, #6]
strh r13, [r12, #SSI_STX0]
add r10, #8
lsr r13, r8, #16 /* r13: buffer size */
cmp r10, r13
lslgt r8, r13, #16
addle r8, #8
1:
/* RX */
/* shall we receive? */
ldr r13, [r12, #SSI_SIER]
tst r13, #SSI_SIER_RFF0_EN
beq 1f
/* RX FIFO full? */
ldr r13, [r12, #SSI_SISR]
tst r13, #SSI_SISR_RFF0
beq 1f
ldr r11, imx_ssi_fiq_rx_buffer
mov r10, #0x10000
sub r10, #1
and r10, r10, r9 /* r10: current buffer offset */
add r11, r11, r10
ldr r13, [r12, #SSI_SACNT]
tst r13, #SSI_SACNT_AC97EN
ldr r13, [r12, #SSI_SRX0]
strh r13, [r11]
ldr r13, [r12, #SSI_SRX0]
strh r13, [r11, #2]
/* dummy read to skip slot 12 */
ldrne r13, [r12, #SSI_SRX0]
ldr r13, [r12, #SSI_SRX0]
strh r13, [r11, #4]
ldr r13, [r12, #SSI_SRX0]
strh r13, [r11, #6]
/* dummy read to skip slot 12 */
ldrne r13, [r12, #SSI_SRX0]
add r10, #8
lsr r13, r9, #16 /* r13: buffer size */
cmp r10, r13
lslgt r9, r13, #16
addle r9, #8
1:
@ return from FIQ
subs pc, lr, #4
imx_ssi_fiq_base:
.word 0x0
imx_ssi_fiq_rx_buffer:
.word 0x0
imx_ssi_fiq_tx_buffer:
.word 0x0
imx_ssi_fiq_end:

View File

@ -0,0 +1,26 @@
/*
* platform header for the SIU ASoC driver
*
* Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* 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 ASM_SIU_H
#define ASM_SIU_H
#include <asm/dma-sh.h>
struct device;
struct siu_platform {
struct device *dma_dev;
enum sh_dmae_slave_chan_id dma_slave_tx_a;
enum sh_dmae_slave_chan_id dma_slave_rx_a;
enum sh_dmae_slave_chan_id dma_slave_tx_b;
enum sh_dmae_slave_chan_id dma_slave_rx_b;
};
#endif /* ASM_SIU_H */

View File

@ -115,7 +115,8 @@
#define twl_has_watchdog() false
#endif
#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
#define twl_has_codec() true
#else
#define twl_has_codec() false
@ -711,8 +712,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
if (twl_has_codec() && pdata->codec) {
child = add_child(1, "twl4030_codec",
if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
child = add_child(sub_chip_id, "twl4030_codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
/* Phoenix*/
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
child = add_child(sub_chip_id, "twl6030_codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))

View File

@ -60,7 +60,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
static struct uac_ac_header_descriptor_2 ac_header_desc = {
static struct uac_ac_header_descriptor_v1_2 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
@ -124,7 +124,7 @@ static struct usb_audio_control_selector feature_unit = {
};
#define OUTPUT_TERMINAL_ID 3
static struct uac_output_terminal_descriptor output_terminal_desc = {
static struct uac_output_terminal_descriptor_v1 output_terminal_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
@ -154,7 +154,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
};
/* B.4.2 Class-Specific AS Interface Descriptor */
static struct uac_as_header_descriptor as_header_desc = {
static struct uac_as_header_descriptor_v1 as_header_desc = {
.bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,

View File

@ -237,7 +237,7 @@ static const struct usb_interface_descriptor ac_interface_desc = {
};
/* B.3.2 Class-Specific AC Interface Descriptor */
static const struct uac_ac_header_descriptor_1 ac_header_desc = {
static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,

View File

@ -547,6 +547,10 @@ struct twl4030_codec_data {
unsigned int audio_mclk;
struct twl4030_codec_audio_data *audio;
struct twl4030_codec_vibra_data *vibra;
/* twl6030 */
int audpwron_gpio; /* audio power-on gpio */
int naudint_irq; /* audio interrupt */
};
struct twl4030_platform_data {

View File

@ -25,6 +25,9 @@
#define USB_SUBCLASS_AUDIOSTREAMING 0x02
#define USB_SUBCLASS_MIDISTREAMING 0x03
#define UAC_VERSION_1 0x00
#define UAC_VERSION_2 0x20
/* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */
#define UAC_HEADER 0x01
#define UAC_INPUT_TERMINAL 0x02
@ -32,8 +35,17 @@
#define UAC_MIXER_UNIT 0x04
#define UAC_SELECTOR_UNIT 0x05
#define UAC_FEATURE_UNIT 0x06
#define UAC_PROCESSING_UNIT 0x07
#define UAC_EXTENSION_UNIT 0x08
#define UAC_PROCESSING_UNIT_V1 0x07
#define UAC_EXTENSION_UNIT_V1 0x08
/* UAC v2.0 types */
#define UAC_EFFECT_UNIT 0x07
#define UAC_PROCESSING_UNIT_V2 0x08
#define UAC_EXTENSION_UNIT_V2 0x09
#define UAC_CLOCK_SOURCE 0x0a
#define UAC_CLOCK_SELECTOR 0x0b
#define UAC_CLOCK_MULTIPLIER 0x0c
#define UAC_SAMPLE_RATE_CONVERTER 0x0d
/* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
#define UAC_AS_GENERAL 0x01
@ -66,6 +78,10 @@
#define UAC_GET_STAT 0xff
/* Audio class v2.0 handles all the parameter calls differently */
#define UAC2_CS_CUR 0x01
#define UAC2_CS_RANGE 0x02
/* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
#define UAC_MS_HEADER 0x01
#define UAC_MIDI_IN_JACK 0x02
@ -81,7 +97,7 @@
/* Terminal Control Selectors */
/* 4.3.2 Class-Specific AC Interface Descriptor */
struct uac_ac_header_descriptor {
struct uac_ac_header_descriptor_v1 {
__u8 bLength; /* 8 + n */
__u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
__u8 bDescriptorSubtype; /* UAC_MS_HEADER */
@ -95,7 +111,7 @@ struct uac_ac_header_descriptor {
/* As above, but more useful for defining your own descriptors: */
#define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n) \
struct uac_ac_header_descriptor_##n { \
struct uac_ac_header_descriptor_v1_##n { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubtype; \
@ -130,8 +146,12 @@ struct uac_input_terminal_descriptor {
#define UAC_INPUT_TERMINAL_MICROPHONE_ARRAY 0x205
#define UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY 0x206
/* Terminals - control selectors */
#define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL 0x01
/* 4.3.2.2 Output Terminal Descriptor */
struct uac_output_terminal_descriptor {
struct uac_output_terminal_descriptor_v1 {
__u8 bLength; /* in bytes: 9 */
__u8 bDescriptorType; /* CS_INTERFACE descriptor type */
__u8 bDescriptorSubtype; /* OUTPUT_TERMINAL descriptor subtype */
@ -171,7 +191,7 @@ struct uac_feature_unit_descriptor_##ch { \
} __attribute__ ((packed))
/* 4.5.2 Class-Specific AS Interface Descriptor */
struct uac_as_header_descriptor {
struct uac_as_header_descriptor_v1 {
__u8 bLength; /* in bytes: 7 */
__u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
__u8 bDescriptorSubtype; /* AS_GENERAL */
@ -180,6 +200,19 @@ struct uac_as_header_descriptor {
__le16 wFormatTag; /* The Audio Data Format */
} __attribute__ ((packed));
struct uac_as_header_descriptor_v2 {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bTerminalLink;
__u8 bmControls;
__u8 bFormatType;
__u32 bmFormats;
__u8 bNrChannels;
__u32 bmChannelConfig;
__u8 iChannelNames;
} __attribute__((packed));
#define UAC_DT_AS_HEADER_SIZE 7
/* Formats - A.1.1 Audio Data Format Type I Codes */
@ -232,11 +265,62 @@ struct uac_format_type_i_discrete_descriptor_##n { \
#define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n) (8 + (n * 3))
struct uac_format_type_i_ext_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bSubslotSize;
__u8 bFormatType;
__u8 bBitResolution;
__u8 bHeaderLength;
__u8 bControlSize;
__u8 bSideBandProtocol;
} __attribute__((packed));
/* Formats - Audio Data Format Type I Codes */
#define UAC_FORMAT_TYPE_II_MPEG 0x1001
#define UAC_FORMAT_TYPE_II_AC3 0x1002
struct uac_format_type_ii_discrete_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bFormatType;
__le16 wMaxBitRate;
__le16 wSamplesPerFrame;
__u8 bSamFreqType;
__u8 tSamFreq[][3];
} __attribute__((packed));
struct uac_format_type_ii_ext_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bFormatType;
__u16 wMaxBitRate;
__u16 wSamplesPerFrame;
__u8 bHeaderLength;
__u8 bSideBandProtocol;
} __attribute__((packed));
/* type III */
#define UAC_FORMAT_TYPE_III_IEC1937_AC3 0x2001
#define UAC_FORMAT_TYPE_III_IEC1937_MPEG1_LAYER1 0x2002
#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_NOEXT 0x2003
#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_EXT 0x2004
#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER1_LS 0x2005
#define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER23_LS 0x2006
/* Formats - A.2 Format Type Codes */
#define UAC_FORMAT_TYPE_UNDEFINED 0x0
#define UAC_FORMAT_TYPE_I 0x1
#define UAC_FORMAT_TYPE_II 0x2
#define UAC_FORMAT_TYPE_III 0x3
#define UAC_EXT_FORMAT_TYPE_I 0x81
#define UAC_EXT_FORMAT_TYPE_II 0x82
#define UAC_EXT_FORMAT_TYPE_III 0x83
struct uac_iso_endpoint_descriptor {
__u8 bLength; /* in bytes: 7 */
@ -252,7 +336,31 @@ struct uac_iso_endpoint_descriptor {
#define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02
#define UAC_EP_CS_ATTR_FILL_MAX 0x80
/* Audio class v2.0: CLOCK_SOURCE descriptor */
struct uac_clock_source_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bClockID;
__u8 bmAttributes;
__u8 bmControls;
__u8 bAssocTerminal;
__u8 iClockSource;
} __attribute__((packed));
/* A.10.2 Feature Unit Control Selectors */
struct uac_feature_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u8 bSourceID;
__u8 bControlSize;
__u8 controls[0]; /* variable length */
} __attribute__((packed));
#define UAC_FU_CONTROL_UNDEFINED 0x00
#define UAC_MUTE_CONTROL 0x01
#define UAC_VOLUME_CONTROL 0x02

View File

@ -458,5 +458,8 @@ struct snd_pci_quirk {
const struct snd_pci_quirk *
snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
const struct snd_pci_quirk *
snd_pci_quirk_lookup_id(u16 vendor, u16 device,
const struct snd_pci_quirk *list);
#endif /* __SOUND_CORE_H */

View File

@ -118,9 +118,11 @@ struct dsp_scb_descriptor {
struct snd_info_entry *proc_info;
int ref_count;
spinlock_t lock;
int deleted;
u16 volume[2];
unsigned int deleted :1;
unsigned int updated :1;
unsigned int volume_set :1;
};
struct dsp_task_descriptor {

View File

@ -262,6 +262,8 @@ struct snd_pcm_hw_constraint_list {
unsigned int mask;
};
struct snd_pcm_hwptr_log;
struct snd_pcm_runtime {
/* -- Status -- */
struct snd_pcm_substream *trigger_master;
@ -310,7 +312,9 @@ struct snd_pcm_runtime {
struct snd_pcm_mmap_control *control;
/* -- locking / scheduling -- */
wait_queue_head_t sleep;
unsigned int twake: 1; /* do transfer (!poll) wakeup */
wait_queue_head_t sleep; /* poll sleep */
wait_queue_head_t tsleep; /* transfer sleep */
struct fasync_struct *fasync;
/* -- private section -- */
@ -340,6 +344,10 @@ struct snd_pcm_runtime {
/* -- OSS things -- */
struct snd_pcm_oss_runtime oss;
#endif
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
struct snd_pcm_hwptr_log *hwptr_log;
#endif
};
struct snd_pcm_group { /* keep linked substreams */
@ -834,6 +842,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream);
int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
int snd_pcm_update_state(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime);
int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
@ -905,6 +915,44 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
size_t size, gfp_t gfp_flags);
int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream);
struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
unsigned long offset);
#if 0 /* for kernel-doc */
/**
* snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer
* @substream: the substream to allocate the buffer to
* @size: the requested buffer size, in bytes
*
* Allocates the PCM substream buffer using vmalloc(), i.e., the memory is
* contiguous in kernel virtual space, but not in physical memory. Use this
* if the buffer is accessed by kernel code but not by device DMA.
*
* Returns 1 if the buffer was changed, 0 if not changed, or a negative error
* code.
*/
static int snd_pcm_lib_alloc_vmalloc_buffer
(struct snd_pcm_substream *substream, size_t size);
/**
* snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer
* @substream: the substream to allocate the buffer to
* @size: the requested buffer size, in bytes
*
* This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses
* vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory.
*/
static int snd_pcm_lib_alloc_vmalloc_32_buffer
(struct snd_pcm_substream *substream, size_t size);
#endif
#define snd_pcm_lib_alloc_vmalloc_buffer(subs, size) \
_snd_pcm_lib_alloc_vmalloc_buffer \
(subs, size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)
#define snd_pcm_lib_alloc_vmalloc_32_buffer(subs, size) \
_snd_pcm_lib_alloc_vmalloc_buffer \
(subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO)
#ifdef CONFIG_SND_DMA_SGBUF
/*
* SG-buffer handling
@ -975,6 +1023,10 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s
#define snd_pcm_lib_mmap_iomem NULL
#endif
int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
struct vm_area_struct *area);
#define snd_pcm_lib_mmap_vmalloc snd_pcm_lib_mmap_noncached
static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
{
*max = dma < 4 ? 64 * 1024 : 128 * 1024;

View File

@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime {
struct snd_pcm_plugin *plugin_first;
struct snd_pcm_plugin *plugin_last;
#endif
unsigned int prev_hw_ptr_interrupt;
unsigned int prev_hw_ptr_period;
};
struct snd_pcm_oss_file {

View File

@ -33,6 +33,7 @@ enum sb_hw_type {
SB_HW_20,
SB_HW_201,
SB_HW_PRO,
SB_HW_JAZZ16, /* Media Vision Jazz16 */
SB_HW_16,
SB_HW_16CSP, /* SB16 with CSP chip */
SB_HW_ALS100, /* Avance Logic ALS100 chip */

View File

@ -16,6 +16,8 @@
#include <linux/list.h>
#include <sound/soc.h>
struct snd_pcm_substream;
/*

View File

@ -95,6 +95,21 @@
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
.num_kcontrols = 1}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
wcontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
.num_kcontrols = ARRAY_SIZE(wcontrols)}
/* path domain with event - event handler must return 0 for success */
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
@ -126,6 +141,23 @@
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags}
#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags}
#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
wcontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, \
.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
/* events that are pre and post DAPM */
#define SND_SOC_DAPM_PRE(wname, wevent) \
{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \

View File

@ -168,6 +168,23 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
/*
* Simplified versions of above macros, declaring a struct and calculating
* ARRAY_SIZE internally
*/
#define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \
struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
ARRAY_SIZE(xtexts), xtexts)
#define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \
SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
#define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \
struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
#define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \
struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
ARRAY_SIZE(xtexts), xtexts, xvalues)
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
/*
* Bias levels
*
@ -253,6 +270,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
/* codec register bit access */
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned int mask, unsigned int value);
int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
unsigned short reg, unsigned int mask,
unsigned int value);
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned int mask, unsigned int value);
@ -402,6 +422,10 @@ struct snd_soc_codec {
short reg_cache_size;
short reg_cache_step;
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
unsigned int cache_only:1; /* Suppress writes to hardware */
unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
/* dapm */
u32 pop_time;
struct list_head dapm_widgets;
@ -497,6 +521,8 @@ struct snd_soc_card {
int (*set_bias_level)(struct snd_soc_card *,
enum snd_soc_bias_level level);
long pmdown_time;
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;

View File

@ -15,6 +15,7 @@
struct tlv320dac33_platform_data {
int power_gpio;
u8 burst_bclkdiv;
};
#endif /* __TLV320DAC33_PLAT_H */

View File

@ -23,7 +23,13 @@
#ifndef TPA6130A2_PLAT_H
#define TPA6130A2_PLAT_H
enum tpa_model {
TPA6130A2,
TPA6140A2,
};
struct tpa6130a2_platform_data {
enum tpa_model id;
int power_gpio;
};

View File

@ -1,3 +1,3 @@
/* include/version.h */
#define CONFIG_SND_VERSION "1.0.21"
#define CONFIG_SND_VERSION "1.0.22.1"
#define CONFIG_SND_DATE ""

View File

@ -0,0 +1,26 @@
/*
* linux/sound/wm2000.h -- Platform data for WM2000
*
* Copyright 2010 Wolfson Microelectronics. PLC.
*
* 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 __LINUX_SND_WM2000_H
#define __LINUX_SND_WM2000_H
struct wm2000_platform_data {
/** Filename for system-specific image to download to device. */
const char *download_file;
/** Divide MCLK by 2 for system clock? */
unsigned int mclkdiv2:1;
/** Disable speech clarity enhancement, for use when an
* external algorithm is used. */
unsigned int speech_enh_disable:1;
};
#endif

View File

@ -0,0 +1,57 @@
/*
* Platform data for WM8904
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __MFD_WM8994_PDATA_H__
#define __MFD_WM8994_PDATA_H__
#define WM8904_DRC_REGS 4
#define WM8904_EQ_REGS 25
/**
* DRC configurations are specified with a label and a set of register
* values to write (the enable bits will be ignored). At runtime an
* enumerated control will be presented for each DRC block allowing
* the user to choose the configration to use.
*
* Configurations may be generated by hand or by using the DRC control
* panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/
* for details.
*/
struct wm8904_drc_cfg {
const char *name;
u16 regs[WM8904_DRC_REGS];
};
/**
* ReTune Mobile configurations are specified with a label, sample
* rate and set of values to write (the enable bits will be ignored).
*
* Configurations are expected to be generated using the ReTune Mobile
* control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
*/
struct wm8904_retune_mobile_cfg {
const char *name;
unsigned int rate;
u16 regs[WM8904_EQ_REGS];
};
struct wm8904_pdata {
int num_drc_cfgs;
struct wm8904_drc_cfg *drc_cfgs;
int num_retune_mobile_cfgs;
struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
};
#endif

View File

@ -0,0 +1,26 @@
/*
* Platform data for WM8955
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __WM8955_PDATA_H__
#define __WM8955_PDATA_H__
struct wm8955_pdata {
/* Configure LOUT2/ROUT2 to drive a speaker */
unsigned int out2_speaker:1;
/* Configure MONOIN+/- in differential mode */
unsigned int monoin_diff:1;
};
#endif

View File

@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
(ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
SNDRV_CTL_ELEM_ACCESS_INACTIVE|
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
kctl.info = ncontrol->info;
kctl.get = ncontrol->get;
kctl.put = ncontrol->put;
@ -1099,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
return -EFAULT;
if (tlv.length < sizeof(unsigned int) * 3)
if (tlv.length < sizeof(unsigned int) * 2)
return -EINVAL;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_numid(card, tlv.numid);

View File

@ -100,6 +100,35 @@ EXPORT_SYMBOL_GPL(__snd_printk);
#ifdef CONFIG_PCI
#include <linux/pci.h>
/**
* snd_pci_quirk_lookup_id - look up a PCI SSID quirk list
* @vendor: PCI SSV id
* @device: PCI SSD id
* @list: quirk list, terminated by a null entry
*
* Look through the given quirk list and finds a matching entry
* with the same PCI SSID. When subdevice is 0, all subdevice
* values may match.
*
* Returns the matched entry pointer, or NULL if nothing matched.
*/
const struct snd_pci_quirk *
snd_pci_quirk_lookup_id(u16 vendor, u16 device,
const struct snd_pci_quirk *list)
{
const struct snd_pci_quirk *q;
for (q = list; q->subvendor; q++) {
if (q->subvendor != vendor)
continue;
if (!q->subdevice ||
(device & q->subdevice_mask) == q->subdevice)
return q;
}
return NULL;
}
EXPORT_SYMBOL(snd_pci_quirk_lookup_id);
/**
* snd_pci_quirk_lookup - look up a PCI SSID quirk list
* @pci: pci_dev handle
@ -114,16 +143,9 @@ EXPORT_SYMBOL_GPL(__snd_printk);
const struct snd_pci_quirk *
snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
{
const struct snd_pci_quirk *q;
for (q = list; q->subvendor; q++) {
if (q->subvendor != pci->subsystem_vendor)
continue;
if (!q->subdevice ||
(pci->subsystem_device & q->subdevice_mask) == q->subdevice)
return q;
}
return NULL;
return snd_pci_quirk_lookup_id(pci->subsystem_vendor,
pci->subsystem_device,
list);
}
EXPORT_SYMBOL(snd_pci_quirk_lookup);
#endif

View File

@ -632,6 +632,12 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
}
static inline
snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
{
return runtime->hw_ptr_interrupt;
}
/* define extended formats in the recent OSS versions (if any) */
/* linear formats */
#define AFMT_S32_LE 0x00001000
@ -1102,7 +1108,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
return err;
}
runtime->oss.prepare = 0;
runtime->oss.prev_hw_ptr_interrupt = 0;
runtime->oss.prev_hw_ptr_period = 0;
runtime->oss.period_ptr = 0;
runtime->oss.buffer_used = 0;
@ -1950,7 +1956,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
return result;
}
static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr)
static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
snd_pcm_uframes_t hw_ptr)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t appl_ptr;
@ -1986,7 +1993,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
if (runtime->oss.trigger)
goto _skip1;
if (atomic_read(&psubstream->mmap_count))
snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
snd_pcm_oss_simulate_fill(psubstream,
get_hw_ptr_period(runtime));
runtime->oss.trigger = 1;
runtime->start_threshold = 1;
cmd = SNDRV_PCM_IOCTL_START;
@ -2105,11 +2113,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
if (atomic_read(&substream->mmap_count)) {
snd_pcm_sframes_t n;
n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
delay = get_hw_ptr_period(runtime);
n = delay - runtime->oss.prev_hw_ptr_period;
if (n < 0)
n += runtime->boundary;
info.blocks = n / runtime->period_size;
runtime->oss.prev_hw_ptr_interrupt = delay;
runtime->oss.prev_hw_ptr_period = delay;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_pcm_oss_simulate_fill(substream, delay);
info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
@ -2673,18 +2682,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
return runtime->oss.prev_hw_ptr_period !=
get_hw_ptr_period(runtime);
else
return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
return snd_pcm_playback_avail(runtime) >=
runtime->oss.period_frames;
}
static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
return runtime->oss.prev_hw_ptr_period !=
get_hw_ptr_period(runtime);
else
return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
return snd_pcm_capture_avail(runtime) >=
runtime->oss.period_frames;
}
static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)

View File

@ -894,6 +894,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
memset((void*)runtime->control, 0, size);
init_waitqueue_head(&runtime->sleep);
init_waitqueue_head(&runtime->tsleep);
runtime->status->state = SNDRV_PCM_STATE_OPEN;
@ -921,6 +922,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
snd_free_pages((void*)runtime->control,
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
kfree(runtime->hw_constraints.rules);
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
if (runtime->hwptr_log)
kfree(runtime->hwptr_log);
#endif
kfree(runtime);
substream->runtime = NULL;
put_pid(substream->pid);

View File

@ -126,17 +126,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
}
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask))
#else
#define xrun_debug(substream, mask) 0
#endif
#define dump_stack_on_xrun(substream) do { \
if (xrun_debug(substream, 2)) \
dump_stack(); \
} while (0)
static void pcm_debug_name(struct snd_pcm_substream *substream,
char *name, size_t len)
{
@ -147,6 +136,24 @@ static void pcm_debug_name(struct snd_pcm_substream *substream,
substream->number);
}
#define XRUN_DEBUG_BASIC (1<<0)
#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */
#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */
#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */
#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
#define xrun_debug(substream, mask) \
((substream)->pstr->xrun_debug & (mask))
#define dump_stack_on_xrun(substream) do { \
if (xrun_debug(substream, XRUN_DEBUG_STACK)) \
dump_stack(); \
} while (0)
static void xrun(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@ -154,7 +161,7 @@ static void xrun(struct snd_pcm_substream *substream)
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
if (xrun_debug(substream, 1)) {
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
char name[16];
pcm_debug_name(substream, name, sizeof(name));
snd_printd(KERN_DEBUG "XRUN: %s\n", name);
@ -162,32 +169,102 @@ static void xrun(struct snd_pcm_substream *substream)
}
}
static snd_pcm_uframes_t
snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t pos;
#define hw_ptr_error(substream, fmt, args...) \
do { \
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
xrun_log_show(substream); \
if (printk_ratelimit()) { \
snd_printd("PCM: " fmt, ##args); \
} \
dump_stack_on_xrun(substream); \
} \
} while (0)
pos = substream->ops->pointer(substream);
if (pos == SNDRV_PCM_POS_XRUN)
return pos; /* XRUN */
if (pos >= runtime->buffer_size) {
if (printk_ratelimit()) {
char name[16];
pcm_debug_name(substream, name, sizeof(name));
snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, "
"buffer size = 0x%lx, period size = 0x%lx\n",
name, pos, runtime->buffer_size,
runtime->period_size);
}
pos = 0;
#define XRUN_LOG_CNT 10
struct hwptr_log_entry {
unsigned long jiffies;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t period_size;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t old_hw_ptr;
snd_pcm_uframes_t hw_ptr_base;
};
struct snd_pcm_hwptr_log {
unsigned int idx;
unsigned int hit: 1;
struct hwptr_log_entry entries[XRUN_LOG_CNT];
};
static void xrun_log(struct snd_pcm_substream *substream,
snd_pcm_uframes_t pos)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
struct hwptr_log_entry *entry;
if (log == NULL) {
log = kzalloc(sizeof(*log), GFP_ATOMIC);
if (log == NULL)
return;
runtime->hwptr_log = log;
} else {
if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
return;
}
pos -= pos % runtime->min_align;
return pos;
entry = &log->entries[log->idx];
entry->jiffies = jiffies;
entry->pos = pos;
entry->period_size = runtime->period_size;
entry->buffer_size = runtime->buffer_size;;
entry->old_hw_ptr = runtime->status->hw_ptr;
entry->hw_ptr_base = runtime->hw_ptr_base;
log->idx = (log->idx + 1) % XRUN_LOG_CNT;
}
static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
static void xrun_log_show(struct snd_pcm_substream *substream)
{
struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
struct hwptr_log_entry *entry;
char name[16];
unsigned int idx;
int cnt;
if (log == NULL)
return;
if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
return;
pcm_debug_name(substream, name, sizeof(name));
for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
entry = &log->entries[idx];
if (entry->period_size == 0)
break;
snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
"hwptr=%ld/%ld\n",
name, entry->jiffies, (unsigned long)entry->pos,
(unsigned long)entry->period_size,
(unsigned long)entry->buffer_size,
(unsigned long)entry->old_hw_ptr,
(unsigned long)entry->hw_ptr_base);
idx++;
idx %= XRUN_LOG_CNT;
}
log->hit = 1;
}
#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
#define xrun_debug(substream, mask) 0
#define xrun(substream) do { } while (0)
#define hw_ptr_error(substream, fmt, args...) do { } while (0)
#define xrun_log(substream, pos) do { } while (0)
#define xrun_log_show(substream) do { } while (0)
#endif
int snd_pcm_update_state(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t avail;
@ -209,88 +286,94 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
}
}
if (avail >= runtime->control->avail_min)
wake_up(&runtime->sleep);
wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep);
return 0;
}
#define hw_ptr_error(substream, fmt, args...) \
do { \
if (xrun_debug(substream, 1)) { \
if (printk_ratelimit()) { \
snd_printd("PCM: " fmt, ##args); \
} \
dump_stack_on_xrun(substream); \
} \
} while (0)
static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
unsigned int in_interrupt)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base;
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
snd_pcm_sframes_t hdelta, delta;
unsigned long jdelta;
old_hw_ptr = runtime->status->hw_ptr;
pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
pos = substream->ops->pointer(substream);
if (pos == SNDRV_PCM_POS_XRUN) {
xrun(substream);
return -EPIPE;
}
if (xrun_debug(substream, 8)) {
char name[16];
pcm_debug_name(substream, name, sizeof(name));
snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, "
"hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
name, (unsigned int)pos,
(unsigned int)runtime->period_size,
(unsigned int)runtime->buffer_size,
(unsigned long)old_hw_ptr,
(unsigned long)runtime->hw_ptr_base,
(unsigned long)runtime->hw_ptr_interrupt);
if (pos >= runtime->buffer_size) {
if (printk_ratelimit()) {
char name[16];
pcm_debug_name(substream, name, sizeof(name));
xrun_log_show(substream);
snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
"buffer size = %ld, period size = %ld\n",
name, pos, runtime->buffer_size,
runtime->period_size);
}
pos = 0;
}
pos -= pos % runtime->min_align;
if (xrun_debug(substream, XRUN_DEBUG_LOG))
xrun_log(substream, pos);
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
delta = new_hw_ptr - hw_ptr_interrupt;
if (hw_ptr_interrupt >= runtime->boundary) {
hw_ptr_interrupt -= runtime->boundary;
if (hw_base < runtime->boundary / 2)
/* hw_base was already lapped; recalc delta */
delta = new_hw_ptr - hw_ptr_interrupt;
}
if (delta < 0) {
if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
delta += runtime->buffer_size;
if (delta < 0) {
hw_ptr_error(substream,
"Unexpected hw_pointer value "
"(stream=%i, pos=%ld, intr_ptr=%ld)\n",
substream->stream, (long)pos,
(long)hw_ptr_interrupt);
#if 1
/* simply skipping the hwptr update seems more
* robust in some cases, e.g. on VMware with
* inaccurate timer source
*/
return 0; /* skip this update */
#else
/* rebase to interrupt position */
hw_base = new_hw_ptr = hw_ptr_interrupt;
/* align hw_base to buffer_size */
hw_base -= hw_base % runtime->buffer_size;
delta = 0;
#endif
} else {
if (in_interrupt) {
/* we know that one period was processed */
/* delta = "expected next hw_ptr" for in_interrupt != 0 */
delta = runtime->hw_ptr_interrupt + runtime->period_size;
if (delta > new_hw_ptr) {
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary)
hw_base = 0;
new_hw_ptr = hw_base + pos;
goto __delta;
}
}
/* new_hw_ptr might be lower than old_hw_ptr in case when */
/* pointer crosses the end of the ring buffer */
if (new_hw_ptr < old_hw_ptr) {
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary)
hw_base = 0;
new_hw_ptr = hw_base + pos;
}
__delta:
delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
if (xrun_debug(substream, in_interrupt ?
XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
char name[16];
pcm_debug_name(substream, name, sizeof(name));
snd_printd("%s_update: %s: pos=%u/%u/%u, "
"hwptr=%ld/%ld/%ld/%ld\n",
in_interrupt ? "period" : "hwptr",
name,
(unsigned int)pos,
(unsigned int)runtime->period_size,
(unsigned int)runtime->buffer_size,
(unsigned long)delta,
(unsigned long)old_hw_ptr,
(unsigned long)new_hw_ptr,
(unsigned long)runtime->hw_ptr_base);
}
/* something must be really wrong */
if (delta >= runtime->buffer_size + runtime->period_size) {
hw_ptr_error(substream,
"Unexpected hw_pointer value %s"
"(stream=%i, pos=%ld, new_hw_ptr=%ld, "
"old_hw_ptr=%ld)\n",
in_interrupt ? "[Q] " : "[P]",
substream->stream, (long)pos,
(long)new_hw_ptr, (long)old_hw_ptr);
return 0;
}
/* Do jiffies check only in xrun_debug mode */
if (!xrun_debug(substream, 4))
if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
goto no_jiffies_check;
/* Skip the jiffies check for hardwares with BATCH flag.
@ -299,7 +382,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
*/
if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
goto no_jiffies_check;
hdelta = new_hw_ptr - old_hw_ptr;
hdelta = delta;
if (hdelta < runtime->delay)
goto no_jiffies_check;
hdelta -= runtime->delay;
@ -308,130 +391,68 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
delta = jdelta /
(((runtime->period_size * HZ) / runtime->rate)
+ HZ/100);
/* move new_hw_ptr according jiffies not pos variable */
new_hw_ptr = old_hw_ptr;
hw_base = delta;
/* use loop to avoid checks for delta overflows */
/* the delta value is small or zero in most cases */
while (delta > 0) {
new_hw_ptr += runtime->period_size;
if (new_hw_ptr >= runtime->boundary)
new_hw_ptr -= runtime->boundary;
delta--;
}
/* align hw_base to buffer_size */
hw_ptr_error(substream,
"hw_ptr skipping! [Q] "
"hw_ptr skipping! %s"
"(pos=%ld, delta=%ld, period=%ld, "
"jdelta=%lu/%lu/%lu)\n",
"jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
in_interrupt ? "[Q] " : "",
(long)pos, (long)hdelta,
(long)runtime->period_size, jdelta,
((hdelta * HZ) / runtime->rate), delta);
hw_ptr_interrupt = runtime->hw_ptr_interrupt +
runtime->period_size * delta;
if (hw_ptr_interrupt >= runtime->boundary)
hw_ptr_interrupt -= runtime->boundary;
/* rebase to interrupt position */
hw_base = new_hw_ptr = hw_ptr_interrupt;
/* align hw_base to buffer_size */
hw_base -= hw_base % runtime->buffer_size;
((hdelta * HZ) / runtime->rate), hw_base,
(unsigned long)old_hw_ptr,
(unsigned long)new_hw_ptr);
/* reset values to proper state */
delta = 0;
hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
}
no_jiffies_check:
if (delta > runtime->period_size + runtime->period_size / 2) {
hw_ptr_error(substream,
"Lost interrupts? "
"(stream=%i, delta=%ld, intr_ptr=%ld)\n",
"Lost interrupts? %s"
"(stream=%i, delta=%ld, new_hw_ptr=%ld, "
"old_hw_ptr=%ld)\n",
in_interrupt ? "[Q] " : "",
substream->stream, (long)delta,
(long)hw_ptr_interrupt);
/* rebase hw_ptr_interrupt */
hw_ptr_interrupt =
new_hw_ptr - new_hw_ptr % runtime->period_size;
(long)new_hw_ptr,
(long)old_hw_ptr);
}
runtime->hw_ptr_interrupt = hw_ptr_interrupt;
if (runtime->status->hw_ptr == new_hw_ptr)
return 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
if (runtime->status->hw_ptr == new_hw_ptr)
return 0;
if (in_interrupt) {
runtime->hw_ptr_interrupt = new_hw_ptr -
(new_hw_ptr % runtime->period_size);
}
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
runtime->hw_ptr_jiffies = jiffies;
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
return snd_pcm_update_hw_ptr_post(substream, runtime);
return snd_pcm_update_state(substream, runtime);
}
/* CAUTION: call it with irq disabled */
int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
snd_pcm_sframes_t delta;
unsigned long jdelta;
old_hw_ptr = runtime->status->hw_ptr;
pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
if (pos == SNDRV_PCM_POS_XRUN) {
xrun(substream);
return -EPIPE;
}
if (xrun_debug(substream, 16)) {
char name[16];
pcm_debug_name(substream, name, sizeof(name));
snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
"hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
name, (unsigned int)pos,
(unsigned int)runtime->period_size,
(unsigned int)runtime->buffer_size,
(unsigned long)old_hw_ptr,
(unsigned long)runtime->hw_ptr_base,
(unsigned long)runtime->hw_ptr_interrupt);
}
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
delta = new_hw_ptr - old_hw_ptr;
jdelta = jiffies - runtime->hw_ptr_jiffies;
if (delta < 0) {
delta += runtime->buffer_size;
if (delta < 0) {
hw_ptr_error(substream,
"Unexpected hw_pointer value [2] "
"(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
substream->stream, (long)pos,
(long)old_hw_ptr, jdelta);
return 0;
}
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary)
hw_base = 0;
new_hw_ptr = hw_base + pos;
}
/* Do jiffies check only in xrun_debug mode */
if (!xrun_debug(substream, 4))
goto no_jiffies_check;
if (delta < runtime->delay)
goto no_jiffies_check;
delta -= runtime->delay;
if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
hw_ptr_error(substream,
"hw_ptr skipping! "
"(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
(long)pos, (long)delta,
(long)runtime->period_size, jdelta,
((delta * HZ) / runtime->rate));
return 0;
}
no_jiffies_check:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
if (runtime->status->hw_ptr == new_hw_ptr)
return 0;
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
runtime->hw_ptr_jiffies = jiffies;
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
return snd_pcm_update_hw_ptr_post(substream, runtime);
return snd_pcm_update_hw_ptr0(substream, 0);
}
/**
@ -745,10 +766,13 @@ int snd_interval_ratnum(struct snd_interval *i,
unsigned int rats_count, struct snd_ratnum *rats,
unsigned int *nump, unsigned int *denp)
{
unsigned int best_num, best_diff, best_den;
unsigned int best_num, best_den;
int best_diff;
unsigned int k;
struct snd_interval t;
int err;
unsigned int result_num, result_den;
int result_diff;
best_num = best_den = best_diff = 0;
for (k = 0; k < rats_count; ++k) {
@ -770,6 +794,8 @@ int snd_interval_ratnum(struct snd_interval *i,
den -= r;
}
diff = num - q * den;
if (diff < 0)
diff = -diff;
if (best_num == 0 ||
diff * best_den < best_diff * den) {
best_diff = diff;
@ -784,6 +810,9 @@ int snd_interval_ratnum(struct snd_interval *i,
t.min = div_down(best_num, best_den);
t.openmin = !!(best_num % best_den);
result_num = best_num;
result_diff = best_diff;
result_den = best_den;
best_num = best_den = best_diff = 0;
for (k = 0; k < rats_count; ++k) {
unsigned int num = rats[k].num;
@ -806,6 +835,8 @@ int snd_interval_ratnum(struct snd_interval *i,
den += rats[k].den_step - r;
}
diff = q * den - num;
if (diff < 0)
diff = -diff;
if (best_num == 0 ||
diff * best_den < best_diff * den) {
best_diff = diff;
@ -825,10 +856,14 @@ int snd_interval_ratnum(struct snd_interval *i,
return err;
if (snd_interval_single(i)) {
if (best_diff * result_den < result_diff * best_den) {
result_num = best_num;
result_den = best_den;
}
if (nump)
*nump = best_num;
*nump = result_num;
if (denp)
*denp = best_den;
*denp = result_den;
}
return err;
}
@ -1643,7 +1678,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
snd_pcm_stream_lock_irqsave(substream, flags);
if (!snd_pcm_running(substream) ||
snd_pcm_update_hw_ptr_interrupt(substream) < 0)
snd_pcm_update_hw_ptr0(substream, 1) < 0)
goto _end;
if (substream->timer_running)
@ -1674,7 +1709,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
long tout;
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
add_wait_queue(&runtime->tsleep, &wait);
for (;;) {
if (signal_pending(current)) {
err = -ERESTARTSYS;
@ -1717,7 +1752,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
break;
}
_endloop:
remove_wait_queue(&runtime->sleep, &wait);
remove_wait_queue(&runtime->tsleep, &wait);
*availp = avail;
return err;
}
@ -1776,6 +1811,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
goto _end_unlock;
}
runtime->twake = 1;
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t avail;
@ -1797,15 +1833,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
if (frames > cont)
frames = cont;
if (snd_BUG_ON(!frames)) {
runtime->twake = 0;
snd_pcm_stream_unlock_irq(substream);
return -EINVAL;
}
appl_ptr = runtime->control->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_pcm_stream_unlock_irq(substream);
if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
goto _end;
err = transfer(substream, appl_ofs, data, offset, frames);
snd_pcm_stream_lock_irq(substream);
if (err < 0)
goto _end_unlock;
switch (runtime->status->state) {
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
@ -1834,8 +1872,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
}
}
_end_unlock:
runtime->twake = 0;
if (xfer > 0 && err >= 0)
snd_pcm_update_state(substream, runtime);
snd_pcm_stream_unlock_irq(substream);
_end:
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
@ -1993,6 +2033,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
goto _end_unlock;
}
runtime->twake = 1;
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t avail;
@ -2021,15 +2062,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
if (frames > cont)
frames = cont;
if (snd_BUG_ON(!frames)) {
runtime->twake = 0;
snd_pcm_stream_unlock_irq(substream);
return -EINVAL;
}
appl_ptr = runtime->control->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_pcm_stream_unlock_irq(substream);
if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
goto _end;
err = transfer(substream, appl_ofs, data, offset, frames);
snd_pcm_stream_lock_irq(substream);
if (err < 0)
goto _end_unlock;
switch (runtime->status->state) {
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
@ -2052,8 +2095,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
xfer += frames;
}
_end_unlock:
runtime->twake = 0;
if (xfer > 0 && err >= 0)
snd_pcm_update_state(substream, runtime);
snd_pcm_stream_unlock_irq(substream);
_end:
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}

View File

@ -23,6 +23,7 @@
#include <linux/time.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/info.h>
@ -434,3 +435,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL(snd_pcm_lib_free_pages);
int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
size_t size, gfp_t gfp_flags)
{
struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream))
return -EINVAL;
runtime = substream->runtime;
if (runtime->dma_area) {
if (runtime->dma_bytes >= size)
return 0; /* already large enough */
vfree(runtime->dma_area);
}
runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
if (!runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;
return 1;
}
EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
/**
* snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
* @substream: the substream with a buffer allocated by
* snd_pcm_lib_alloc_vmalloc_buffer()
*/
int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream))
return -EINVAL;
runtime = substream->runtime;
vfree(runtime->dma_area);
runtime->dma_area = NULL;
return 0;
}
EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
/**
* snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct
* @substream: the substream with a buffer allocated by
* snd_pcm_lib_alloc_vmalloc_buffer()
* @offset: offset in the buffer
*
* This function is to be used as the page callback in the PCM ops.
*/
struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
return vmalloc_to_page(substream->runtime->dma_area + offset);
}
EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);

View File

@ -27,6 +27,7 @@
#include <linux/pm_qos_params.h>
#include <linux/uio.h>
#include <linux/dma-mapping.h>
#include <linux/math64.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@ -315,10 +316,10 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!params->info)
params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
if (!params->fifo_size) {
if (snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
if (snd_mask_min(m) == snd_mask_max(m) &&
snd_interval_min(i) == snd_interval_max(i)) {
changed = substream->ops->ioctl(substream,
SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
if (changed < 0)
@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
return usecs;
}
static int calc_boundary(struct snd_pcm_runtime *runtime)
{
u_int64_t boundary;
boundary = (u_int64_t)runtime->buffer_size *
(u_int64_t)runtime->period_size;
#if BITS_PER_LONG < 64
/* try to find lowest common multiple for buffer and period */
if (boundary > LONG_MAX - runtime->buffer_size) {
u_int32_t remainder = -1;
u_int32_t divident = runtime->buffer_size;
u_int32_t divisor = runtime->period_size;
while (remainder) {
remainder = divident % divisor;
if (remainder) {
divident = divisor;
divisor = remainder;
}
}
boundary = div_u64(boundary, divisor);
if (boundary > LONG_MAX - runtime->buffer_size)
return -ERANGE;
}
#endif
if (boundary == 0)
return -ERANGE;
runtime->boundary = boundary;
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
runtime->boundary *= 2;
return 0;
}
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->stop_threshold = runtime->buffer_size;
runtime->silence_threshold = 0;
runtime->silence_size = 0;
runtime->boundary = runtime->buffer_size;
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
runtime->boundary *= 2;
err = calc_boundary(runtime);
if (err < 0)
goto _error;
snd_pcm_timer_resolution_change(substream);
runtime->status->state = SNDRV_PCM_STATE_SETUP;
@ -516,6 +549,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
struct snd_pcm_sw_params *params)
{
struct snd_pcm_runtime *runtime;
int err;
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
@ -540,6 +574,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
if (params->silence_threshold > runtime->buffer_size)
return -EINVAL;
}
err = 0;
snd_pcm_stream_lock_irq(substream);
runtime->tstamp_mode = params->tstamp_mode;
runtime->period_step = params->period_step;
@ -553,10 +588,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
wake_up(&runtime->sleep);
err = snd_pcm_update_state(substream, runtime);
}
snd_pcm_stream_unlock_irq(substream);
return 0;
return err;
}
static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
@ -917,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
runtime->status->state = state;
}
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
}
static struct action_ops snd_pcm_action_stop = {
@ -1002,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
SNDRV_TIMER_EVENT_MPAUSE,
&runtime->trigger_tstamp);
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
} else {
runtime->status->state = SNDRV_PCM_STATE_RUNNING;
if (substream->timer)
@ -1059,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
runtime->status->suspended_state = runtime->status->state;
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
}
static struct action_ops snd_pcm_action_suspend = {
@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
long size;
unsigned long offset;
#ifdef pgprot_noncached
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
#endif
area->vm_flags |= VM_IO;
size = area->vm_end - area->vm_start;
offset = area->vm_pgoff << PAGE_SHIFT;
@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
#endif /* SNDRV_PCM_INFO_MMAP */
/* mmap callback with pgprot_noncached */
int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
return snd_pcm_default_mmap(substream, area);
}
EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached);
/*
* mmap DMA buffer
*/

View File

@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
if (p->cmd == cmd)
return p->func(client, arg);
}
snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",
snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
return -ENOTTY;
}

View File

@ -33,22 +33,21 @@
#define SKEW_BASE 0x10000 /* 16bit shift */
static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick,
int tempo, int ppq)
static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
{
if (tempo < 1000000)
tick->resolution = (tempo * 1000) / ppq;
if (tmr->tempo < 1000000)
tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
else {
/* might overflow.. */
unsigned int s;
s = tempo % ppq;
s = (s * 1000) / ppq;
tick->resolution = (tempo / ppq) * 1000;
tick->resolution += s;
s = tmr->tempo % tmr->ppq;
s = (s * 1000) / tmr->ppq;
tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
tmr->tick.resolution += s;
}
if (tick->resolution <= 0)
tick->resolution = 1;
snd_seq_timer_update_tick(tick, 0);
if (tmr->tick.resolution <= 0)
tmr->tick.resolution = 1;
snd_seq_timer_update_tick(&tmr->tick, 0);
}
/* create new timer (constructor) */
@ -96,7 +95,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
/* setup defaults */
tmr->ppq = 96; /* 96 PPQ */
tmr->tempo = 500000; /* 120 BPM */
snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
snd_seq_timer_set_tick_resolution(tmr);
tmr->running = 0;
tmr->type = SNDRV_SEQ_TIMER_ALSA;
@ -180,7 +179,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
spin_lock_irqsave(&tmr->lock, flags);
if ((unsigned int)tempo != tmr->tempo) {
tmr->tempo = tempo;
snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
snd_seq_timer_set_tick_resolution(tmr);
}
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
@ -205,7 +204,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
}
tmr->ppq = ppq;
snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
snd_seq_timer_set_tick_resolution(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}

View File

@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
#define MAX_PCM_SUBSTREAMS 128
#define MAX_MIDI_DEVICES 2
#if 0 /* emu10k1 emulation */
#define MAX_BUFFER_SIZE (128 * 1024)
static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
{
int err;
err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
if (err < 0)
return err;
return 0;
}
#define add_playback_constraints emu10k1_playback_constraints
#endif
#if 0 /* RME9652 emulation */
#define MAX_BUFFER_SIZE (26 * 64 * 1024)
#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
#define USE_CHANNELS_MIN 26
#define USE_CHANNELS_MAX 26
#define USE_PERIODS_MIN 2
#define USE_PERIODS_MAX 2
#endif
#if 0 /* ICE1712 emulation */
#define MAX_BUFFER_SIZE (256 * 1024)
#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
#define USE_CHANNELS_MIN 10
#define USE_CHANNELS_MAX 10
#define USE_PERIODS_MIN 1
#define USE_PERIODS_MAX 1024
#endif
#if 0 /* UDA1341 emulation */
#define MAX_BUFFER_SIZE (16380)
#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
#define USE_CHANNELS_MIN 2
#define USE_CHANNELS_MAX 2
#define USE_PERIODS_MIN 2
#define USE_PERIODS_MAX 255
#endif
#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */
#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
#define USE_CHANNELS_MIN 2
#define USE_CHANNELS_MAX 2
#define USE_RATE SNDRV_PCM_RATE_48000
#define USE_RATE_MIN 48000
#define USE_RATE_MAX 48000
#endif
#if 0 /* CA0106 */
#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
#define USE_CHANNELS_MIN 2
#define USE_CHANNELS_MAX 2
#define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000)
#define USE_RATE_MIN 48000
#define USE_RATE_MAX 192000
#define MAX_BUFFER_SIZE ((65536-64)*8)
#define MAX_PERIOD_SIZE (65536-64)
#define USE_PERIODS_MIN 2
#define USE_PERIODS_MAX 8
#endif
/* defaults */
#ifndef MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE (64*1024)
#endif
#ifndef MAX_PERIOD_SIZE
#define MIN_PERIOD_SIZE 64
#define MAX_PERIOD_SIZE MAX_BUFFER_SIZE
#endif
#ifndef USE_FORMATS
#define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
#endif
#ifndef USE_RATE
#define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
#define USE_RATE_MIN 5500
#define USE_RATE_MAX 48000
#endif
#ifndef USE_CHANNELS_MIN
#define USE_CHANNELS_MIN 1
#endif
#ifndef USE_CHANNELS_MAX
#define USE_CHANNELS_MAX 2
#endif
#ifndef USE_PERIODS_MIN
#define USE_PERIODS_MIN 1
#endif
#ifndef USE_PERIODS_MAX
#define USE_PERIODS_MAX 1024
#endif
#ifndef add_playback_constraints
#define add_playback_constraints(x) 0
#endif
#ifndef add_capture_constraints
#define add_capture_constraints(x) 0
#endif
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};
static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
//static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Soundcard model.");
module_param_array(pcm_devs, int, NULL, 0444);
MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
module_param_array(pcm_substreams, int, NULL, 0444);
@ -193,15 +109,120 @@ struct dummy_timer_ops {
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
};
struct dummy_model {
const char *name;
int (*playback_constraints)(struct snd_pcm_runtime *runtime);
int (*capture_constraints)(struct snd_pcm_runtime *runtime);
u64 formats;
size_t buffer_bytes_max;
size_t period_bytes_min;
size_t period_bytes_max;
unsigned int periods_min;
unsigned int periods_max;
unsigned int rates;
unsigned int rate_min;
unsigned int rate_max;
unsigned int channels_min;
unsigned int channels_max;
};
struct snd_dummy {
struct snd_card *card;
struct dummy_model *model;
struct snd_pcm *pcm;
struct snd_pcm_hardware pcm_hw;
spinlock_t mixer_lock;
int mixer_volume[MIXER_ADDR_LAST+1][2];
int capture_source[MIXER_ADDR_LAST+1][2];
const struct dummy_timer_ops *timer_ops;
};
/*
* card models
*/
static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
{
int err;
err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
if (err < 0)
return err;
return 0;
}
struct dummy_model model_emu10k1 = {
.name = "emu10k1",
.playback_constraints = emu10k1_playback_constraints,
.buffer_bytes_max = 128 * 1024,
};
struct dummy_model model_rme9652 = {
.name = "rme9652",
.buffer_bytes_max = 26 * 64 * 1024,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 26,
.channels_max = 26,
.periods_min = 2,
.periods_max = 2,
};
struct dummy_model model_ice1712 = {
.name = "ice1712",
.buffer_bytes_max = 256 * 1024,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 10,
.channels_max = 10,
.periods_min = 1,
.periods_max = 1024,
};
struct dummy_model model_uda1341 = {
.name = "uda1341",
.buffer_bytes_max = 16380,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 2,
.channels_max = 2,
.periods_min = 2,
.periods_max = 255,
};
struct dummy_model model_ac97 = {
.name = "ac97",
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
};
struct dummy_model model_ca0106 = {
.name = "ca0106",
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.buffer_bytes_max = ((65536-64)*8),
.period_bytes_max = (65536-64),
.periods_min = 2,
.periods_max = 8,
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000,
.rate_min = 48000,
.rate_max = 192000,
};
struct dummy_model *dummy_models[] = {
&model_emu10k1,
&model_rme9652,
&model_ice1712,
&model_uda1341,
&model_ac97,
&model_ca0106,
NULL
};
/*
* system timer interface
*/
@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = {
.channels_min = USE_CHANNELS_MIN,
.channels_max = USE_CHANNELS_MAX,
.buffer_bytes_max = MAX_BUFFER_SIZE,
.period_bytes_min = 64,
.period_bytes_min = MIN_PERIOD_SIZE,
.period_bytes_max = MAX_PERIOD_SIZE,
.periods_min = USE_PERIODS_MIN,
.periods_max = USE_PERIODS_MAX,
@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
static int dummy_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
struct dummy_model *model = dummy->model;
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
return err;
runtime->hw = dummy_pcm_hardware;
runtime->hw = dummy->pcm_hw;
if (substream->pcm->device & 1) {
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
err = add_playback_constraints(substream->runtime);
else
err = add_capture_constraints(substream->runtime);
if (model == NULL)
return 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (model->playback_constraints)
err = model->playback_constraints(substream->runtime);
} else {
if (model->capture_constraints)
err = model->capture_constraints(substream->runtime);
}
if (err < 0) {
dummy->timer_ops->free(substream);
return err;
@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
/*
* proc interface
*/
static void print_formats(struct snd_info_buffer *buffer)
static void print_formats(struct snd_dummy *dummy,
struct snd_info_buffer *buffer)
{
int i;
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
if (dummy_pcm_hardware.formats & (1ULL << i))
if (dummy->pcm_hw.formats & (1ULL << i))
snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
}
}
static void print_rates(struct snd_info_buffer *buffer)
static void print_rates(struct snd_dummy *dummy,
struct snd_info_buffer *buffer)
{
static int rates[] = {
5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer)
};
int i;
if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS)
if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)
snd_iprintf(buffer, " continuous");
if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT)
if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)
snd_iprintf(buffer, " knot");
for (i = 0; i < ARRAY_SIZE(rates); i++)
if (dummy_pcm_hardware.rates & (1 << i))
if (dummy->pcm_hw.rates & (1 << i))
snd_iprintf(buffer, " %d", rates[i]);
}
#define get_dummy_int_ptr(ofs) \
(unsigned int *)((char *)&dummy_pcm_hardware + (ofs))
#define get_dummy_ll_ptr(ofs) \
(unsigned long long *)((char *)&dummy_pcm_hardware + (ofs))
#define get_dummy_int_ptr(dummy, ofs) \
(unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs))
#define get_dummy_ll_ptr(dummy, ofs) \
(unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs))
struct dummy_hw_field {
const char *name;
@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = {
static void dummy_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_dummy *dummy = entry->private_data;
int i;
for (i = 0; i < ARRAY_SIZE(fields); i++) {
snd_iprintf(buffer, "%s ", fields[i].name);
if (fields[i].size == sizeof(int))
snd_iprintf(buffer, fields[i].format,
*get_dummy_int_ptr(fields[i].offset));
*get_dummy_int_ptr(dummy, fields[i].offset));
else
snd_iprintf(buffer, fields[i].format,
*get_dummy_ll_ptr(fields[i].offset));
*get_dummy_ll_ptr(dummy, fields[i].offset));
if (!strcmp(fields[i].name, "formats"))
print_formats(buffer);
print_formats(dummy, buffer);
else if (!strcmp(fields[i].name, "rates"))
print_rates(buffer);
print_rates(dummy, buffer);
snd_iprintf(buffer, "\n");
}
}
@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry,
static void dummy_proc_write(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_dummy *dummy = entry->private_data;
char line[64];
while (!snd_info_get_line(buffer, line, sizeof(line))) {
@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry,
if (strict_strtoull(item, 0, &val))
continue;
if (fields[i].size == sizeof(int))
*get_dummy_int_ptr(fields[i].offset) = val;
*get_dummy_int_ptr(dummy, fields[i].offset) = val;
else
*get_dummy_ll_ptr(fields[i].offset) = val;
*get_dummy_ll_ptr(dummy, fields[i].offset) = val;
}
}
@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip)
snd_info_set_text_ops(entry, chip, dummy_proc_read);
entry->c.text.write = dummy_proc_write;
entry->mode |= S_IWUSR;
entry->private_data = chip;
}
}
#else
@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
{
struct snd_card *card;
struct snd_dummy *dummy;
struct dummy_model *m = NULL, **mdl;
int idx, err;
int dev = devptr->id;
@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
return err;
dummy = card->private_data;
dummy->card = card;
for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
if (strcmp(model[dev], (*mdl)->name) == 0) {
printk(KERN_INFO
"snd-dummy: Using model '%s' for card %i\n",
(*mdl)->name, card->number);
m = dummy->model = *mdl;
break;
}
}
for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
if (pcm_substreams[dev] < 1)
pcm_substreams[dev] = 1;
@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
if (err < 0)
goto __nodev;
}
dummy->pcm_hw = dummy_pcm_hardware;
if (m) {
if (m->formats)
dummy->pcm_hw.formats = m->formats;
if (m->buffer_bytes_max)
dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max;
if (m->period_bytes_min)
dummy->pcm_hw.period_bytes_min = m->period_bytes_min;
if (m->period_bytes_max)
dummy->pcm_hw.period_bytes_max = m->period_bytes_max;
if (m->periods_min)
dummy->pcm_hw.periods_min = m->periods_min;
if (m->periods_max)
dummy->pcm_hw.periods_max = m->periods_max;
if (m->rates)
dummy->pcm_hw.rates = m->rates;
if (m->rate_min)
dummy->pcm_hw.rate_min = m->rate_min;
if (m->rate_max)
dummy->pcm_hw.rate_max = m->rate_max;
if (m->channels_min)
dummy->pcm_hw.channels_min = m->channels_min;
if (m->channels_max)
dummy->pcm_hw.channels_max = m->channels_max;
}
err = snd_card_dummy_new_mixer(dummy);
if (err < 0)
goto __nodev;

View File

@ -46,7 +46,6 @@
*/
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/asoundef.h>
@ -55,55 +54,6 @@
#include "vx_cmd.h"
/*
* we use a vmalloc'ed (sg-)buffer
*/
/* get the physical page pointer on the given offset */
static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
unsigned long offset)
{
void *pageptr = subs->runtime->dma_area + offset;
return vmalloc_to_page(pageptr);
}
/*
* allocate a buffer via vmalloc_32().
* called from hw_params
* NOTE: this may be called not only once per pcm open!
*/
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
{
struct snd_pcm_runtime *runtime = subs->runtime;
if (runtime->dma_area) {
/* already allocated */
if (runtime->dma_bytes >= size)
return 0; /* already enough large */
vfree(runtime->dma_area);
}
runtime->dma_area = vmalloc_32(size);
if (! runtime->dma_area)
return -ENOMEM;
memset(runtime->dma_area, 0, size);
runtime->dma_bytes = size;
return 1; /* changed */
}
/*
* free the buffer.
* called from hw_free callback
* NOTE: this may be called not only once per pcm open!
*/
static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
{
struct snd_pcm_runtime *runtime = subs->runtime;
vfree(runtime->dma_area);
runtime->dma_area = NULL;
return 0;
}
/*
* read three pending pcm bytes via inb()
*/
@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs)
static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
return snd_pcm_lib_alloc_vmalloc_32_buffer
(subs, params_buffer_bytes(hw_params));
}
/*
@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
*/
static int vx_pcm_hw_free(struct snd_pcm_substream *subs)
{
return snd_pcm_free_vmalloc_buffer(subs);
return snd_pcm_lib_free_vmalloc_buffer(subs);
}
/*
@ -953,7 +904,8 @@ static struct snd_pcm_ops vx_pcm_playback_ops = {
.prepare = vx_pcm_prepare,
.trigger = vx_pcm_trigger,
.pointer = vx_pcm_playback_pointer,
.page = snd_pcm_get_vmalloc_page,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
};
@ -1173,7 +1125,8 @@ static struct snd_pcm_ops vx_pcm_capture_ops = {
.prepare = vx_pcm_prepare,
.trigger = vx_pcm_trigger,
.pointer = vx_pcm_capture_pointer,
.page = snd_pcm_get_vmalloc_page,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
};

View File

@ -63,15 +63,16 @@ config SND_AD1848
will be called snd-ad1848.
config SND_ALS100
tristate "Avance Logic ALS100/ALS120"
tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx"
depends on PNP
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_SB16_DSP
help
Say Y here to include support for soundcards based on Avance
Logic ALS100, ALS110, ALS120 and ALS200 chips.
Say Y here to include support for soundcards based on the
Diamond Technologies DT-019X or Avance Logic chips: ALS007,
ALS100, ALS110, ALS120 and ALS200 chips.
To compile this driver as a module, choose M here: the module
will be called snd-als100.
@ -127,20 +128,6 @@ config SND_CS4236
To compile this driver as a module, choose M here: the module
will be called snd-cs4236.
config SND_DT019X
tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
depends on PNP
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_SB16_DSP
help
Say Y here to include support for soundcards based on the
Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
To compile this driver as a module, choose M here: the module
will be called snd-dt019x.
config SND_ES968
tristate "Generic ESS ES968 driver"
depends on PNP
@ -252,6 +239,22 @@ config SND_INTERWAVE_STB
To compile this driver as a module, choose M here: the module
will be called snd-interwave-stb.
config SND_JAZZ16
tristate "Media Vision Jazz16 card and compatibles"
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_SB8_DSP
help
Say Y here to include support for soundcards based on the
Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16),
codec MVA416 (CS4216) and mixer MVA514 (ICS2514).
Media Vision's Jazz16 cards were sold under names Pro Sonic 16,
Premium 3-D and Pro 3-D. There were also OEMs cards with the
Jazz16 chipset.
To compile this driver as a module, choose M here: the module
will be called snd-jazz16.
config SND_OPL3SA2
tristate "Yamaha OPL3-SA2/SA3"
select SND_OPL3_LIB

View File

@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
snd-cmi8330-objs := cmi8330.o
snd-dt019x-objs := dt019x.o
snd-es18xx-objs := es18xx.o
snd-opl3sa2-objs := opl3sa2.o
snd-sc6000-objs := sc6000.o
@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
obj-$(CONFIG_SND_DT019X) += snd-dt019x.o
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
obj-$(CONFIG_SND_SC6000) += snd-sc6000.o

View File

@ -2,9 +2,13 @@
/*
card-als100.c - driver for Avance Logic ALS100 based soundcards.
Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>
Thanks to Pierfrancesco 'qM2' Passerini.
Generalised for soundcards based on DT-0196 and ALS-007 chips
by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
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
@ -33,10 +37,10 @@
#define PFX "als100: "
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
MODULE_DESCRIPTION("Avance Logic ALS1X0");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
"{Avance Logic ALS-007}}"
"{{Avance Logic,ALS100 - PRO16PNP},"
"{Avance Logic,ALS110},"
"{Avance Logic,ALS120},"
"{Avance Logic,ALS200},"
@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
"{Avance Logic,ALS120},"
"{RTL,RTL3000}}");
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
MODULE_LICENSE("GPL");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for als100 based soundcard.");
MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for als100 based soundcard.");
MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable als100 based soundcard.");
MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
MODULE_ALIAS("snd-dt019x");
struct snd_card_als100 {
int dev_no;
struct pnp_dev *dev;
struct pnp_dev *devmpu;
struct pnp_dev *devopl;
@ -72,25 +80,43 @@ struct snd_card_als100 {
};
static struct pnp_card_device_id snd_als100_pnpids[] = {
/* DT197A30 */
{ .id = "RWB1688",
.devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
.driver_data = SB_HW_DT019X },
/* DT0196 / ALS-007 */
{ .id = "ALS0007",
.devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
.driver_data = SB_HW_DT019X },
/* ALS100 - PRO16PNP */
{ .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
{ .id = "ALS0001",
.devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
.driver_data = SB_HW_ALS100 },
/* ALS110 - MF1000 - Digimate 3D Sound */
{ .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } },
{ .id = "ALS0110",
.devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },
.driver_data = SB_HW_ALS100 },
/* ALS120 */
{ .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
{ .id = "ALS0120",
.devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
.driver_data = SB_HW_ALS100 },
/* ALS200 */
{ .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } },
{ .id = "ALS0200",
.devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },
.driver_data = SB_HW_ALS100 },
/* ALS200 OEM */
{ .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } },
{ .id = "ALS0200",
.devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },
.driver_data = SB_HW_ALS100 },
/* RTL3000 */
{ .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
{ .id = "", } /* end */
{ .id = "RTL3000",
.devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
.driver_data = SB_HW_ALS100 },
{ .id = "" } /* end */
};
MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
#define DRIVER_NAME "snd-card-als100"
static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
struct pnp_card_link *card,
const struct pnp_card_device_id *id)
@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
return err;
}
port[dev] = pnp_port_start(pdev, 0);
dma8[dev] = pnp_dma(pdev, 1);
dma16[dev] = pnp_dma(pdev, 0);
if (id->driver_data == SB_HW_DT019X)
dma8[dev] = pnp_dma(pdev, 0);
else {
dma8[dev] = pnp_dma(pdev, 1);
dma16[dev] = pnp_dma(pdev, 0);
}
irq[dev] = pnp_irq(pdev, 0);
pdev = acard->devmpu;
@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev,
}
snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_sbdsp_create(card, port[dev],
irq[dev],
snd_sb16dsp_interrupt,
dma8[dev],
dma16[dev],
SB_HW_ALS100, &chip)) < 0) {
if (pid->driver_data == SB_HW_DT019X)
dma16[dev] = -1;
error = snd_sbdsp_create(card, port[dev], irq[dev],
snd_sb16dsp_interrupt,
dma8[dev], dma16[dev],
pid->driver_data,
&chip);
if (error < 0) {
snd_card_free(card);
return error;
}
acard->chip = chip;
strcpy(card->driver, "ALS100");
strcpy(card->shortname, "Avance Logic ALS100");
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
card->shortname, chip->name, chip->port,
irq[dev], dma8[dev], dma16[dev]);
if (pid->driver_data == SB_HW_DT019X) {
strcpy(card->driver, "DT-019X");
strcpy(card->shortname, "Diamond Tech. DT-019X");
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
card->shortname, chip->name, chip->port,
irq[dev], dma8[dev]);
} else {
strcpy(card->driver, "ALS100");
strcpy(card->shortname, "Avance Logic ALS100");
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
card->shortname, chip->name, chip->port,
irq[dev], dma8[dev], dma16[dev]);
}
if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
snd_card_free(card);
@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev,
}
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100,
int mpu_type = MPU401_HW_ALS100;
if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
mpu_irq[dev] = -1;
if (pid->driver_data == SB_HW_DT019X)
mpu_type = MPU401_HW_MPU401;
if (snd_mpu401_uart_new(card, 0,
mpu_type,
mpu_port[dev], 0,
mpu_irq[dev], IRQF_DISABLED,
mpu_irq[dev],
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
NULL) < 0)
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
}
@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard)
static struct pnp_card_driver als100_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "als100",
.name = "als100",
.id_table = snd_als100_pnpids,
.probe = snd_als100_pnp_detect,
.remove = __devexit_p(snd_als100_pnp_remove),
@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void)
if (!als100_devices) {
pnp_unregister_card_driver(&als100_pnpc_driver);
#ifdef MODULE
snd_printk(KERN_ERR "no ALS100 based soundcards found\n");
snd_printk(KERN_ERR "no Avance Logic based soundcards found\n");
#endif
return -ENODEV;
}

View File

@ -1,321 +0,0 @@
/*
dt019x.c - driver for Diamond Technologies DT-0197H based soundcards.
Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it>
Generalised for soundcards based on DT-0196 and ALS-007 chips
by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
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/init.h>
#include <linux/wait.h>
#include <linux/pnp.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/sb.h>
#define PFX "dt019x: "
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
"{Avance Logic ALS-007}}");
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; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard.");
struct snd_card_dt019x {
struct pnp_dev *dev;
struct pnp_dev *devmpu;
struct pnp_dev *devopl;
struct snd_sb *chip;
};
static struct pnp_card_device_id snd_dt019x_pnpids[] = {
/* DT197A30 */
{ .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
/* DT0196 / ALS-007 */
{ .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
{ .id = "", }
};
MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids);
#define DRIVER_NAME "snd-card-dt019x"
static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
struct pnp_card_link *card,
const struct pnp_card_device_id *pid)
{
struct pnp_dev *pdev;
int err;
acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
if (acard->dev == NULL)
return -ENODEV;
acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL);
pdev = acard->dev;
err = pnp_activate_dev(pdev);
if (err < 0) {
snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n");
return err;
}
port[dev] = pnp_port_start(pdev, 0);
dma8[dev] = pnp_dma(pdev, 0);
irq[dev] = pnp_irq(pdev, 0);
snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n",
port[dev],irq[dev],dma8[dev]);
pdev = acard->devmpu;
if (pdev != NULL) {
err = pnp_activate_dev(pdev);
if (err < 0) {
pnp_release_card_device(pdev);
snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n");
goto __mpu_error;
}
mpu_port[dev] = pnp_port_start(pdev, 0);
mpu_irq[dev] = pnp_irq(pdev, 0);
snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n",
mpu_port[dev],mpu_irq[dev]);
} else {
__mpu_error:
acard->devmpu = NULL;
mpu_port[dev] = -1;
}
pdev = acard->devopl;
if (pdev != NULL) {
err = pnp_activate_dev(pdev);
if (err < 0) {
pnp_release_card_device(pdev);
snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n");
goto __fm_error;
}
fm_port[dev] = pnp_port_start(pdev, 0);
snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]);
} else {
__fm_error:
acard->devopl = NULL;
fm_port[dev] = -1;
}
return 0;
}
static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid)
{
int error;
struct snd_sb *chip;
struct snd_card *card;
struct snd_card_dt019x *acard;
struct snd_opl3 *opl3;
error = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_card_dt019x), &card);
if (error < 0)
return error;
acard = card->private_data;
snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
return error;
}
if ((error = snd_sbdsp_create(card, port[dev],
irq[dev],
snd_sb16dsp_interrupt,
dma8[dev],
-1,
SB_HW_DT019X,
&chip)) < 0) {
snd_card_free(card);
return error;
}
acard->chip = chip;
strcpy(card->driver, "DT-019X");
strcpy(card->shortname, "Diamond Tech. DT-019X");
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
card->shortname, chip->name, chip->port,
irq[dev], dma8[dev]);
if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
snd_card_free(card);
return error;
}
if ((error = snd_sbmixer_new(chip)) < 0) {
snd_card_free(card);
return error;
}
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
mpu_irq[dev] = -1;
if (snd_mpu401_uart_new(card, 0,
/* MPU401_HW_SB,*/
MPU401_HW_MPU401,
mpu_port[dev], 0,
mpu_irq[dev],
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
NULL) < 0)
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]);
}
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
if (snd_opl3_create(card,
fm_port[dev],
fm_port[dev] + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n",
fm_port[dev], fm_port[dev] + 2);
} else {
if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
snd_card_free(card);
return error;
}
if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
snd_card_free(card);
return error;
}
}
}
if ((error = snd_card_register(card)) < 0) {
snd_card_free(card);
return error;
}
pnp_set_card_drvdata(pcard, card);
return 0;
}
static unsigned int __devinitdata dt019x_devices;
static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card,
const struct pnp_card_device_id *pid)
{
static int dev;
int res;
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev])
continue;
res = snd_card_dt019x_probe(dev, card, pid);
if (res < 0)
return res;
dev++;
dt019x_devices++;
return 0;
}
return -ENODEV;
}
static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard)
{
snd_card_free(pnp_get_card_drvdata(pcard));
pnp_set_card_drvdata(pcard, NULL);
}
#ifdef CONFIG_PM
static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
{
struct snd_card *card = pnp_get_card_drvdata(pcard);
struct snd_card_dt019x *acard = card->private_data;
struct snd_sb *chip = acard->chip;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_sbmixer_suspend(chip);
return 0;
}
static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard)
{
struct snd_card *card = pnp_get_card_drvdata(pcard);
struct snd_card_dt019x *acard = card->private_data;
struct snd_sb *chip = acard->chip;
snd_sbdsp_reset(chip);
snd_sbmixer_resume(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif
static struct pnp_card_driver dt019x_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "dt019x",
.id_table = snd_dt019x_pnpids,
.probe = snd_dt019x_pnp_probe,
.remove = __devexit_p(snd_dt019x_pnp_remove),
#ifdef CONFIG_PM
.suspend = snd_dt019x_pnp_suspend,
.resume = snd_dt019x_pnp_resume,
#endif
};
static int __init alsa_card_dt019x_init(void)
{
int err;
err = pnp_register_card_driver(&dt019x_pnpc_driver);
if (err)
return err;
if (!dt019x_devices) {
pnp_unregister_card_driver(&dt019x_pnpc_driver);
#ifdef MODULE
snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
#endif
return -ENODEV;
}
return 0;
}
static void __exit alsa_card_dt019x_exit(void)
{
pnp_unregister_card_driver(&dt019x_pnpc_driver);
}
module_init(alsa_card_dt019x_init)
module_exit(alsa_card_dt019x_exit)

View File

@ -33,6 +33,7 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
@ -546,6 +547,93 @@ __skip_mpu:
#ifdef OPTi93X
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0);
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_TLV("Master Playback Volume", 0,
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
db_scale_5bit_3db_step),
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1,
db_scale_5bit),
WSS_DOUBLE_TLV("FM Playback Volume", 0,
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE("Line Playback Switch", 0,
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Line Playback Volume", 0,
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE("Mic Playback Switch", 0,
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Mic Playback Volume", 0,
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE_TLV("CD Playback Volume", 0,
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE("Aux Playback Switch", 0,
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Aux Playback Volume", 0,
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
};
static int __devinit snd_opti93x_mixer(struct snd_wss *chip)
{
struct snd_card *card;
unsigned int idx;
struct snd_ctl_elem_id id1, id2;
int err;
if (snd_BUG_ON(!chip || !chip->pcm))
return -EINVAL;
card = chip->card;
strcpy(card->mixername, chip->pcm->name);
memset(&id1, 0, sizeof(id1));
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* reassign AUX0 switch to CD */
strcpy(id1.name, "Aux Playback Switch");
strcpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
snd_printk(KERN_ERR "Cannot rename opti93x control\n");
return err;
}
/* reassign AUX1 switch to FM */
strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
strcpy(id2.name, "FM Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
snd_printk(KERN_ERR "Cannot rename opti93x control\n");
return err;
}
/* remove AUX1 volume */
strcpy(id1.name, "Aux Playback Volume"); id1.index = 1;
snd_ctl_remove_id(card, &id1);
/* Replace WSS volume controls with OPTi93x volume controls */
id1.index = 0;
for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
strcpy(id1.name, snd_opti93x_controls[idx].name);
snd_ctl_remove_id(card, &id1);
err = snd_ctl_add(card,
snd_ctl_new1(&snd_opti93x_controls[idx], chip));
if (err < 0)
return err;
}
return 0;
}
static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
{
struct snd_opti9xx *chip = dev_id;
@ -754,6 +842,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
error = snd_wss_mixer(codec);
if (error < 0)
return error;
#ifdef OPTi93X
error = snd_opti93x_mixer(codec);
if (error < 0)
return error;
#endif
#ifdef CS4231
error = snd_wss_timer(codec, 0, &timer);
if (error < 0)

View File

@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o
snd-sbawe-objs := sbawe.o emu8000.o
snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
snd-es968-objs := es968.o
snd-jazz16-objs := jazz16.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o
obj-$(CONFIG_SND_SB16) += snd-sb16.o
obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
obj-$(CONFIG_SND_ES968) += snd-es968.o
obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o
ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o

View File

@ -0,0 +1,404 @@
/*
* jazz16.c - driver for Media Vision Jazz16 based soundcards.
* Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
* Based on patches posted by Rask Ingemann Lambertsen and Rene Herman.
* Based on OSS Sound Blaster driver.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
#include <asm/dma.h>
#include <linux/isa.h>
#include <sound/core.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/sb.h>
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
#define PFX "jazz16: "
MODULE_DESCRIPTION("Media Vision Jazz16");
MODULE_SUPPORTED_DEVICE("{{Media Vision ??? },"
"{RTL,RTL3000}}");
MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
MODULE_LICENSE("GPL");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
static unsigned long mpu_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 dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard.");
module_param_array(port, long, NULL, 0444);
MODULE_PARM_DESC(port, "Port # for jazz16 driver.");
module_param_array(mpu_port, long, NULL, 0444);
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver.");
module_param_array(irq, int, NULL, 0444);
MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver.");
module_param_array(mpu_irq, int, NULL, 0444);
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver.");
module_param_array(dma8, int, NULL, 0444);
MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver.");
module_param_array(dma16, int, NULL, 0444);
MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver.");
#define SB_JAZZ16_WAKEUP 0xaf
#define SB_JAZZ16_SET_PORTS 0x50
#define SB_DSP_GET_JAZZ_BRD_REV 0xfa
#define SB_JAZZ16_SET_DMAINTR 0xfb
#define SB_DSP_GET_JAZZ_MODEL 0xfe
struct snd_card_jazz16 {
struct snd_sb *chip;
};
static irqreturn_t jazz16_interrupt(int irq, void *chip)
{
return snd_sb8dsp_interrupt(chip);
}
static int __devinit jazz16_configure_ports(unsigned long port,
unsigned long mpu_port, int idx)
{
unsigned char val;
if (!request_region(0x201, 1, "jazz16 config")) {
snd_printk(KERN_ERR "config port region is already in use.\n");
return -EBUSY;
}
outb(SB_JAZZ16_WAKEUP - idx, 0x201);
udelay(100);
outb(SB_JAZZ16_SET_PORTS + idx, 0x201);
udelay(100);
val = port & 0x70;
val |= (mpu_port & 0x30) >> 4;
outb(val, 0x201);
release_region(0x201, 1);
return 0;
}
static int __devinit jazz16_detect_board(unsigned long port,
unsigned long mpu_port)
{
int err;
int val;
struct snd_sb chip;
if (!request_region(port, 0x10, "jazz16")) {
snd_printk(KERN_ERR "I/O port region is already in use.\n");
return -EBUSY;
}
/* just to call snd_sbdsp_command/reset/get_byte() */
chip.port = port;
err = snd_sbdsp_reset(&chip);
if (err < 0)
for (val = 0; val < 4; val++) {
err = jazz16_configure_ports(port, mpu_port, val);
if (err < 0)
break;
err = snd_sbdsp_reset(&chip);
if (!err)
break;
}
if (err < 0) {
err = -ENODEV;
goto err_unmap;
}
if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) {
err = -EBUSY;
goto err_unmap;
}
val = snd_sbdsp_get_byte(&chip);
if (val >= 0x30)
snd_sbdsp_get_byte(&chip);
if ((val & 0xf0) != 0x10) {
err = -ENODEV;
goto err_unmap;
}
if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) {
err = -EBUSY;
goto err_unmap;
}
snd_sbdsp_get_byte(&chip);
err = snd_sbdsp_get_byte(&chip);
snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
val, err);
err = 0;
err_unmap:
release_region(port, 0x10);
return err;
}
static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq)
{
static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4,
0, 2, 5, 0, 0, 0, 0, 6 };
static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 };
if (jazz_dma_bits[chip->dma8] == 0 ||
jazz_dma_bits[chip->dma16] == 0 ||
jazz_irq_bits[chip->irq] == 0)
return -EINVAL;
if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR))
return -EBUSY;
if (!snd_sbdsp_command(chip,
jazz_dma_bits[chip->dma8] |
(jazz_dma_bits[chip->dma16] << 4)))
return -EBUSY;
if (!snd_sbdsp_command(chip,
jazz_irq_bits[chip->irq] |
(jazz_irq_bits[mpu_irq] << 4)))
return -EBUSY;
return 0;
}
static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev)
{
if (!enable[dev])
return 0;
if (port[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR "please specify port\n");
return 0;
} else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
snd_printk(KERN_ERR "incorrect port specified\n");
return 0;
}
if (dma8[dev] != SNDRV_AUTO_DMA &&
dma8[dev] != 1 && dma8[dev] != 3) {
snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
return 0;
}
if (dma16[dev] != SNDRV_AUTO_DMA &&
dma16[dev] != 5 && dma16[dev] != 7) {
snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
return 0;
}
if (mpu_port[dev] != SNDRV_AUTO_PORT &&
(mpu_port[dev] & ~0x030) != 0x300) {
snd_printk(KERN_ERR "incorrect mpu_port specified\n");
return 0;
}
if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
return 0;
}
return 1;
}
static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev)
{
struct snd_card *card;
struct snd_card_jazz16 *jazz16;
struct snd_sb *chip;
struct snd_opl3 *opl3;
static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1};
static int possible_dmas8[] = {1, 3, -1};
static int possible_dmas16[] = {5, 7, -1};
int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_card_jazz16), &card);
if (err < 0)
return err;
jazz16 = card->private_data;
xirq = irq[dev];
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
if (xirq < 0) {
snd_printk(KERN_ERR "unable to find a free IRQ\n");
err = -EBUSY;
goto err_free;
}
}
xdma8 = dma8[dev];
if (xdma8 == SNDRV_AUTO_DMA) {
xdma8 = snd_legacy_find_free_dma(possible_dmas8);
if (xdma8 < 0) {
snd_printk(KERN_ERR "unable to find a free DMA8\n");
err = -EBUSY;
goto err_free;
}
}
xdma16 = dma16[dev];
if (xdma16 == SNDRV_AUTO_DMA) {
xdma16 = snd_legacy_find_free_dma(possible_dmas16);
if (xdma16 < 0) {
snd_printk(KERN_ERR "unable to find a free DMA16\n");
err = -EBUSY;
goto err_free;
}
}
xmpu_port = mpu_port[dev];
if (xmpu_port == SNDRV_AUTO_PORT)
xmpu_port = 0;
err = jazz16_detect_board(port[dev], xmpu_port);
if (err < 0) {
printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
goto err_free;
}
err = snd_sbdsp_create(card, port[dev], irq[dev],
jazz16_interrupt,
dma8[dev], dma16[dev],
SB_HW_JAZZ16,
&chip);
if (err < 0)
goto err_free;
xmpu_irq = mpu_irq[dev];
if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT)
xmpu_irq = 0;
err = jazz16_configure_board(chip, xmpu_irq);
if (err < 0) {
printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
goto err_free;
}
jazz16->chip = chip;
strcpy(card->driver, "jazz16");
strcpy(card->shortname, "Media Vision Jazz16");
sprintf(card->longname,
"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
port[dev], xirq, xdma8, xdma16);
err = snd_sb8dsp_pcm(chip, 0, NULL);
if (err < 0)
goto err_free;
err = snd_sbmixer_new(chip);
if (err < 0)
goto err_free;
err = snd_opl3_create(card, chip->port, chip->port + 2,
OPL3_HW_AUTO, 1, &opl3);
if (err < 0)
snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
chip->port, chip->port + 2);
else {
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
goto err_free;
}
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
mpu_irq[dev] = -1;
if (snd_mpu401_uart_new(card, 0,
MPU401_HW_MPU401,
mpu_port[dev], 0,
mpu_irq[dev],
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
NULL) < 0)
snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
mpu_port[dev]);
}
snd_card_set_dev(card, devptr);
err = snd_card_register(card);
if (err < 0)
goto err_free;
dev_set_drvdata(devptr, card);
return 0;
err_free:
snd_card_free(card);
return err;
}
static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev)
{
struct snd_card *card = dev_get_drvdata(devptr);
dev_set_drvdata(devptr, NULL);
snd_card_free(card);
return 0;
}
#ifdef CONFIG_PM
static int snd_jazz16_suspend(struct device *pdev, unsigned int n,
pm_message_t state)
{
struct snd_card *card = dev_get_drvdata(pdev);
struct snd_card_jazz16 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_sbmixer_suspend(chip);
return 0;
}
static int snd_jazz16_resume(struct device *pdev, unsigned int n)
{
struct snd_card *card = dev_get_drvdata(pdev);
struct snd_card_jazz16 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
snd_sbdsp_reset(chip);
snd_sbmixer_resume(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif
static struct isa_driver snd_jazz16_driver = {
.match = snd_jazz16_match,
.probe = snd_jazz16_probe,
.remove = __devexit_p(snd_jazz16_remove),
#ifdef CONFIG_PM
.suspend = snd_jazz16_suspend,
.resume = snd_jazz16_resume,
#endif
.driver = {
.name = "jazz16"
},
};
static int __init alsa_card_jazz16_init(void)
{
return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS);
}
static void __exit alsa_card_jazz16_exit(void)
{
isa_unregister_driver(&snd_jazz16_driver);
}
module_init(alsa_card_jazz16_init)
module_exit(alsa_card_jazz16_exit)

View File

@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int mixreg, rate, size, count;
unsigned char format;
unsigned char stereo = runtime->channels > 1;
int dma;
rate = runtime->rate;
switch (chip->hardware) {
case SB_HW_JAZZ16:
if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
if (chip->mode & SB_MODE_CAPTURE_16)
return -EBUSY;
else
chip->mode |= SB_MODE_PLAYBACK_16;
}
chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
break;
case SB_HW_PRO:
if (runtime->channels > 1) {
if (snd_BUG_ON(rate != SB8_RATE(11025) &&
@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
default:
return -EINVAL;
}
if (chip->mode & SB_MODE_PLAYBACK_16) {
format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
dma = chip->dma16;
} else {
format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
chip->mode |= SB_MODE_PLAYBACK_8;
dma = chip->dma8;
}
size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
if (runtime->channels > 1) {
if (chip->hardware == SB_HW_JAZZ16)
snd_sbdsp_command(chip, format);
else if (stereo) {
/* set playback stereo mode */
spin_lock(&chip->mixer_lock);
mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
/* Soundblaster hardware programming reference guide, 3-23 */
snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
runtime->dma_area[0] = 0x80;
snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE);
snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
/* force interrupt */
chip->mode = SB_MODE_HALT;
snd_sbdsp_command(chip, SB_DSP_OUTPUT);
snd_sbdsp_command(chip, 0);
snd_sbdsp_command(chip, 0);
}
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
if (runtime->channels > 1) {
if (stereo) {
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
spin_lock(&chip->mixer_lock);
/* save output filter status and turn it off */
@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
snd_sbdsp_command(chip, 256 - runtime->rate_den);
}
if (chip->playback_format != SB_DSP_OUTPUT) {
if (chip->mode & SB_MODE_PLAYBACK_16)
count /= 2;
count--;
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
snd_sbdsp_command(chip, count & 0xff);
snd_sbdsp_command(chip, count >> 8);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_dma_program(chip->dma8, runtime->dma_addr,
snd_dma_program(dma, runtime->dma_addr,
size, DMA_MODE_WRITE | DMA_AUTOINIT);
return 0;
}
@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT;
return 0;
}
@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int mixreg, rate, size, count;
unsigned char format;
unsigned char stereo = runtime->channels > 1;
int dma;
rate = runtime->rate;
switch (chip->hardware) {
case SB_HW_JAZZ16:
if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
if (chip->mode & SB_MODE_PLAYBACK_16)
return -EBUSY;
else
chip->mode |= SB_MODE_CAPTURE_16;
}
chip->capture_format = SB_DSP_LO_INPUT_AUTO;
break;
case SB_HW_PRO:
if (runtime->channels > 1) {
if (snd_BUG_ON(rate != SB8_RATE(11025) &&
@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
default:
return -EINVAL;
}
if (chip->mode & SB_MODE_CAPTURE_16) {
format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
dma = chip->dma16;
} else {
format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
chip->mode |= SB_MODE_CAPTURE_8;
dma = chip->dma8;
}
size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
if (runtime->channels > 1)
if (chip->hardware == SB_HW_JAZZ16)
snd_sbdsp_command(chip, format);
else if (stereo)
snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
if (runtime->channels > 1) {
if (stereo) {
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
spin_lock(&chip->mixer_lock);
/* save input filter status and turn it off */
@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
snd_sbdsp_command(chip, 256 - runtime->rate_den);
}
if (chip->capture_format != SB_DSP_INPUT) {
if (chip->mode & SB_MODE_PLAYBACK_16)
count /= 2;
count--;
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
snd_sbdsp_command(chip, count & 0xff);
snd_sbdsp_command(chip, count >> 8);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_dma_program(chip->dma8, runtime->dma_addr,
snd_dma_program(dma, runtime->dma_addr,
size, DMA_MODE_READ | DMA_AUTOINIT);
return 0;
}
@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT;
return 0;
}
@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
snd_sb_ack_8bit(chip);
switch (chip->mode) {
case SB_MODE_PLAYBACK_8: /* ok.. playback is active */
case SB_MODE_PLAYBACK_16: /* ok.. playback is active */
if (chip->hardware != SB_HW_JAZZ16)
break;
/* fallthru */
case SB_MODE_PLAYBACK_8:
substream = chip->playback_substream;
runtime = substream->runtime;
if (chip->playback_format == SB_DSP_OUTPUT)
snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
snd_pcm_period_elapsed(substream);
break;
case SB_MODE_CAPTURE_16:
if (chip->hardware != SB_HW_JAZZ16)
break;
/* fallthru */
case SB_MODE_CAPTURE_8:
substream = chip->capture_substream;
runtime = substream->runtime;
@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
size_t ptr;
int dma;
if (chip->mode != SB_MODE_PLAYBACK_8)
if (chip->mode & SB_MODE_PLAYBACK_8)
dma = chip->dma8;
else if (chip->mode & SB_MODE_PLAYBACK_16)
dma = chip->dma16;
else
return 0;
ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size);
ptr = snd_dma_pointer(dma, chip->p_dma_size);
return bytes_to_frames(substream->runtime, ptr);
}
@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
size_t ptr;
int dma;
if (chip->mode != SB_MODE_CAPTURE_8)
if (chip->mode & SB_MODE_CAPTURE_8)
dma = chip->dma8;
else if (chip->mode & SB_MODE_CAPTURE_16)
dma = chip->dma16;
else
return 0;
ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size);
ptr = snd_dma_pointer(dma, chip->c_dma_size);
return bytes_to_frames(substream->runtime, ptr);
}
@ -446,6 +509,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
runtime->hw = snd_sb8_capture;
}
switch (chip->hardware) {
case SB_HW_JAZZ16:
if (chip->dma16 == 5 || chip->dma16 == 7)
runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
runtime->hw.rate_min = 4000;
runtime->hw.rate_max = 50000;
runtime->hw.channels_max = 2;
break;
case SB_HW_PRO:
runtime->hw.rate_max = 44100;
runtime->hw.channels_max = 2;
@ -468,6 +539,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
}
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_clock);
if (chip->dma8 > 3 || chip->dma16 >= 0) {
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
runtime->hw.period_bytes_max = 128 * 1024 * 1024;
}
return 0;
}
@ -480,6 +559,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream)
chip->capture_substream = NULL;
spin_lock_irqsave(&chip->open_lock, flags);
chip->open &= ~SB_OPEN_PCM;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
chip->mode &= ~SB_MODE_PLAYBACK;
else
chip->mode &= ~SB_MODE_CAPTURE;
spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
@ -515,6 +598,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
struct snd_card *card = chip->card;
struct snd_pcm *pcm;
int err;
size_t max_prealloc = 64 * 1024;
if (rpcm)
*rpcm = NULL;
@ -527,9 +611,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
if (chip->dma8 > 3 || chip->dma16 >= 0)
max_prealloc = 128 * 1024;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
64*1024, 64*1024);
64*1024, max_prealloc);
if (rpcm)
*rpcm = pcm;

View File

@ -170,6 +170,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
case SB_HW_CS5530:
str = "16 (CS5530)";
break;
case SB_HW_JAZZ16:
str = "Pro (Jazz16)";
break;
default:
return -ENODEV;
}

View File

@ -528,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
* SB 2.0 specific mixer elements
*/
static struct sbmix_elem snd_sb20_ctl_master_play_vol =
SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
static struct sbmix_elem *snd_sb20_controls[] = {
&snd_sb20_ctl_master_play_vol,
&snd_sb20_ctl_pcm_play_vol,
&snd_sb20_ctl_synth_play_vol,
&snd_sb20_ctl_cd_play_vol
static struct sbmix_elem snd_sb20_controls[] = {
SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
};
static unsigned char snd_sb20_init_values[][2] = {
@ -552,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = {
/*
* SB Pro specific mixer elements
*/
static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
static struct sbmix_elem snd_sbpro_ctl_capture_source =
static struct sbmix_elem snd_sbpro_controls[] = {
SB_DOUBLE("Master Playback Volume",
SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
SB_DOUBLE("PCM Playback Volume",
SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
SB_DOUBLE("Synth Playback Volume",
SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
SB_DOUBLE("Line Playback Volume",
SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
{
.name = "Capture Source",
.type = SB_MIX_CAPTURE_PRO
};
static struct sbmix_elem snd_sbpro_ctl_capture_filter =
SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
static struct sbmix_elem *snd_sbpro_controls[] = {
&snd_sbpro_ctl_master_play_vol,
&snd_sbpro_ctl_pcm_play_vol,
&snd_sbpro_ctl_pcm_play_filter,
&snd_sbpro_ctl_synth_play_vol,
&snd_sbpro_ctl_cd_play_vol,
&snd_sbpro_ctl_line_play_vol,
&snd_sbpro_ctl_mic_play_vol,
&snd_sbpro_ctl_capture_source,
&snd_sbpro_ctl_capture_filter,
&snd_sbpro_ctl_capture_low_filter
},
SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
};
static unsigned char snd_sbpro_init_values[][2] = {
@ -598,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = {
/*
* SB16 specific mixer elements
*/
static struct sbmix_elem snd_sb16_ctl_master_play_vol =
SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
static struct sbmix_elem snd_sb16_ctl_tone_bass =
SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
static struct sbmix_elem snd_sb16_ctl_tone_treble =
SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
static struct sbmix_elem snd_sb16_ctl_line_capture_route =
SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
static struct sbmix_elem snd_sb16_ctl_line_play_switch =
SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
static struct sbmix_elem snd_sb16_ctl_line_play_vol =
SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
static struct sbmix_elem snd_sb16_ctl_capture_vol =
SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
static struct sbmix_elem snd_sb16_ctl_play_vol =
SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
static struct sbmix_elem *snd_sb16_controls[] = {
&snd_sb16_ctl_master_play_vol,
&snd_sb16_ctl_3d_enhance_switch,
&snd_sb16_ctl_tone_bass,
&snd_sb16_ctl_tone_treble,
&snd_sb16_ctl_pcm_play_vol,
&snd_sb16_ctl_synth_capture_route,
&snd_sb16_ctl_synth_play_vol,
&snd_sb16_ctl_cd_capture_route,
&snd_sb16_ctl_cd_play_switch,
&snd_sb16_ctl_cd_play_vol,
&snd_sb16_ctl_line_capture_route,
&snd_sb16_ctl_line_play_switch,
&snd_sb16_ctl_line_play_vol,
&snd_sb16_ctl_mic_capture_route,
&snd_sb16_ctl_mic_play_switch,
&snd_sb16_ctl_mic_play_vol,
&snd_sb16_ctl_pc_speaker_vol,
&snd_sb16_ctl_capture_vol,
&snd_sb16_ctl_play_vol,
&snd_sb16_ctl_auto_mic_gain
static struct sbmix_elem snd_sb16_controls[] = {
SB_DOUBLE("Master Playback Volume",
SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
SB_DOUBLE("PCM Playback Volume",
SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
SB16_INPUT_SW("Synth Capture Route",
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
SB_DOUBLE("Synth Playback Volume",
SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
SB16_INPUT_SW("CD Capture Route",
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
SB_DOUBLE("CD Playback Switch",
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
SB_DOUBLE("CD Playback Volume",
SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
SB16_INPUT_SW("Mic Capture Route",
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
SB_DOUBLE("Capture Volume",
SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
SB_DOUBLE("Playback Volume",
SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
SB16_INPUT_SW("Line Capture Route",
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
SB_DOUBLE("Line Playback Switch",
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
SB_DOUBLE("Line Playback Volume",
SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
SB_DOUBLE("Tone Control - Bass",
SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
SB_DOUBLE("Tone Control - Treble",
SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
};
static unsigned char snd_sb16_init_values[][2] = {
@ -678,46 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = {
/*
* DT019x specific mixer elements
*/
static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7);
static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
static struct sbmix_elem snd_dt019x_ctl_capture_source =
static struct sbmix_elem snd_dt019x_controls[] = {
/* ALS4000 below has some parts which we might be lacking,
* e.g. snd_als4000_ctl_mono_playback_switch - check it! */
SB_DOUBLE("Master Playback Volume",
SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
SB_DOUBLE("PCM Playback Switch",
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
SB_DOUBLE("PCM Playback Volume",
SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
SB_DOUBLE("Synth Playback Switch",
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
SB_DOUBLE("Synth Playback Volume",
SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
SB_DOUBLE("CD Playback Switch",
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
SB_DOUBLE("CD Playback Volume",
SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7),
SB_DOUBLE("Line Playback Switch",
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
SB_DOUBLE("Line Playback Volume",
SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
{
.name = "Capture Source",
.type = SB_MIX_CAPTURE_DT019X
};
static struct sbmix_elem *snd_dt019x_controls[] = {
/* ALS4000 below has some parts which we might be lacking,
* e.g. snd_als4000_ctl_mono_playback_switch - check it! */
&snd_dt019x_ctl_master_play_vol,
&snd_dt019x_ctl_pcm_play_vol,
&snd_dt019x_ctl_synth_play_vol,
&snd_dt019x_ctl_cd_play_vol,
&snd_dt019x_ctl_mic_play_vol,
&snd_dt019x_ctl_pc_speaker_vol,
&snd_dt019x_ctl_line_play_vol,
&snd_sb16_ctl_mic_play_switch,
&snd_sb16_ctl_cd_play_switch,
&snd_sb16_ctl_line_play_switch,
&snd_dt019x_ctl_pcm_play_switch,
&snd_dt019x_ctl_synth_play_switch,
&snd_dt019x_ctl_capture_source
}
};
static unsigned char snd_dt019x_init_values[][2] = {
@ -735,82 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = {
/*
* ALS4000 specific mixer elements
*/
static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = {
static struct sbmix_elem snd_als4000_controls[] = {
SB_DOUBLE("PCM Playback Switch",
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
SB_DOUBLE("Synth Playback Switch",
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
{
.name = "Master Mono Capture Route",
.type = SB_MIX_MONO_CAPTURE_ALS4K
};
static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback =
SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback =
},
SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
SB_SINGLE("Digital Loopback Switch",
SB_ALS4000_CR3_CONFIGURATION, 7, 0x01);
/* FIXME: functionality of 3D controls might be swapped, I didn't find
* a description of how to identify what is supposed to be what */
static struct sbmix_elem snd_als4000_3d_control_switch =
SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
static struct sbmix_elem snd_als4000_3d_control_ratio =
SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07);
static struct sbmix_elem snd_als4000_3d_control_freq =
SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
/* FIXME: functionality of 3D controls might be swapped, I didn't find
* a description of how to identify what is supposed to be what */
SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
/* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03);
static struct sbmix_elem snd_als4000_3d_control_delay =
SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
/* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
* but what ALSA 3D attribute is that actually? "Center", "Depth",
* "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch =
SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
SB_ALS4000_FMDAC, 5, 0x01);
SB_ALS4000_FMDAC, 5, 0x01),
#ifdef NOT_AVAILABLE
static struct sbmix_elem snd_als4000_ctl_fmdac =
SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
static struct sbmix_elem snd_als4000_ctl_qsound =
SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
#endif
static struct sbmix_elem *snd_als4000_controls[] = {
/* ALS4000a.PDF regs page */
&snd_sb16_ctl_master_play_vol, /* MX30/31 12 */
&snd_dt019x_ctl_pcm_play_switch, /* MX4C 16 */
&snd_sb16_ctl_pcm_play_vol, /* MX32/33 12 */
&snd_sb16_ctl_synth_capture_route, /* MX3D/3E 14 */
&snd_dt019x_ctl_synth_play_switch, /* MX4C 16 */
&snd_sb16_ctl_synth_play_vol, /* MX34/35 12/13 */
&snd_sb16_ctl_cd_capture_route, /* MX3D/3E 14 */
&snd_sb16_ctl_cd_play_switch, /* MX3C 14 */
&snd_sb16_ctl_cd_play_vol, /* MX36/37 13 */
&snd_sb16_ctl_line_capture_route, /* MX3D/3E 14 */
&snd_sb16_ctl_line_play_switch, /* MX3C 14 */
&snd_sb16_ctl_line_play_vol, /* MX38/39 13 */
&snd_sb16_ctl_mic_capture_route, /* MX3D/3E 14 */
&snd_als4000_ctl_mic_20db_boost, /* MX4D 16 */
&snd_sb16_ctl_mic_play_switch, /* MX3C 14 */
&snd_sb16_ctl_mic_play_vol, /* MX3A 13 */
&snd_sb16_ctl_pc_speaker_vol, /* MX3B 14 */
&snd_sb16_ctl_capture_vol, /* MX3F/40 15 */
&snd_sb16_ctl_play_vol, /* MX41/42 15 */
&snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */
&snd_als4k_ctl_master_mono_capture_route, /* MX4B 16 */
&snd_als4000_ctl_mono_playback_switch, /* MX4C 16 */
&snd_als4000_ctl_mixer_analog_loopback, /* MX4D 16 */
&snd_als4000_ctl_mixer_digital_loopback, /* CR3 21 */
&snd_als4000_3d_control_switch, /* MX50 17 */
&snd_als4000_3d_control_ratio, /* MX50 17 */
&snd_als4000_3d_control_freq, /* MX50 17 */
&snd_als4000_3d_control_delay, /* MX51 18 */
&snd_als4000_3d_control_poweroff_switch, /* MX51 18 */
&snd_als4000_ctl_3db_freq_control_switch, /* MX4F 17 */
#ifdef NOT_AVAILABLE
&snd_als4000_ctl_fmdac,
&snd_als4000_ctl_qsound,
SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
#endif
};
@ -829,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = {
{ SB_ALS4000_MIC_IN_GAIN, 0 },
};
/*
*/
static int snd_sbmixer_init(struct snd_sb *chip,
struct sbmix_elem **controls,
struct sbmix_elem *controls,
int controls_count,
unsigned char map[][2],
int map_count,
@ -856,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip,
}
for (idx = 0; idx < controls_count; idx++) {
if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
if (err < 0)
return err;
}
snd_component_add(card, name);
@ -888,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
return err;
break;
case SB_HW_PRO:
case SB_HW_JAZZ16:
if ((err = snd_sbmixer_init(chip,
snd_sbpro_controls,
ARRAY_SIZE(snd_sbpro_controls),
@ -908,6 +800,15 @@ int snd_sbmixer_new(struct snd_sb *chip)
return err;
break;
case SB_HW_ALS4000:
/* use only the first 16 controls from SB16 */
err = snd_sbmixer_init(chip,
snd_sb16_controls,
16,
snd_sb16_init_values,
ARRAY_SIZE(snd_sb16_init_values),
"ALS4000");
if (err < 0)
return err;
if ((err = snd_sbmixer_init(chip,
snd_als4000_controls,
ARRAY_SIZE(snd_als4000_controls),
@ -1029,6 +930,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip)
save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
break;
case SB_HW_PRO:
case SB_HW_JAZZ16:
save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
break;
case SB_HW_16:
@ -1055,6 +957,7 @@ void snd_sbmixer_resume(struct snd_sb *chip)
restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
break;
case SB_HW_PRO:
case SB_HW_JAZZ16:
restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
break;
case SB_HW_16:

View File

@ -2014,6 +2014,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
case WSS_HW_INTERWAVE:
ptexts = gusmax_texts;
break;
case WSS_HW_OPTI93X:
case WSS_HW_OPL3SA2:
ptexts = opl3sa_texts;
break;
@ -2246,54 +2247,12 @@ WSS_SINGLE("Beep Bypass Playback Switch", 0,
CS4231_MONO_CTRL, 5, 1, 0),
};
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_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,
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
WSS_DOUBLE("FM Playback Switch", 0,
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE("FM Playback Volume", 0,
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
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, 15, 1),
WSS_DOUBLE("Mic Playback Switch", 0,
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE("Mic Playback Volume", 0,
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
WSS_DOUBLE("Mic Boost", 0,
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
WSS_DOUBLE("CD Playback Switch", 0,
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE("CD Playback Volume", 0,
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
WSS_DOUBLE("Aux Playback Switch", 0,
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE("Aux Playback Volume", 0,
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
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,
}
};
int snd_wss_mixer(struct snd_wss *chip)
{
struct snd_card *card;
unsigned int idx;
int err;
int count = ARRAY_SIZE(snd_wss_controls);
if (snd_BUG_ON(!chip || !chip->pcm))
return -EINVAL;
@ -2302,28 +2261,19 @@ int snd_wss_mixer(struct snd_wss *chip)
strcpy(card->mixername, chip->pcm->name);
if (chip->hardware == WSS_HW_OPTI93X)
for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
err = snd_ctl_add(card,
snd_ctl_new1(&snd_opti93x_controls[idx],
chip));
if (err < 0)
return err;
}
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;
/* There is no loopback on OPTI93X */
else if (chip->hardware == WSS_HW_OPTI93X)
count = 9;
/* 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;
}
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;
}

View File

@ -26,7 +26,6 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/gfp.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
@ -603,25 +602,14 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream)
static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int size = params_buffer_bytes(hw_params);
/* alloc virtual 'dma' area */
if (runtime->dma_area)
vfree(runtime->dma_area);
runtime->dma_area = vmalloc_user(size);
if (runtime->dma_area == NULL)
return -ENOMEM;
runtime->dma_bytes = size;
return 0;
return snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
}
/* hw_free callback */
static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream)
{
vfree(substream->runtime->dma_area);
substream->runtime->dma_area = NULL;
return 0;
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
/* prepare callback */
@ -692,13 +680,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream)
chip->channel[chan->idx].pos);
}
/* get the physical page pointer on the given offset */
static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
return vmalloc_to_page(substream->runtime->dma_area + offset);
}
/* operators */
static struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
.open = snd_sgio2audio_playback1_open,
@ -709,7 +690,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
.prepare = snd_sgio2audio_pcm_prepare,
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_sgio2audio_page,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
};
static struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
@ -721,7 +703,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
.prepare = snd_sgio2audio_pcm_prepare,
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_sgio2audio_page,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
};
static struct snd_pcm_ops snd_sgio2audio_capture_ops = {
@ -733,7 +716,8 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = {
.prepare = snd_sgio2audio_pcm_prepare,
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_sgio2audio_page,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
};
/*

View File

@ -198,7 +198,7 @@ MODULE_LICENSE("GPL");
* 5530 only. The 5510/5520 decode is different.
*/
static struct pci_device_id id_tbl[] = {
static DEFINE_PCI_DEVICE_TABLE(id_tbl) = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 },
{ }
};

View File

@ -328,11 +328,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg)
return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
}
static int sound_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int len = 0, dtype;
int dev = iminor(inode);
int dev = iminor(file->f_dentry->d_inode);
long ret = -EINVAL;
void __user *p = (void __user *)arg;
if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
@ -353,6 +353,7 @@ static int sound_ioctl(struct inode *inode, struct file *file,
if (cmd == OSS_GETVERSION)
return __put_user(SOUND_VERSION, (int __user *)p);
lock_kernel();
if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */
(dev & 0x0f) != SND_DEV_CTL) {
dtype = dev & 0x0f;
@ -360,24 +361,31 @@ static int sound_ioctl(struct inode *inode, struct file *file,
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
cmd, p);
break;
default:
return sound_mixer_ioctl(dev >> 4, cmd, p);
ret = sound_mixer_ioctl(dev >> 4, cmd, p);
break;
}
unlock_kernel();
return ret;
}
switch (dev & 0x0f) {
case SND_DEV_CTL:
if (cmd == SOUND_MIXER_GETLEVELS)
return get_mixer_levels(p);
if (cmd == SOUND_MIXER_SETLEVELS)
return set_mixer_levels(p);
return sound_mixer_ioctl(dev >> 4, cmd, p);
ret = get_mixer_levels(p);
else if (cmd == SOUND_MIXER_SETLEVELS)
ret = set_mixer_levels(p);
else
ret = sound_mixer_ioctl(dev >> 4, cmd, p);
break;
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_ioctl(dev, file, cmd, p);
ret = sequencer_ioctl(dev, file, cmd, p);
break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
@ -390,7 +398,8 @@ static int sound_ioctl(struct inode *inode, struct file *file,
break;
}
return -EINVAL;
unlock_kernel();
return ret;
}
static unsigned int sound_poll(struct file *file, poll_table * wait)
@ -490,7 +499,7 @@ const struct file_operations oss_sound_fops = {
.read = sound_read,
.write = sound_write,
.poll = sound_poll,
.ioctl = sound_ioctl,
.unlocked_ioctl = sound_ioctl,
.mmap = sound_mmap,
.open = sound_open,
.release = sound_release,

View File

@ -789,6 +789,7 @@ config SND_VIRTUOSO
Say Y here to include support for sound cards based on the
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
Essence ST (Deluxe), and Essence STX.
Support for the DS is experimental.
Support for the HDAV1.3 (Deluxe) is very experimental.
To compile this driver as a module, choose M here: the module

View File

@ -544,25 +544,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97)
return 0;
}
static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, 0x72, 0x0808);
return 0;
}
static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
.build_specific = patch_wolfson_wm9705_specific,
};
static int patch_wolfson05(struct snd_ac97 * ac97)
{
/* WM9705, WM9710 */
ac97->build_ops = &patch_wolfson_wm9705_ops;
ac97->build_ops = &patch_wolfson_wm9703_ops;
#ifdef CONFIG_TOUCHSCREEN_WM9705
/* WM9705 touchscreen uses AUX and VIDEO for touch */
ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;

View File

@ -1048,7 +1048,7 @@ snd_ad1889_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
static struct pci_device_id snd_ad1889_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) },
{ 0, },
};

View File

@ -275,7 +275,7 @@ struct snd_ali {
#endif
};
static struct pci_device_id snd_ali_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = {
{PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0},
{0, }
};

View File

@ -145,7 +145,7 @@ struct snd_als300_substream_data {
int block_counter_register;
};
static struct pci_device_id snd_als300_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = {
{ 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 },
{ 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS },
{ 0, }

View File

@ -117,7 +117,7 @@ struct snd_card_als4000 {
#endif
};
static struct pci_device_id snd_als4000_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = {
{ 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */
{ 0, }
};

View File

@ -286,7 +286,7 @@ struct atiixp {
/*
*/
static struct pci_device_id snd_atiixp_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = {
{ PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */
{ PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */
{ PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */

View File

@ -261,7 +261,7 @@ struct atiixp_modem {
/*
*/
static struct pci_device_id snd_atiixp_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = {
{ PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */
{ PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */
{ 0, }

View File

@ -1,6 +1,6 @@
#include "au8810.h"
#include "au88x0.h"
static struct pci_device_id snd_vortex_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = {
{PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,},
{0,}
};

View File

@ -1,6 +1,6 @@
#include "au8820.h"
#include "au88x0.h"
static struct pci_device_id snd_vortex_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = {
{PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,},
{0,}
};

View File

@ -1,6 +1,6 @@
#include "au8830.h"
#include "au88x0.h"
static struct pci_device_id snd_vortex_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = {
{PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,},
{0,}
};

View File

@ -164,7 +164,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
static struct pci_device_id snd_aw2_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
{PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
0, 0, 0},
{0}

View File

@ -350,7 +350,7 @@ struct snd_azf3328 {
#endif
};
static const struct pci_device_id snd_azf3328_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = {
{ 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */
{ 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */
{ 0, }

View File

@ -795,7 +795,7 @@ fail:
.driver_data = SND_BT87X_BOARD_ ## id }
/* driver_data is the card id for that device */
static struct pci_device_id snd_bt87x_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = {
/* Hauppauge WinTV series */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC),
/* Hauppauge WinTV series */
@ -964,7 +964,7 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci)
/* default entries for all Bt87x cards - it's not exported */
/* driver_data is set to 0 to call detection */
static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = {
static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN),
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN),
{ }

View File

@ -1875,7 +1875,7 @@ static int snd_ca0106_resume(struct pci_dev *pci)
#endif
// PCI IDs
static struct pci_device_id snd_ca0106_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = {
{ PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */
{ 0, }
};

View File

@ -2796,7 +2796,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
#endif
static struct pci_device_id snd_cmipci_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = {
{PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0},
{PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0},
{PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
@ -3018,7 +3018,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
int integrated_midi = 0;
char modelstr[16];
int pcm_index, pcm_spdif_index;
static struct pci_device_id intel_82437vx[] = {
static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) },
{ },
};

View File

@ -494,7 +494,7 @@ struct cs4281 {
static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
static struct pci_device_id snd_cs4281_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = {
{ PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */
{ 0, }
};

View File

@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control.");
module_param_array(mmap_valid, bool, NULL, 0444);
MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
static struct pci_device_id snd_cs46xx_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = {
{ PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */
{ PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */
{ PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */

View File

@ -2238,11 +2238,11 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
/* set the desired CODEC mode */
if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) {
snd_printdd("cs46xx: CODOEC1 mode %04x\n",0x0);
snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x0);
snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0);
snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0);
} else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) {
snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3);
snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3);
snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3);
snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3);
} else {
snd_BUG(); /* should never happen ... */
}
@ -2266,7 +2266,7 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
return;
/* test if we can write to the record gain volume register */
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);
snd_ac97_write(ac97, AC97_REC_GAIN, 0x8a05);
if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
return;
@ -3597,7 +3597,7 @@ static struct cs_card_type __devinitdata cards[] = {
#ifdef CONFIG_PM
static unsigned int saved_regs[] = {
BA0_ACOSV,
BA0_ASER_FADDR,
/*BA0_ASER_FADDR,*/
BA0_ASER_MASTER,
BA1_PVOL,
BA1_CVOL,
@ -3644,6 +3644,7 @@ int snd_cs46xx_resume(struct pci_dev *pci)
#ifdef CONFIG_SND_CS46XX_NEW_DSP
int i;
#endif
unsigned int tmp;
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
@ -3685,6 +3686,15 @@ int snd_cs46xx_resume(struct pci_dev *pci)
snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
/*
* Stop capture DMA.
*/
tmp = snd_cs46xx_peek(chip, BA1_CCTL);
chip->capt.ctl = tmp & 0x0000ffff;
snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000);
mdelay(5);
/* reset playback/capture */
snd_cs46xx_set_play_sample_rate(chip, 8000);
snd_cs46xx_set_capture_sample_rate(chip, 8000);

View File

@ -298,6 +298,9 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
#ifdef CONFIG_PM
kfree(ins->scbs[i].data);
#endif
}
kfree(ins->code.data);
@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam
index = find_free_scb_index (ins);
memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
strcpy(ins->scbs[index].scb_name, name);
ins->scbs[index].address = dest;
ins->scbs[index].index = index;
ins->scbs[index].proc_info = NULL;
ins->scbs[index].ref_count = 1;
ins->scbs[index].deleted = 0;
spin_lock_init(&ins->scbs[index].lock);
desc = (ins->scbs + index);
ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
return desc;
}
#define SCB_BYTES (0x10 * 4)
struct dsp_scb_descriptor *
cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest)
{
struct dsp_scb_descriptor * desc;
#ifdef CONFIG_PM
/* copy the data for resume */
scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
if (!scb_data)
return NULL;
#endif
desc = _map_scb (chip,name,dest);
if (desc) {
desc->data = scb_data;
_dsp_create_scb(chip,scb_data,dest);
} else {
snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
#ifdef CONFIG_PM
kfree(scb_data);
#endif
}
return desc;
@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip)
continue;
_dsp_create_scb(chip, s->data, s->address);
}
for (i = 0; i < ins->nscb; i++) {
struct dsp_scb_descriptor *s = &ins->scbs[i];
if (s->deleted)
continue;
if (s->updated)
cs46xx_dsp_spos_update_scb(chip, s);
if (s->volume_set)
cs46xx_dsp_scb_set_volume(chip, s,
s->volume[0], s->volume[1]);
}
if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
cs46xx_dsp_enable_spdif_hw(chip);
snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2,
(OUTPUT_SNOOP_BUFFER + 0x10) << 0x10);
if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN)
cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV,
ins->spdif_csuv_stream);
}
if (chip->dsp_spos_instance->spdif_status_in) {
cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005);
cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff);
}
return 0;
}
#endif

View File

@ -212,6 +212,7 @@ static inline void cs46xx_dsp_spos_update_scb (struct snd_cs46xx * chip,
(scb->address + SCBsubListPtr) << 2,
(scb->sub_list_ptr->address << 0x10) |
(scb->next_scb_ptr->address));
scb->updated = 1;
}
static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip,
@ -222,6 +223,9 @@ static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip,
snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
scb->volume_set = 1;
scb->volume[0] = left;
scb->volume[1] = right;
}
#endif /* __DSP_SPOS_H__ */
#endif /* CONFIG_SND_CS46XX_NEW_DSP */

View File

@ -115,7 +115,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
unsigned long flags;
if ( scb->parent_scb_ptr ) {
/* unlink parent SCB */
@ -153,8 +152,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor
scb->next_scb_ptr = ins->the_null_scb;
}
spin_lock_irqsave(&chip->reg_lock, flags);
/* update parent first entry in DSP RAM */
cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
@ -162,7 +159,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor
cs46xx_dsp_spos_update_scb(chip,scb);
scb->parent_scb_ptr = NULL;
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
}
@ -197,9 +193,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
goto _end;
#endif
spin_lock_irqsave(&scb->lock, flags);
spin_lock_irqsave(&chip->reg_lock, flags);
_dsp_unlink_scb (chip,scb);
spin_unlock_irqrestore(&scb->lock, flags);
spin_unlock_irqrestore(&chip->reg_lock, flags);
cs46xx_dsp_proc_free_scb_desc(scb);
if (snd_BUG_ON(!scb->scb_symbol))
@ -207,6 +203,10 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
remove_symbol (chip,scb->scb_symbol);
ins->scbs[scb->index].deleted = 1;
#ifdef CONFIG_PM
kfree(ins->scbs[scb->index].data);
ins->scbs[scb->index].data = NULL;
#endif
if (scb->index < ins->scb_highest_frag_index)
ins->scb_highest_frag_index = scb->index;
@ -1508,20 +1508,17 @@ int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
chip->dsp_spos_instance->npcm_channels <= 0))
return -EIO;
spin_lock(&pcm_channel->src_scb->lock);
spin_lock_irqsave(&chip->reg_lock, flags);
if (pcm_channel->unlinked) {
spin_unlock(&pcm_channel->src_scb->lock);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return -EIO;
}
spin_lock_irqsave(&chip->reg_lock, flags);
pcm_channel->unlinked = 1;
spin_unlock_irqrestore(&chip->reg_lock, flags);
_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
spin_unlock_irqrestore(&chip->reg_lock, flags);
spin_unlock(&pcm_channel->src_scb->lock);
return 0;
}
@ -1533,10 +1530,10 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
unsigned long flags;
spin_lock(&pcm_channel->src_scb->lock);
spin_lock_irqsave(&chip->reg_lock, flags);
if (pcm_channel->unlinked == 0) {
spin_unlock(&pcm_channel->src_scb->lock);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return -EIO;
}
@ -1552,8 +1549,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
spin_lock_irqsave(&chip->reg_lock, flags);
/* update SCB entry in DSP RAM */
cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
@ -1562,8 +1557,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
pcm_channel->unlinked = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
spin_unlock(&pcm_channel->src_scb->lock);
return 0;
}
@ -1596,13 +1589,17 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s
int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
{
unsigned long flags;
if (snd_BUG_ON(!src->parent_scb_ptr))
return -EINVAL;
/* mute SCB */
cs46xx_dsp_scb_set_volume (chip,src,0,0);
spin_lock_irqsave(&chip->reg_lock, flags);
_dsp_unlink_scb (chip,src);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}

View File

@ -58,7 +58,7 @@ struct snd_cs5530 {
unsigned long pci_base;
};
static struct pci_device_id snd_cs5530_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = {
{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
PCI_ANY_ID, 0, 0},
{0,}

View File

@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME);
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME);
static struct pci_device_id snd_cs5535audio_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) },
{}

View File

@ -1214,10 +1214,11 @@ static int atc_dev_free(struct snd_device *dev)
return ct_atc_destroy(atc);
}
static int __devinit atc_identify_card(struct ct_atc *atc)
static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid)
{
const struct snd_pci_quirk *p;
const struct snd_pci_quirk *list;
u16 vendor_id, device_id;
switch (atc->chip_type) {
case ATC20K1:
@ -1231,13 +1232,19 @@ static int __devinit atc_identify_card(struct ct_atc *atc)
default:
return -ENOENT;
}
p = snd_pci_quirk_lookup(atc->pci, list);
if (ssid) {
vendor_id = ssid >> 16;
device_id = ssid & 0xffff;
} else {
vendor_id = atc->pci->subsystem_vendor;
device_id = atc->pci->subsystem_device;
}
p = snd_pci_quirk_lookup_id(vendor_id, device_id, list);
if (p) {
if (p->value < 0) {
printk(KERN_ERR "ctxfi: "
"Device %04x:%04x is black-listed\n",
atc->pci->subsystem_vendor,
atc->pci->subsystem_device);
vendor_id, device_id);
return -ENOENT;
}
atc->model = p->value;
@ -1250,8 +1257,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc)
atc->model_name = ct_subsys_name[atc->model];
snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
atc->chip_name, atc->model_name,
atc->pci->subsystem_vendor,
atc->pci->subsystem_device);
vendor_id, device_id);
return 0;
}
@ -1625,7 +1631,8 @@ static struct ct_atc atc_preset __devinitdata = {
int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
unsigned int rsr, unsigned int msr,
int chip_type, struct ct_atc **ratc)
int chip_type, unsigned int ssid,
struct ct_atc **ratc)
{
struct ct_atc *atc;
static struct snd_device_ops ops = {
@ -1651,7 +1658,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
mutex_init(&atc->atc_mutex);
/* Find card model */
err = atc_identify_card(atc);
err = atc_identify_card(atc, ssid);
if (err < 0) {
printk(KERN_ERR "ctatc: Card not recognised\n");
goto error1;

View File

@ -148,7 +148,7 @@ struct ct_atc {
int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
unsigned int rsr, unsigned int msr, int chip_type,
struct ct_atc **ratc);
unsigned int subsysid, struct ct_atc **ratc);
int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
#endif /* CTATC_H */

View File

@ -32,6 +32,7 @@ module_param(multiple, uint, S_IRUGO);
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static unsigned int subsystem[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver");
@ -39,8 +40,10 @@ module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver");
module_param_array(subsystem, int, NULL, 0444);
MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver");
static struct pci_device_id ct_pci_dev_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = {
/* only X-Fi is supported, so... */
{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1),
.driver_data = ATC20K1,
@ -85,7 +88,7 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
multiple = 2;
}
err = ct_atc_create(card, pci, reference_rate, multiple,
pci_id->driver_data, &atc);
pci_id->driver_data, subsystem[dev], &atc);
if (err < 0)
goto error;

View File

@ -63,7 +63,7 @@ static const struct firmware card_fw[] = {
{0, "darla20_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */
{0,}
};

View File

@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP];
chip->dsp_code_to_load = FW_DARLA20_DSP;
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
chip->clock_state = GD_CLOCK_UNDEF;
/* Since this card has no ASIC, mark it as loaded so everything
@ -57,15 +57,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
return init_line_levels(chip);
}
/* The Darla20 has no external clock sources */
static u32 detect_input_clocks(const struct echoaudio *chip)
{

View File

@ -67,7 +67,7 @@ static const struct firmware card_fw[] = {
{0, "darla24_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */
{0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */
{0,}

View File

@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP];
chip->dsp_code_to_load = FW_DARLA24_DSP;
/* Since this card has no ASIC, mark it as loaded so everything
works OK */
chip->asic_loaded = TRUE;
@ -56,15 +56,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
return init_line_levels(chip);
}
static u32 detect_input_clocks(const struct echoaudio *chip)
{
u32 clocks_from_dsp, clock_bits;

View File

@ -81,7 +81,7 @@ static const struct firmware card_fw[] = {
{0, "3g_asic.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */
{0,}
};

View File

@ -61,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->has_midi = TRUE;
chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP];
chip->dsp_code_to_load = FW_ECHO3G_DSP;
/* Load the DSP code and the ASIC on the PCI card and get
what type of external box is attached */
@ -97,20 +97,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
chip->professional_spdif = FALSE;
chip->non_audio_spdif = FALSE;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
if (err < 0)
return err;
err = set_phantom_power(chip, 0);
if (err < 0)
return err;
err = set_professional_spdif(chip, TRUE);
DE_INIT(("init_hw done\n"));
return err;
@ -118,6 +104,18 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
static int set_mixer_defaults(struct echoaudio *chip)
{
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
chip->professional_spdif = FALSE;
chip->non_audio_spdif = FALSE;
chip->bad_board = FALSE;
chip->phantom_power = FALSE;
return init_line_levels(chip);
}
static int set_phantom_power(struct echoaudio *chip, char on)
{
u32 control_reg = le32_to_cpu(chip->comm_page->control_register);

View File

@ -36,22 +36,61 @@ MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
static int get_firmware(const struct firmware **fw_entry,
const struct firmware *frm, struct echoaudio *chip)
struct echoaudio *chip, const short fw_index)
{
int err;
char name[30];
DE_ACT(("firmware requested: %s\n", frm->data));
snprintf(name, sizeof(name), "ea/%s", frm->data);
if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0)
#ifdef CONFIG_PM
if (chip->fw_cache[fw_index]) {
DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
*fw_entry = chip->fw_cache[fw_index];
return 0;
}
#endif
DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data));
snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
err = request_firmware(fw_entry, name, pci_device(chip));
if (err < 0)
snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
#ifdef CONFIG_PM
else
chip->fw_cache[fw_index] = *fw_entry;
#endif
return err;
}
static void free_firmware(const struct firmware *fw_entry)
{
#ifdef CONFIG_PM
DE_ACT(("firmware not released (kept in cache)\n"));
#else
release_firmware(fw_entry);
DE_ACT(("firmware released\n"));
#endif
}
static void free_firmware_cache(struct echoaudio *chip)
{
#ifdef CONFIG_PM
int i;
for (i = 0; i < 8 ; i++)
if (chip->fw_cache[i]) {
release_firmware(chip->fw_cache[i]);
DE_ACT(("release_firmware(%d)\n", i));
}
DE_ACT(("firmware_cache released\n"));
#endif
}
@ -714,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
DE_ACT(("pcm_trigger resume\n"));
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
DE_ACT(("pcm_trigger start\n"));
@ -737,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
err = start_transport(chip, channelmask,
chip->pipe_cyclic_mask);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
DE_ACT(("pcm_trigger suspend\n"));
case SNDRV_PCM_TRIGGER_STOP:
DE_ACT(("pcm_trigger stop\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
@ -1821,7 +1864,9 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
/* The hardware doesn't tell us which substream caused the irq,
thus we have to check all running substreams. */
for (ss = 0; ss < DSP_MAXPIPES; ss++) {
if ((substream = chip->substream[ss])) {
substream = chip->substream[ss];
if (substream && ((struct audiopipe *)substream->runtime->
private_data)->state == PIPE_STATE_STARTED) {
period = pcm_pointer(substream) /
substream->runtime->period_size;
if (period != chip->last_period[ss]) {
@ -1874,6 +1919,7 @@ static int snd_echo_free(struct echoaudio *chip)
pci_disable_device(chip->pci);
/* release chip data */
free_firmware_cache(chip);
kfree(chip);
DE_INIT(("Chip freed.\n"));
return 0;
@ -1911,18 +1957,27 @@ static __devinit int snd_echo_create(struct snd_card *card,
return err;
pci_set_master(pci);
/* allocate a chip-specific data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
pci_disable_device(pci);
return -ENOMEM;
/* Allocate chip if needed */
if (!*rchip) {
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
pci_disable_device(pci);
return -ENOMEM;
}
DE_INIT(("chip=%p\n", chip));
spin_lock_init(&chip->lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
atomic_set(&chip->opencount, 0);
mutex_init(&chip->mode_mutex);
chip->can_set_rate = 1;
} else {
/* If this was called from the resume function, chip is
* already allocated and it contains current card settings.
*/
chip = *rchip;
}
DE_INIT(("chip=%p\n", chip));
spin_lock_init(&chip->lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
/* PCI resource allocation */
chip->dsp_registers_phys = pci_resource_start(pci, 0);
@ -1962,7 +2017,9 @@ static __devinit int snd_echo_create(struct snd_card *card,
chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;
err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err) {
if (err >= 0)
err = set_mixer_defaults(chip);
if (err < 0) {
DE_INIT(("init_hw err=%d\n", err));
snd_echo_free(chip);
return err;
@ -1973,9 +2030,6 @@ static __devinit int snd_echo_create(struct snd_card *card,
snd_echo_free(chip);
return err;
}
atomic_set(&chip->opencount, 0);
mutex_init(&chip->mode_mutex);
chip->can_set_rate = 1;
*rchip = chip;
/* Init done ! */
return 0;
@ -2008,6 +2062,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,
snd_card_set_dev(card, &pci->dev);
chip = NULL; /* Tells snd_echo_create to allocate chip */
if ((err = snd_echo_create(card, pci, &chip)) < 0) {
snd_card_free(card);
return err;
@ -2147,6 +2202,112 @@ ctl_error:
#if defined(CONFIG_PM)
static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state)
{
struct echoaudio *chip = pci_get_drvdata(pci);
DE_INIT(("suspend start\n"));
snd_pcm_suspend_all(chip->analog_pcm);
snd_pcm_suspend_all(chip->digital_pcm);
#ifdef ECHOCARD_HAS_MIDI
/* This call can sleep */
if (chip->midi_out)
snd_echo_midi_output_trigger(chip->midi_out, 0);
#endif
spin_lock_irq(&chip->lock);
if (wait_handshake(chip)) {
spin_unlock_irq(&chip->lock);
return -EIO;
}
clear_handshake(chip);
if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) {
spin_unlock_irq(&chip->lock);
return -EIO;
}
spin_unlock_irq(&chip->lock);
chip->dsp_code = NULL;
free_irq(chip->irq, chip);
chip->irq = -1;
pci_save_state(pci);
pci_disable_device(pci);
DE_INIT(("suspend done\n"));
return 0;
}
static int snd_echo_resume(struct pci_dev *pci)
{
struct echoaudio *chip = pci_get_drvdata(pci);
struct comm_page *commpage, *commpage_bak;
u32 pipe_alloc_mask;
int err;
DE_INIT(("resume start\n"));
pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
commpage = chip->comm_page;
memcpy(commpage_bak, commpage, sizeof(struct comm_page));
err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err < 0) {
kfree(commpage_bak);
DE_INIT(("resume init_hw err=%d\n", err));
snd_echo_free(chip);
return err;
}
DE_INIT(("resume init OK\n"));
/* Temporarily set chip->pipe_alloc_mask=0 otherwise
* restore_dsp_settings() fails.
*/
pipe_alloc_mask = chip->pipe_alloc_mask;
chip->pipe_alloc_mask = 0;
err = restore_dsp_rettings(chip);
chip->pipe_alloc_mask = pipe_alloc_mask;
if (err < 0) {
kfree(commpage_bak);
return err;
}
DE_INIT(("resume restore OK\n"));
memcpy(&commpage->audio_format, &commpage_bak->audio_format,
sizeof(commpage->audio_format));
memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr,
sizeof(commpage->sglist_addr));
memcpy(&commpage->midi_output, &commpage_bak->midi_output,
sizeof(commpage->midi_output));
kfree(commpage_bak);
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
ECHOCARD_NAME, chip)) {
snd_echo_free(chip);
snd_printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
DE_INIT(("resume irq=%d\n", chip->irq));
#ifdef ECHOCARD_HAS_MIDI
if (chip->midi_input_enabled)
enable_midi_input(chip, TRUE);
if (chip->midi_out)
snd_echo_midi_output_trigger(chip->midi_out, 1);
#endif
DE_INIT(("resume done\n"));
return 0;
}
#endif /* CONFIG_PM */
static void __devexit snd_echo_remove(struct pci_dev *pci)
{
struct echoaudio *chip;
@ -2169,6 +2330,10 @@ static struct pci_driver driver = {
.id_table = snd_echo_ids,
.probe = snd_echo_probe,
.remove = __devexit_p(snd_echo_remove),
#ifdef CONFIG_PM
.suspend = snd_echo_suspend,
.resume = snd_echo_resume,
#endif /* CONFIG_PM */
};

View File

@ -442,13 +442,16 @@ struct echoaudio {
u16 device_id, subdevice_id;
u16 *dsp_code; /* Current DSP code loaded,
* NULL if nothing loaded */
const struct firmware *dsp_code_to_load;/* DSP code to load */
const struct firmware *asic_code; /* Current ASIC code */
short dsp_code_to_load; /* DSP code to load */
short asic_code; /* Current ASIC code */
u32 comm_page_phys; /* Physical address of the
* memory seen by DSP */
volatile u32 __iomem *dsp_registers; /* DSP's register base */
u32 active_mask; /* Chs. active mask or
* punks out */
#ifdef CONFIG_PM
const struct firmware *fw_cache[8]; /* Cached firmwares */
#endif
#ifdef ECHOCARD_HAS_MIDI
u16 mtc_state; /* State for MIDI input parsing state machine */
@ -464,11 +467,13 @@ static int load_firmware(struct echoaudio *chip);
static int wait_handshake(struct echoaudio *chip);
static int send_vector(struct echoaudio *chip, u32 command);
static int get_firmware(const struct firmware **fw_entry,
const struct firmware *frm, struct echoaudio *chip);
struct echoaudio *chip, const short fw_index);
static void free_firmware(const struct firmware *fw_entry);
#ifdef ECHOCARD_HAS_MIDI
static int enable_midi_input(struct echoaudio *chip, char enable);
static void snd_echo_midi_output_trigger(
struct snd_rawmidi_substream *substream, int up);
static int midi_service_irq(struct echoaudio *chip);
static int __devinit snd_echo_midi_create(struct snd_card *card,
struct echoaudio *chip);

View File

@ -227,12 +227,11 @@ static int load_asic(struct echoaudio *chip)
/* Give the DSP a few milliseconds to settle down */
mdelay(2);
err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC,
&card_fw[FW_3G_ASIC]);
err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, FW_3G_ASIC);
if (err < 0)
return err;
chip->asic_code = &card_fw[FW_3G_ASIC];
chip->asic_code = FW_3G_ASIC;
/* Now give the new ASIC some time to set up */
msleep(1000);

View File

@ -175,15 +175,15 @@ static inline int check_asic_status(struct echoaudio *chip)
#ifdef ECHOCARD_HAS_ASIC
/* Load ASIC code - done after the DSP is loaded */
static int load_asic_generic(struct echoaudio *chip, u32 cmd,
const struct firmware *asic)
static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
{
const struct firmware *fw;
int err;
u32 i, size;
u8 *code;
if ((err = get_firmware(&fw, asic, chip)) < 0) {
err = get_firmware(&fw, chip, asic);
if (err < 0) {
snd_printk(KERN_WARNING "Firmware not found !\n");
return err;
}
@ -245,7 +245,8 @@ static int install_resident_loader(struct echoaudio *chip)
return 0;
}
if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) {
i = get_firmware(&fw, chip, FW_361_LOADER);
if (i < 0) {
snd_printk(KERN_WARNING "Firmware not found !\n");
return i;
}
@ -485,7 +486,8 @@ static int load_firmware(struct echoaudio *chip)
chip->dsp_code = NULL;
}
if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0)
err = get_firmware(&fw, chip, chip->dsp_code_to_load);
if (err < 0)
return err;
err = load_dsp(chip, (u16 *)fw->data);
free_firmware(fw);
@ -495,9 +497,6 @@ static int load_firmware(struct echoaudio *chip)
if ((box_type = load_asic(chip)) < 0)
return box_type; /* error */
if ((err = restore_dsp_rettings(chip)) < 0)
return err;
return box_type;
}
@ -657,25 +656,89 @@ static void get_audio_meters(struct echoaudio *chip, long *meters)
static int restore_dsp_rettings(struct echoaudio *chip)
{
int err;
int i, o, err;
DE_INIT(("restore_dsp_settings\n"));
if ((err = check_asic_status(chip)) < 0)
return err;
/* @ Gina20/Darla20 only. Should be harmless for other cards. */
/* Gina20/Darla20 only. Should be harmless for other cards. */
chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF;
chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF;
chip->comm_page->handshake = 0xffffffff;
if ((err = set_sample_rate(chip, chip->sample_rate)) < 0)
/* Restore output busses */
for (i = 0; i < num_busses_out(chip); i++) {
err = set_output_gain(chip, i, chip->output_gain[i]);
if (err < 0)
return err;
}
#ifdef ECHOCARD_HAS_VMIXER
for (i = 0; i < num_pipes_out(chip); i++)
for (o = 0; o < num_busses_out(chip); o++) {
err = set_vmixer_gain(chip, o, i,
chip->vmixer_gain[o][i]);
if (err < 0)
return err;
}
if (update_vmixer_level(chip) < 0)
return -EIO;
#endif /* ECHOCARD_HAS_VMIXER */
#ifdef ECHOCARD_HAS_MONITOR
for (o = 0; o < num_busses_out(chip); o++)
for (i = 0; i < num_busses_in(chip); i++) {
err = set_monitor_gain(chip, o, i,
chip->monitor_gain[o][i]);
if (err < 0)
return err;
}
#endif /* ECHOCARD_HAS_MONITOR */
#ifdef ECHOCARD_HAS_INPUT_GAIN
for (i = 0; i < num_busses_in(chip); i++) {
err = set_input_gain(chip, i, chip->input_gain[i]);
if (err < 0)
return err;
}
#endif /* ECHOCARD_HAS_INPUT_GAIN */
err = update_output_line_level(chip);
if (err < 0)
return err;
if (chip->meters_enabled)
if (send_vector(chip, DSP_VC_METERS_ON) < 0)
return -EIO;
err = update_input_line_level(chip);
if (err < 0)
return err;
err = set_sample_rate(chip, chip->sample_rate);
if (err < 0)
return err;
if (chip->meters_enabled) {
err = send_vector(chip, DSP_VC_METERS_ON);
if (err < 0)
return err;
}
#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
if (set_digital_mode(chip, chip->digital_mode) < 0)
return -EIO;
#endif
#ifdef ECHOCARD_HAS_DIGITAL_IO
if (set_professional_spdif(chip, chip->professional_spdif) < 0)
return -EIO;
#endif
#ifdef ECHOCARD_HAS_PHANTOM_POWER
if (set_phantom_power(chip, chip->phantom_power) < 0)
return -EIO;
#endif
#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
/* set_input_clock() also restores automute setting */
if (set_input_clock(chip, chip->input_clock) < 0)
return -EIO;
#endif
@ -685,23 +748,14 @@ static int restore_dsp_rettings(struct echoaudio *chip)
return -EIO;
#endif
if (update_output_line_level(chip) < 0)
return -EIO;
if (update_input_line_level(chip) < 0)
return -EIO;
#ifdef ECHOCARD_HAS_VMIXER
if (update_vmixer_level(chip) < 0)
return -EIO;
#endif
if (wait_handshake(chip) < 0)
return -EIO;
clear_handshake(chip);
if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0)
return -EIO;
DE_INIT(("restore_dsp_rettings done\n"));
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
return 0;
}
@ -918,9 +972,6 @@ static int init_dsp_comm_page(struct echoaudio *chip)
chip->card_name = ECHOCARD_NAME;
chip->bad_board = TRUE; /* Set TRUE until DSP loaded */
chip->dsp_code = NULL; /* Current DSP code not loaded */
chip->digital_mode = DIGITAL_MODE_NONE;
chip->input_clock = ECHO_CLOCK_INTERNAL;
chip->output_clock = ECHO_CLOCK_WORD;
chip->asic_loaded = FALSE;
memset(chip->comm_page, 0, sizeof(struct comm_page));
@ -931,7 +982,6 @@ static int init_dsp_comm_page(struct echoaudio *chip)
chip->comm_page->midi_out_free_count =
cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
chip->comm_page->sample_rate = cpu_to_le32(44100);
chip->sample_rate = 44100;
/* Set line levels so we don't blast any inputs on startup */
memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE);
@ -942,50 +992,21 @@ static int init_dsp_comm_page(struct echoaudio *chip)
/* This function initializes the several volume controls for busses and pipes.
This MUST be called after the DSP is up and running ! */
/* This function initializes the chip structure with default values, ie. all
* muted and internal clock source. Then it copies the settings to the DSP.
* This MUST be called after the DSP is up and running !
*/
static int init_line_levels(struct echoaudio *chip)
{
int st, i, o;
DE_INIT(("init_line_levels\n"));
/* Mute output busses */
for (i = 0; i < num_busses_out(chip); i++)
if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED)))
return st;
if ((st = update_output_line_level(chip)))
return st;
#ifdef ECHOCARD_HAS_VMIXER
/* Mute the Vmixer */
for (i = 0; i < num_pipes_out(chip); i++)
for (o = 0; o < num_busses_out(chip); o++)
if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED)))
return st;
if ((st = update_vmixer_level(chip)))
return st;
#endif /* ECHOCARD_HAS_VMIXER */
#ifdef ECHOCARD_HAS_MONITOR
/* Mute the monitor mixer */
for (o = 0; o < num_busses_out(chip); o++)
for (i = 0; i < num_busses_in(chip); i++)
if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED)))
return st;
if ((st = update_output_line_level(chip)))
return st;
#endif /* ECHOCARD_HAS_MONITOR */
#ifdef ECHOCARD_HAS_INPUT_GAIN
for (i = 0; i < num_busses_in(chip); i++)
if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED)))
return st;
if ((st = update_input_line_level(chip)))
return st;
#endif /* ECHOCARD_HAS_INPUT_GAIN */
return 0;
memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain));
memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain));
memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain));
memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain));
chip->input_clock = ECHO_CLOCK_INTERNAL;
chip->output_clock = ECHO_CLOCK_WORD;
chip->sample_rate = 44100;
return restore_dsp_rettings(chip);
}

View File

@ -67,7 +67,7 @@ static const struct firmware card_fw[] = {
{0, "gina20_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */
{0,}
};

View File

@ -49,7 +49,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP];
chip->dsp_code_to_load = FW_GINA20_DSP;
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
chip->clock_state = GD_CLOCK_UNDEF;
/* Since this card has no ASIC, mark it as loaded so everything
@ -62,17 +62,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
err = set_professional_spdif(chip, TRUE);
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
chip->professional_spdif = FALSE;
return init_line_levels(chip);
}
static u32 detect_input_clocks(const struct echoaudio *chip)
{
u32 clocks_from_dsp, clock_bits;

View File

@ -85,7 +85,7 @@ static const struct firmware card_fw[] = {
{0, "gina24_361_asic.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */
{0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */
{0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */

View File

@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force);
static int set_input_clock(struct echoaudio *chip, u16 clock);
static int set_professional_spdif(struct echoaudio *chip, char prof);
static int set_digital_mode(struct echoaudio *chip, u8 mode);
static int load_asic_generic(struct echoaudio *chip, u32 cmd,
const struct firmware *asic);
static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
static int check_asic_status(struct echoaudio *chip);
@ -58,19 +57,16 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 |
ECHO_CLOCK_BIT_ADAT;
chip->professional_spdif = FALSE;
chip->digital_in_automute = TRUE;
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
/* Gina24 comes in both '301 and '361 flavors */
if (chip->device_id == DEVICE_ID_56361) {
chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP];
chip->dsp_code_to_load = FW_GINA24_361_DSP;
chip->digital_modes =
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
} else {
chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP];
chip->dsp_code_to_load = FW_GINA24_301_DSP;
chip->digital_modes =
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
@ -82,19 +78,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA);
if (err < 0)
return err;
err = set_professional_spdif(chip, TRUE);
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
chip->professional_spdif = FALSE;
chip->digital_in_automute = TRUE;
return init_line_levels(chip);
}
static u32 detect_input_clocks(const struct echoaudio *chip)
{
u32 clocks_from_dsp, clock_bits;
@ -125,7 +124,7 @@ static int load_asic(struct echoaudio *chip)
{
u32 control_reg;
int err;
const struct firmware *fw;
short asic;
if (chip->asic_loaded)
return 1;
@ -135,14 +134,15 @@ static int load_asic(struct echoaudio *chip)
/* Pick the correct ASIC for '301 or '361 Gina24 */
if (chip->device_id == DEVICE_ID_56361)
fw = &card_fw[FW_GINA24_361_ASIC];
asic = FW_GINA24_361_ASIC;
else
fw = &card_fw[FW_GINA24_301_ASIC];
asic = FW_GINA24_301_ASIC;
if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0)
err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic);
if (err < 0)
return err;
chip->asic_code = fw;
chip->asic_code = asic;
/* Now give the new ASIC a little time to set up */
mdelay(10);

View File

@ -68,7 +68,7 @@ static const struct firmware card_fw[] = {
{0, "indigo_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */
{0,}
};

View File

@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP];
chip->dsp_code_to_load = FW_INDIGO_DSP;
/* Since this card has no ASIC, mark it as loaded so everything
works OK */
chip->asic_loaded = TRUE;
@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
return init_line_levels(chip);
}
static u32 detect_input_clocks(const struct echoaudio *chip)
{
return ECHO_CLOCK_BIT_INTERNAL;

View File

@ -61,6 +61,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg |= clock;
if (control_reg != old_control_reg) {
DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
chip->comm_page->control_register = cpu_to_le32(control_reg);
chip->sample_rate = rate;
clear_handshake(chip);

View File

@ -68,7 +68,7 @@ static const struct firmware card_fw[] = {
{0, "indigo_dj_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/
{0,}
};

View File

@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP];
chip->dsp_code_to_load = FW_INDIGO_DJ_DSP;
/* Since this card has no ASIC, mark it as loaded so everything
works OK */
chip->asic_loaded = TRUE;
@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
if ((err = init_line_levels(chip)) < 0)
return err;
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
return init_line_levels(chip);
}
static u32 detect_input_clocks(const struct echoaudio *chip)
{
return ECHO_CLOCK_BIT_INTERNAL;

View File

@ -68,7 +68,7 @@ static const struct firmware card_fw[] = {
{0, "indigo_djx_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/
{0,}
};

View File

@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP];
chip->dsp_code_to_load = FW_INDIGO_DJX_DSP;
/* Since this card has no ASIC, mark it as loaded so everything
works OK */
chip->asic_loaded = TRUE;
@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
err = init_line_levels(chip);
if (err < 0)
return err;
DE_INIT(("init_hw done\n"));
return err;
}
static int set_mixer_defaults(struct echoaudio *chip)
{
return init_line_levels(chip);
}

View File

@ -69,7 +69,7 @@ static const struct firmware card_fw[] = {
{0, "indigo_io_dsp.fw"}
};
static struct pci_device_id snd_echo_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
{0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/
{0,}
};

Some files were not shown because too many files have changed in this diff Show More