Merge branch 'topic/misc' into fix/misc
This commit is contained in:
commit
a9104f9899
|
@ -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/UA-1000 audio/MIDI interfaces.
|
||||
|
||||
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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 bFormatType;
|
||||
__u8 bSubslotSize;
|
||||
__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
|
||||
|
|
|
@ -544,7 +544,7 @@ struct snd_rawmidi_status {
|
|||
* Timer section - /dev/snd/timer
|
||||
*/
|
||||
|
||||
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 5)
|
||||
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
|
||||
|
||||
enum {
|
||||
SNDRV_TIMER_CLASS_NONE = -1,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -393,7 +393,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
|
|||
event == SNDRV_TIMER_EVENT_CONTINUE)
|
||||
resolution = snd_timer_resolution(ti);
|
||||
if (ti->ccallback)
|
||||
ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution);
|
||||
ti->ccallback(ti, event, &tstamp, resolution);
|
||||
if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
|
||||
return;
|
||||
timer = ti->timer;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
|
@ -1558,7 +1558,7 @@ static int __devinit snd_card_miro_pnp(struct snd_miro *chip,
|
|||
|
||||
err = pnp_activate_dev(devmc);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n",
|
||||
snd_printk(KERN_ERR "MC pnp configure failure: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
@ -143,12 +144,8 @@ struct snd_opti9xx {
|
|||
|
||||
spinlock_t lock;
|
||||
|
||||
long wss_base;
|
||||
int irq;
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
struct pnp_dev *dev;
|
||||
struct pnp_dev *devmpu;
|
||||
#endif /* CONFIG_PNP */
|
||||
};
|
||||
|
||||
static int snd_opti9xx_pnp_is_probed;
|
||||
|
@ -158,12 +155,17 @@ static int snd_opti9xx_pnp_is_probed;
|
|||
static struct pnp_card_device_id snd_opti9xx_pnpids[] = {
|
||||
#ifndef OPTi93X
|
||||
/* OPTi 82C924 */
|
||||
{ .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 },
|
||||
{ .id = "OPT0924",
|
||||
.devs = { { "OPT0000" }, { "OPT0002" }, { "OPT0005" } },
|
||||
.driver_data = 0x0924 },
|
||||
/* OPTi 82C925 */
|
||||
{ .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 },
|
||||
{ .id = "OPT0925",
|
||||
.devs = { { "OPT9250" }, { "OPT0002" }, { "OPT0005" } },
|
||||
.driver_data = 0x0925 },
|
||||
#else
|
||||
/* OPTi 82C931/3 */
|
||||
{ .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 },
|
||||
{ .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } },
|
||||
.driver_data = 0x0931 },
|
||||
#endif /* OPTi93X */
|
||||
{ .id = "" }
|
||||
};
|
||||
|
@ -206,24 +208,35 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
|
|||
chip->hardware = hardware;
|
||||
strcpy(chip->name, snd_opti9xx_names[hardware]);
|
||||
|
||||
chip->mc_base_size = opti9xx_mc_size[hardware];
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
chip->irq = -1;
|
||||
|
||||
#ifndef OPTi93X
|
||||
#ifdef CONFIG_PNP
|
||||
if (isapnp && chip->mc_base)
|
||||
/* PnP resource gives the least 10 bits */
|
||||
chip->mc_base |= 0xc00;
|
||||
else
|
||||
#endif /* CONFIG_PNP */
|
||||
{
|
||||
chip->mc_base = 0xf8c;
|
||||
chip->mc_base_size = opti9xx_mc_size[hardware];
|
||||
}
|
||||
#else
|
||||
chip->mc_base_size = opti9xx_mc_size[hardware];
|
||||
#endif
|
||||
|
||||
switch (hardware) {
|
||||
#ifndef OPTi93X
|
||||
case OPTi9XX_HW_82C928:
|
||||
case OPTi9XX_HW_82C929:
|
||||
chip->mc_base = 0xf8c;
|
||||
chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3;
|
||||
chip->pwd_reg = 3;
|
||||
break;
|
||||
|
||||
case OPTi9XX_HW_82C924:
|
||||
case OPTi9XX_HW_82C925:
|
||||
chip->mc_base = 0xf8c;
|
||||
chip->password = 0xe5;
|
||||
chip->pwd_reg = 3;
|
||||
break;
|
||||
|
@ -291,7 +304,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
|
|||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
|
||||
unsigned char value)
|
||||
{
|
||||
|
@ -340,7 +353,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
|
|||
|
||||
|
||||
static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||
long wss_base,
|
||||
long port,
|
||||
int irq, int dma1, int dma2,
|
||||
long mpu_port, int mpu_irq)
|
||||
{
|
||||
|
@ -353,16 +366,23 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
|||
switch (chip->hardware) {
|
||||
#ifndef OPTi93X
|
||||
case OPTi9XX_HW_82C924:
|
||||
/* opti 929 mode (?), OPL3 clock output, audio enable */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc);
|
||||
/* enable wave audio */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
|
||||
|
||||
case OPTi9XX_HW_82C925:
|
||||
/* enable WSS mode */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
|
||||
/* OPL3 FM synthesis */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20);
|
||||
/* disable Sound Blaster IRQ and DMA */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
|
||||
#ifdef CS4231
|
||||
/* cs4231/4248 fix enabled */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
|
||||
#else
|
||||
/* cs4231/4248 fix disabled */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02);
|
||||
#endif /* CS4231 */
|
||||
break;
|
||||
|
@ -410,21 +430,26 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (wss_base) {
|
||||
case 0x530:
|
||||
/* PnP resource says it decodes only 10 bits of address */
|
||||
switch (port & 0x3ff) {
|
||||
case 0x130:
|
||||
chip->wss_base = 0x530;
|
||||
wss_base_bits = 0x00;
|
||||
break;
|
||||
case 0x604:
|
||||
case 0x204:
|
||||
chip->wss_base = 0x604;
|
||||
wss_base_bits = 0x03;
|
||||
break;
|
||||
case 0xe80:
|
||||
case 0x280:
|
||||
chip->wss_base = 0xe80;
|
||||
wss_base_bits = 0x01;
|
||||
break;
|
||||
case 0xf40:
|
||||
case 0x340:
|
||||
chip->wss_base = 0xf40;
|
||||
wss_base_bits = 0x02;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", port);
|
||||
goto __skip_base;
|
||||
}
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
|
||||
|
@ -486,7 +511,7 @@ __skip_base:
|
|||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
#ifndef OPTi93X
|
||||
outb(irq_bits << 3 | dma_bits, wss_base);
|
||||
outb(irq_bits << 3 | dma_bits, chip->wss_base);
|
||||
#else /* OPTi93X */
|
||||
snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
|
||||
#endif /* OPTi93X */
|
||||
|
@ -546,6 +571,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;
|
||||
|
@ -641,15 +753,15 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
|
|||
{
|
||||
struct pnp_dev *pdev;
|
||||
int err;
|
||||
struct pnp_dev *devmpu;
|
||||
#ifndef OPTi93X
|
||||
struct pnp_dev *devmc;
|
||||
#endif
|
||||
|
||||
chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
|
||||
if (chip->dev == NULL)
|
||||
pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
|
||||
if (pdev == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
|
||||
|
||||
pdev = chip->dev;
|
||||
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
|
||||
|
@ -662,9 +774,24 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
|
|||
chip->mc_indir_index = pnp_port_start(pdev, 3) + 2;
|
||||
chip->mc_indir_size = pnp_port_len(pdev, 3) - 2;
|
||||
#else
|
||||
if (pid->driver_data != 0x0924)
|
||||
port = pnp_port_start(pdev, 1);
|
||||
devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
|
||||
if (devmc == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
err = pnp_activate_dev(devmc);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "MC pnp configure failure: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
port = pnp_port_start(pdev, 1);
|
||||
fm_port = pnp_port_start(pdev, 2) + 8;
|
||||
/*
|
||||
* The MC(0) is never accessed and card does not
|
||||
* include it in the PnP resource range. OPTI93x include it.
|
||||
*/
|
||||
chip->mc_base = pnp_port_start(devmc, 0) - 1;
|
||||
chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
|
||||
#endif /* OPTi93X */
|
||||
irq = pnp_irq(pdev, 0);
|
||||
dma1 = pnp_dma(pdev, 0);
|
||||
|
@ -672,16 +799,16 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
|
|||
dma2 = pnp_dma(pdev, 1);
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
pdev = chip->devmpu;
|
||||
if (pdev && mpu_port > 0) {
|
||||
err = pnp_activate_dev(pdev);
|
||||
devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
|
||||
|
||||
if (devmpu && mpu_port > 0) {
|
||||
err = pnp_activate_dev(devmpu);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "AUDIO pnp configure failure\n");
|
||||
snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
|
||||
mpu_port = -1;
|
||||
chip->devmpu = NULL;
|
||||
} else {
|
||||
mpu_port = pnp_port_start(pdev, 0);
|
||||
mpu_irq = pnp_irq(pdev, 0);
|
||||
mpu_port = pnp_port_start(devmpu, 0);
|
||||
mpu_irq = pnp_irq(devmpu, 0);
|
||||
}
|
||||
}
|
||||
return pid->driver_data;
|
||||
|
@ -736,7 +863,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
|
||||
error = snd_wss_create(card, chip->wss_base + 4, -1, irq, dma1, xdma2,
|
||||
#ifdef OPTi93X
|
||||
WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
|
||||
#else
|
||||
|
@ -754,6 +881,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)
|
||||
|
@ -772,10 +904,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
|||
sprintf(card->shortname, "OPTi %s", card->driver);
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
|
||||
card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
|
||||
card->shortname, pcm->name,
|
||||
chip->wss_base + 4, irq, dma1, xdma2);
|
||||
#else
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
|
||||
card->shortname, pcm->name, port + 4, irq, dma1);
|
||||
card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
|
||||
|
@ -969,9 +1102,6 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
|
|||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
if (hw <= OPTi9XX_HW_82C930)
|
||||
chip->mc_base -= 0x80;
|
||||
|
||||
error = snd_opti9xx_read_check(chip);
|
||||
if (error) {
|
||||
snd_printk(KERN_ERR "OPTI chip not found\n");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,405 @@
|
|||
|
||||
/*
|
||||
* 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 <linux/delay.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)
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Coprocessor access types
|
||||
* Coprocessor access types
|
||||
*/
|
||||
#define COPR_CUSTOM 0x0001 /* Custom applications */
|
||||
#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */
|
||||
|
|
|
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2,9 +2,9 @@ typedef struct vmidi_devc {
|
|||
int dev;
|
||||
|
||||
/* State variables */
|
||||
int opened;
|
||||
int opened;
|
||||
spinlock_t lock;
|
||||
|
||||
|
||||
/* MIDI fields */
|
||||
int my_mididev;
|
||||
int pair_mididev;
|
||||
|
@ -12,4 +12,3 @@ typedef struct vmidi_devc {
|
|||
int intr_active;
|
||||
void (*midi_input_intr) (int dev, unsigned char data);
|
||||
} vmidi_devc;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, },
|
||||
};
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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, }
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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, }
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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, }
|
||||
|
|
|
@ -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),
|
||||
{ }
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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) },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,}
|
||||
|
|
|
@ -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) },
|
||||
{}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
@ -1876,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;
|
||||
|
@ -1913,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);
|
||||
|
@ -1964,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;
|
||||
|
@ -1975,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;
|
||||
|
@ -2010,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;
|
||||
|
@ -2149,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;
|
||||
|
@ -2171,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 */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,}
|
||||
};
|
||||
|
|
|
@ -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_IO_DSP];
|
||||
chip->dsp_code_to_load = FW_INDIGO_IO_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;
|
||||
|
|
|
@ -69,7 +69,7 @@ static const struct firmware card_fw[] = {
|
|||
{0, "indigo_iox_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */
|
||||
{0,}
|
||||
};
|
||||
|
|
|
@ -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_IOX_DSP];
|
||||
chip->dsp_code_to_load = FW_INDIGO_IOX_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);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ static const struct firmware card_fw[] = {
|
|||
{0, "layla20_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */
|
||||
{0,}
|
||||
|
|
|
@ -31,8 +31,7 @@
|
|||
|
||||
static int read_dsp(struct echoaudio *chip, u32 *data);
|
||||
static int set_professional_spdif(struct echoaudio *chip, char prof);
|
||||
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);
|
||||
static int update_flags(struct echoaudio *chip);
|
||||
|
||||
|
@ -54,7 +53,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_LAYLA20_DSP];
|
||||
chip->dsp_code_to_load = FW_LAYLA20_DSP;
|
||||
chip->input_clock_types =
|
||||
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
|
||||
|
@ -65,17 +64,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;
|
||||
|
@ -144,7 +146,7 @@ static int load_asic(struct echoaudio *chip)
|
|||
return 0;
|
||||
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,
|
||||
&card_fw[FW_LAYLA20_ASIC]);
|
||||
FW_LAYLA20_ASIC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ static const struct firmware card_fw[] = {
|
|||
{0, "layla24_2S_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */
|
||||
{0,}
|
||||
};
|
||||
|
|
|
@ -32,8 +32,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);
|
||||
|
||||
|
||||
|
@ -54,7 +53,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_LAYLA24_DSP];
|
||||
chip->dsp_code_to_load = FW_LAYLA24_DSP;
|
||||
chip->input_clock_types =
|
||||
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
|
||||
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT;
|
||||
|
@ -62,9 +61,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
|||
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->digital_in_automute = TRUE;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
return err;
|
||||
|
@ -73,17 +69,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
|||
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;
|
||||
|
@ -123,18 +124,18 @@ static int load_asic(struct echoaudio *chip)
|
|||
|
||||
/* Load the ASIC for the PCI card */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC,
|
||||
&card_fw[FW_LAYLA24_1_ASIC]);
|
||||
FW_LAYLA24_1_ASIC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC];
|
||||
chip->asic_code = FW_LAYLA24_2S_ASIC;
|
||||
|
||||
/* Now give the new ASIC a little time to set up */
|
||||
mdelay(10);
|
||||
|
||||
/* Do the external one */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
|
||||
&card_fw[FW_LAYLA24_2S_ASIC]);
|
||||
FW_LAYLA24_2S_ASIC);
|
||||
if (err < 0)
|
||||
return FALSE;
|
||||
|
||||
|
@ -299,7 +300,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
|
|||
/* Depending on what digital mode you want, Layla24 needs different ASICs
|
||||
loaded. This function checks the ASIC needed for the new mode and sees
|
||||
if it matches the one already loaded. */
|
||||
static int switch_asic(struct echoaudio *chip, const struct firmware *asic)
|
||||
static int switch_asic(struct echoaudio *chip, short asic)
|
||||
{
|
||||
s8 *monitors;
|
||||
|
||||
|
@ -335,7 +336,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
|||
{
|
||||
u32 control_reg;
|
||||
int err, incompatible_clock;
|
||||
const struct firmware *asic;
|
||||
short asic;
|
||||
|
||||
/* Set clock to "internal" if it's not compatible with the new mode */
|
||||
incompatible_clock = FALSE;
|
||||
|
@ -344,12 +345,12 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
|||
case DIGITAL_MODE_SPDIF_RCA:
|
||||
if (chip->input_clock == ECHO_CLOCK_ADAT)
|
||||
incompatible_clock = TRUE;
|
||||
asic = &card_fw[FW_LAYLA24_2S_ASIC];
|
||||
asic = FW_LAYLA24_2S_ASIC;
|
||||
break;
|
||||
case DIGITAL_MODE_ADAT:
|
||||
if (chip->input_clock == ECHO_CLOCK_SPDIF)
|
||||
incompatible_clock = TRUE;
|
||||
asic = &card_fw[FW_LAYLA24_2A_ASIC];
|
||||
asic = FW_LAYLA24_2A_ASIC;
|
||||
break;
|
||||
default:
|
||||
DE_ACT(("Digital mode not supported: %d\n", mode));
|
||||
|
|
|
@ -77,7 +77,7 @@ static const struct firmware card_fw[] = {
|
|||
{0, "mia_dsp.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
|
||||
{0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */
|
||||
{0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */
|
||||
{0,}
|
||||
|
|
|
@ -53,7 +53,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_MIA_DSP];
|
||||
chip->dsp_code_to_load = FW_MIA_DSP;
|
||||
/* Since this card has no ASIC, mark it as loaded so everything
|
||||
works OK */
|
||||
chip->asic_loaded = TRUE;
|
||||
|
@ -66,15 +66,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)))
|
||||
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;
|
||||
|
|
|
@ -92,7 +92,7 @@ static const struct firmware card_fw[] = {
|
|||
{0, "mona_2_asic.fw"}
|
||||
};
|
||||
|
||||
static struct pci_device_id snd_echo_ids[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = {
|
||||
{0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */
|
||||
{0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
@ -64,32 +63,30 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
|
|||
|
||||
/* Mona comes in both '301 and '361 flavors */
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP];
|
||||
chip->dsp_code_to_load = FW_MONA_361_DSP;
|
||||
else
|
||||
chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP];
|
||||
|
||||
chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
|
||||
chip->professional_spdif = FALSE;
|
||||
chip->digital_in_automute = TRUE;
|
||||
chip->dsp_code_to_load = FW_MONA_301_DSP;
|
||||
|
||||
if ((err = load_firmware(chip)) < 0)
|
||||
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;
|
||||
|
@ -120,7 +117,7 @@ static int load_asic(struct echoaudio *chip)
|
|||
{
|
||||
u32 control_reg;
|
||||
int err;
|
||||
const struct firmware *asic;
|
||||
short asic;
|
||||
|
||||
if (chip->asic_loaded)
|
||||
return 0;
|
||||
|
@ -128,9 +125,9 @@ static int load_asic(struct echoaudio *chip)
|
|||
mdelay(10);
|
||||
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC48];
|
||||
asic = FW_MONA_361_1_ASIC48;
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC48];
|
||||
asic = FW_MONA_301_1_ASIC48;
|
||||
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic);
|
||||
if (err < 0)
|
||||
|
@ -141,7 +138,7 @@ static int load_asic(struct echoaudio *chip)
|
|||
|
||||
/* Do the external one */
|
||||
err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC,
|
||||
&card_fw[FW_MONA_2_ASIC]);
|
||||
FW_MONA_2_ASIC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -165,22 +162,22 @@ loaded. This function checks the ASIC needed for the new mode and sees
|
|||
if it matches the one already loaded. */
|
||||
static int switch_asic(struct echoaudio *chip, char double_speed)
|
||||
{
|
||||
const struct firmware *asic;
|
||||
int err;
|
||||
short asic;
|
||||
|
||||
/* Check the clock detect bits to see if this is
|
||||
a single-speed clock or a double-speed clock; load
|
||||
a new ASIC if necessary. */
|
||||
if (chip->device_id == DEVICE_ID_56361) {
|
||||
if (double_speed)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC96];
|
||||
asic = FW_MONA_361_1_ASIC96;
|
||||
else
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC48];
|
||||
asic = FW_MONA_361_1_ASIC48;
|
||||
} else {
|
||||
if (double_speed)
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC96];
|
||||
asic = FW_MONA_301_1_ASIC96;
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC48];
|
||||
asic = FW_MONA_301_1_ASIC48;
|
||||
}
|
||||
|
||||
if (asic != chip->asic_code) {
|
||||
|
@ -200,7 +197,7 @@ static int switch_asic(struct echoaudio *chip, char double_speed)
|
|||
static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
||||
{
|
||||
u32 control_reg, clock;
|
||||
const struct firmware *asic;
|
||||
short asic;
|
||||
char force_write;
|
||||
|
||||
/* Only set the clock for internal mode. */
|
||||
|
@ -218,14 +215,14 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
|
|||
if (chip->digital_mode == DIGITAL_MODE_ADAT)
|
||||
return -EINVAL;
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC96];
|
||||
asic = FW_MONA_361_1_ASIC96;
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC96];
|
||||
asic = FW_MONA_301_1_ASIC96;
|
||||
} else {
|
||||
if (chip->device_id == DEVICE_ID_56361)
|
||||
asic = &card_fw[FW_MONA_361_1_ASIC48];
|
||||
asic = FW_MONA_361_1_ASIC48;
|
||||
else
|
||||
asic = &card_fw[FW_MONA_301_1_ASIC48];
|
||||
asic = FW_MONA_301_1_ASIC48;
|
||||
}
|
||||
|
||||
force_write = 0;
|
||||
|
@ -410,8 +407,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
|
|||
case DIGITAL_MODE_ADAT:
|
||||
/* If the current ASIC is the 96KHz ASIC, switch the ASIC
|
||||
and set to 48 KHz */
|
||||
if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] ||
|
||||
chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) {
|
||||
if (chip->asic_code == FW_MONA_361_1_ASIC96 ||
|
||||
chip->asic_code == FW_MONA_301_1_ASIC96) {
|
||||
set_sample_rate(chip, 48000);
|
||||
}
|
||||
control_reg |= GML_ADAT_MODE;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue