Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (148 commits) [ALSA] intel8x0m - Free irq in suspend [ALSA] Move CONFIG_SND_AC97_POWER_SAVE to pci/Kconfig [ALSA] usb-audio: add mixer control names for the Aureon 5.1 MkII [ALSA] ES1938: remove duplicate field initialization [ALSA] usb-audio: increase number of packets per URB [ALSA] hda-codec - Fix headphone auto-toggle on sigmatel codec [ALSA] hda-intel - A slight cleanup of timeout check in azx_get_response() [ALSA] hda-codec - Fix mic input with STAC92xx codecs [ALSA] mixart: Use SEEK_{SET,CUR,END} instead of hardcoded values [ALSA] gus: Use SEEK_{SET,CUR,END} instead of hardcoded values [ALSA] opl4: Use SEEK_{SET,CUR,END} instead of hardcoded values [ALSA] sound core: Use SEEK_{SET,CUR,END} instead of hardcoded values [ALSA] hda-codec - Support multiple headphone pins [ALSA] hda_intel prefer 24bit instead of 20bit [ALSA] hda-codec - Add vendor ids for Motorola and Conexant [ALSA] hda-codec - Add device id for Motorola si3054-compatible codec [ALSA] Add missing compat ioctls for ALSA control API [ALSA] powermac - Fix Oops when conflicting with aoa driver [ALSA] aoa: add locking to tas codec [ALSA] hda-intel - Fix suspend/resume with MSI ...
This commit is contained in:
commit
f7425b160d
|
@ -758,6 +758,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||||
position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
|
position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
|
||||||
single_cmd - Use single immediate commands to communicate with
|
single_cmd - Use single immediate commands to communicate with
|
||||||
codecs (for debugging only)
|
codecs (for debugging only)
|
||||||
|
disable_msi - Disable Message Signaled Interrupt (MSI)
|
||||||
|
|
||||||
This module supports one card and autoprobe.
|
This module supports one card and autoprobe.
|
||||||
|
|
||||||
|
@ -778,11 +779,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||||
6stack-digout 6-jack with a SPDIF out
|
6stack-digout 6-jack with a SPDIF out
|
||||||
w810 3-jack
|
w810 3-jack
|
||||||
z71v 3-jack (HP shared SPDIF)
|
z71v 3-jack (HP shared SPDIF)
|
||||||
asus 3-jack
|
asus 3-jack (ASUS Mobo)
|
||||||
|
asus-w1v ASUS W1V
|
||||||
|
asus-dig ASUS with SPDIF out
|
||||||
|
asus-dig2 ASUS with SPDIF out (using GPIO2)
|
||||||
uniwill 3-jack
|
uniwill 3-jack
|
||||||
F1734 2-jack
|
F1734 2-jack
|
||||||
lg LG laptop (m1 express dual)
|
lg LG laptop (m1 express dual)
|
||||||
lg-lw LG LW20 laptop
|
lg-lw LG LW20/LW25 laptop
|
||||||
|
tcl TCL S700
|
||||||
|
clevo Clevo laptops (m520G, m665n)
|
||||||
test for testing/debugging purpose, almost all controls can be
|
test for testing/debugging purpose, almost all controls can be
|
||||||
adjusted. Appearing only when compiled with
|
adjusted. Appearing only when compiled with
|
||||||
$CONFIG_SND_DEBUG=y
|
$CONFIG_SND_DEBUG=y
|
||||||
|
@ -790,6 +796,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||||
|
|
||||||
ALC260
|
ALC260
|
||||||
hp HP machines
|
hp HP machines
|
||||||
|
hp-3013 HP machines (3013-variant)
|
||||||
fujitsu Fujitsu S7020
|
fujitsu Fujitsu S7020
|
||||||
acer Acer TravelMate
|
acer Acer TravelMate
|
||||||
basic fixed pin assignment (old default model)
|
basic fixed pin assignment (old default model)
|
||||||
|
@ -797,24 +804,32 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||||
|
|
||||||
ALC262
|
ALC262
|
||||||
fujitsu Fujitsu Laptop
|
fujitsu Fujitsu Laptop
|
||||||
|
hp-bpc HP xw4400/6400/8400/9400 laptops
|
||||||
|
benq Benq ED8
|
||||||
basic fixed pin assignment w/o SPDIF
|
basic fixed pin assignment w/o SPDIF
|
||||||
auto auto-config reading BIOS (default)
|
auto auto-config reading BIOS (default)
|
||||||
|
|
||||||
ALC882/885
|
ALC882/885
|
||||||
3stack-dig 3-jack with SPDIF I/O
|
3stack-dig 3-jack with SPDIF I/O
|
||||||
6stck-dig 6-jack digital with SPDIF I/O
|
6stck-dig 6-jack digital with SPDIF I/O
|
||||||
|
arima Arima W820Di1
|
||||||
auto auto-config reading BIOS (default)
|
auto auto-config reading BIOS (default)
|
||||||
|
|
||||||
ALC883/888
|
ALC883/888
|
||||||
3stack-dig 3-jack with SPDIF I/O
|
3stack-dig 3-jack with SPDIF I/O
|
||||||
6stack-dig 6-jack digital with SPDIF I/O
|
6stack-dig 6-jack digital with SPDIF I/O
|
||||||
6stack-dig-demo 6-stack digital for Intel demo board
|
3stack-6ch 3-jack 6-channel
|
||||||
|
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
|
||||||
|
6stack-dig-demo 6-jack digital for Intel demo board
|
||||||
|
acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
|
||||||
auto auto-config reading BIOS (default)
|
auto auto-config reading BIOS (default)
|
||||||
|
|
||||||
ALC861/660
|
ALC861/660
|
||||||
3stack 3-jack
|
3stack 3-jack
|
||||||
3stack-dig 3-jack with SPDIF I/O
|
3stack-dig 3-jack with SPDIF I/O
|
||||||
6stack-dig 6-jack with SPDIF I/O
|
6stack-dig 6-jack with SPDIF I/O
|
||||||
|
3stack-660 3-jack (for ALC660)
|
||||||
|
uniwill-m31 Uniwill M31 laptop
|
||||||
auto auto-config reading BIOS (default)
|
auto auto-config reading BIOS (default)
|
||||||
|
|
||||||
CMI9880
|
CMI9880
|
||||||
|
@ -843,10 +858,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||||
3stack-dig ditto with SPDIF
|
3stack-dig ditto with SPDIF
|
||||||
laptop 3-jack with hp-jack automute
|
laptop 3-jack with hp-jack automute
|
||||||
laptop-dig ditto with SPDIF
|
laptop-dig ditto with SPDIF
|
||||||
auto auto-confgi reading BIOS (default)
|
auto auto-config reading BIOS (default)
|
||||||
|
|
||||||
STAC7661(?)
|
STAC9200/9205/9220/9221/9254
|
||||||
|
ref Reference board
|
||||||
|
3stack D945 3stack
|
||||||
|
5stack D945 5stack + SPDIF
|
||||||
|
|
||||||
|
STAC9227/9228/9229/927x
|
||||||
|
ref Reference board
|
||||||
|
3stack D965 3stack
|
||||||
|
5stack D965 5stack + SPDIF
|
||||||
|
|
||||||
|
STAC9872
|
||||||
vaio Setup for VAIO FE550G/SZ110
|
vaio Setup for VAIO FE550G/SZ110
|
||||||
|
vaio-ar Setup for VAIO AR
|
||||||
|
|
||||||
If the default configuration doesn't work and one of the above
|
If the default configuration doesn't work and one of the above
|
||||||
matches with your device, report it together with the PCI
|
matches with your device, report it together with the PCI
|
||||||
|
@ -1213,6 +1239,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||||
|
|
||||||
Module supports only 1 card. This module has no enable option.
|
Module supports only 1 card. This module has no enable option.
|
||||||
|
|
||||||
|
Module snd-mts64
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Module for Ego Systems (ESI) Miditerminal 4140
|
||||||
|
|
||||||
|
This module supports multiple devices.
|
||||||
|
Requires parport (CONFIG_PARPORT).
|
||||||
|
|
||||||
Module snd-nm256
|
Module snd-nm256
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
|
@ -1054,9 +1054,8 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For a device which allows hotplugging, you can use
|
For a device which allows hotplugging, you can use
|
||||||
<function>snd_card_free_in_thread</function>. This one will
|
<function>snd_card_free_when_closed</function>. This one will
|
||||||
postpone the destruction and wait in a kernel-thread until all
|
postpone the destruction until all devices are closed.
|
||||||
devices are closed.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "control.h"
|
#include "control.h"
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
|
@ -140,6 +141,20 @@
|
||||||
#define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */
|
#define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */
|
||||||
#define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */
|
#define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */
|
||||||
|
|
||||||
|
/* powerdown bits */
|
||||||
|
#define AC97_PD_ADC_STATUS 0x0001 /* ADC status (RO) */
|
||||||
|
#define AC97_PD_DAC_STATUS 0x0002 /* DAC status (RO) */
|
||||||
|
#define AC97_PD_MIXER_STATUS 0x0004 /* Analog mixer status (RO) */
|
||||||
|
#define AC97_PD_VREF_STATUS 0x0008 /* Vref status (RO) */
|
||||||
|
#define AC97_PD_PR0 0x0100 /* Power down PCM ADCs and input MUX */
|
||||||
|
#define AC97_PD_PR1 0x0200 /* Power down PCM front DAC */
|
||||||
|
#define AC97_PD_PR2 0x0400 /* Power down Mixer (Vref still on) */
|
||||||
|
#define AC97_PD_PR3 0x0800 /* Power down Mixer (Vref off) */
|
||||||
|
#define AC97_PD_PR4 0x1000 /* Power down AC-Link */
|
||||||
|
#define AC97_PD_PR5 0x2000 /* Disable internal clock usage */
|
||||||
|
#define AC97_PD_PR6 0x4000 /* Headphone amplifier */
|
||||||
|
#define AC97_PD_EAPD 0x8000 /* External Amplifer Power Down (EAPD) */
|
||||||
|
|
||||||
/* extended audio ID bit defines */
|
/* extended audio ID bit defines */
|
||||||
#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
|
#define AC97_EI_VRA 0x0001 /* Variable bit rate supported */
|
||||||
#define AC97_EI_DRA 0x0002 /* Double rate supported */
|
#define AC97_EI_DRA 0x0002 /* Double rate supported */
|
||||||
|
@ -359,6 +374,7 @@
|
||||||
#define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */
|
#define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */
|
||||||
#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
|
#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
|
||||||
#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
|
#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
|
||||||
|
#define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */
|
||||||
|
|
||||||
/* ac97->flags */
|
/* ac97->flags */
|
||||||
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
|
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
|
||||||
|
@ -491,6 +507,12 @@ struct snd_ac97 {
|
||||||
/* jack-sharing info */
|
/* jack-sharing info */
|
||||||
unsigned char indep_surround;
|
unsigned char indep_surround;
|
||||||
unsigned char channel_mode;
|
unsigned char channel_mode;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
unsigned int power_up; /* power states */
|
||||||
|
struct workqueue_struct *power_workq;
|
||||||
|
struct work_struct power_work;
|
||||||
|
#endif
|
||||||
struct device dev;
|
struct device dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -532,6 +554,15 @@ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
|
||||||
void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
||||||
int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value);
|
||||||
int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value);
|
int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup);
|
||||||
|
#else
|
||||||
|
static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg,
|
||||||
|
int powerup)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void snd_ac97_suspend(struct snd_ac97 *ac97);
|
void snd_ac97_suspend(struct snd_ac97 *ac97);
|
||||||
void snd_ac97_resume(struct snd_ac97 *ac97);
|
void snd_ac97_resume(struct snd_ac97 *ac97);
|
||||||
|
@ -583,6 +614,7 @@ struct ac97_pcm {
|
||||||
copy_flag: 1, /* lowlevel driver must fill all entries */
|
copy_flag: 1, /* lowlevel driver must fill all entries */
|
||||||
spdif: 1; /* spdif pcm */
|
spdif: 1; /* spdif pcm */
|
||||||
unsigned short aslots; /* active slots */
|
unsigned short aslots; /* active slots */
|
||||||
|
unsigned short cur_dbl; /* current double-rate state */
|
||||||
unsigned int rates; /* available rates */
|
unsigned int rates; /* available rates */
|
||||||
struct {
|
struct {
|
||||||
unsigned short slots; /* driver input: requested AC97 slot numbers */
|
unsigned short slots; /* driver input: requested AC97 slot numbers */
|
||||||
|
|
|
@ -179,14 +179,13 @@ enum { AD1848_MIX_SINGLE, AD1848_MIX_DOUBLE, AD1848_MIX_CAPTURE };
|
||||||
#define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
#define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
||||||
((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22))
|
((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22))
|
||||||
|
|
||||||
int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value);
|
|
||||||
|
|
||||||
/* for ease of use */
|
/* for ease of use */
|
||||||
struct ad1848_mix_elem {
|
struct ad1848_mix_elem {
|
||||||
const char *name;
|
const char *name;
|
||||||
int index;
|
int index;
|
||||||
int type;
|
int type;
|
||||||
unsigned long private_value;
|
unsigned long private_value;
|
||||||
|
unsigned int *tlv;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
|
#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
|
||||||
|
@ -195,15 +194,26 @@ struct ad1848_mix_elem {
|
||||||
.type = AD1848_MIX_SINGLE, \
|
.type = AD1848_MIX_SINGLE, \
|
||||||
.private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) }
|
.private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) }
|
||||||
|
|
||||||
|
#define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
||||||
|
{ .name = xname, \
|
||||||
|
.index = xindex, \
|
||||||
|
.type = AD1848_MIX_SINGLE, \
|
||||||
|
.private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert), \
|
||||||
|
.tlv = xtlv }
|
||||||
|
|
||||||
#define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
#define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
||||||
{ .name = xname, \
|
{ .name = xname, \
|
||||||
.index = xindex, \
|
.index = xindex, \
|
||||||
.type = AD1848_MIX_DOUBLE, \
|
.type = AD1848_MIX_DOUBLE, \
|
||||||
.private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) }
|
.private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) }
|
||||||
|
|
||||||
static inline int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c)
|
#define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
|
||||||
{
|
{ .name = xname, \
|
||||||
return snd_ad1848_add_ctl(chip, c->name, c->index, c->type, c->private_value);
|
.index = xindex, \
|
||||||
}
|
.type = AD1848_MIX_DOUBLE, \
|
||||||
|
.private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert), \
|
||||||
|
.tlv = xtlv }
|
||||||
|
|
||||||
|
int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c);
|
||||||
|
|
||||||
#endif /* __SOUND_AD1848_H */
|
#endif /* __SOUND_AD1848_H */
|
||||||
|
|
|
@ -39,26 +39,39 @@ struct snd_ak4xxx_ops {
|
||||||
|
|
||||||
#define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */
|
#define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */
|
||||||
|
|
||||||
|
/* DAC label and channels */
|
||||||
|
struct snd_akm4xxx_dac_channel {
|
||||||
|
char *name; /* mixer volume name */
|
||||||
|
unsigned int num_channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ADC labels and channels */
|
||||||
|
struct snd_akm4xxx_adc_channel {
|
||||||
|
char *name; /* capture gain volume label */
|
||||||
|
char *switch_name; /* capture switch */
|
||||||
|
unsigned int num_channels;
|
||||||
|
};
|
||||||
|
|
||||||
struct snd_akm4xxx {
|
struct snd_akm4xxx {
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
unsigned int num_adcs; /* AK4524 or AK4528 ADCs */
|
unsigned int num_adcs; /* AK4524 or AK4528 ADCs */
|
||||||
unsigned int num_dacs; /* AK4524 or AK4528 DACs */
|
unsigned int num_dacs; /* AK4524 or AK4528 DACs */
|
||||||
unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
|
unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
|
||||||
unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image
|
unsigned char volumes[AK4XXX_IMAGE_SIZE]; /* saved volume values */
|
||||||
* for IPGA (AK4528)
|
|
||||||
*/
|
|
||||||
unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */
|
unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */
|
||||||
void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */
|
void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */
|
||||||
/* template should fill the following fields */
|
/* template should fill the following fields */
|
||||||
unsigned int idx_offset; /* control index offset */
|
unsigned int idx_offset; /* control index offset */
|
||||||
enum {
|
enum {
|
||||||
SND_AK4524, SND_AK4528, SND_AK4529,
|
SND_AK4524, SND_AK4528, SND_AK4529,
|
||||||
SND_AK4355, SND_AK4358, SND_AK4381
|
SND_AK4355, SND_AK4358, SND_AK4381,
|
||||||
|
SND_AK5365
|
||||||
} type;
|
} type;
|
||||||
unsigned int *num_stereo; /* array of combined counts
|
|
||||||
* for the mixer
|
/* (array) information of combined codecs */
|
||||||
*/
|
struct snd_akm4xxx_dac_channel *dac_info;
|
||||||
char **channel_names; /* array of mixer channel names */
|
struct snd_akm4xxx_adc_channel *adc_info;
|
||||||
|
|
||||||
struct snd_ak4xxx_ops ops;
|
struct snd_ak4xxx_ops ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,9 +85,9 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak);
|
||||||
(ak)->images[(chip) * 16 + (reg)]
|
(ak)->images[(chip) * 16 + (reg)]
|
||||||
#define snd_akm4xxx_set(ak,chip,reg,val) \
|
#define snd_akm4xxx_set(ak,chip,reg,val) \
|
||||||
((ak)->images[(chip) * 16 + (reg)] = (val))
|
((ak)->images[(chip) * 16 + (reg)] = (val))
|
||||||
#define snd_akm4xxx_get_ipga(ak,chip,reg) \
|
#define snd_akm4xxx_get_vol(ak,chip,reg) \
|
||||||
(ak)->ipga_gain[chip][(reg)-4]
|
(ak)->volumes[(chip) * 16 + (reg)]
|
||||||
#define snd_akm4xxx_set_ipga(ak,chip,reg,val) \
|
#define snd_akm4xxx_set_vol(ak,chip,reg,val) \
|
||||||
((ak)->ipga_gain[chip][(reg)-4] = (val))
|
((ak)->volumes[(chip) * 16 + (reg)] = (val))
|
||||||
|
|
||||||
#endif /* __SOUND_AK4XXX_ADDA_H */
|
#endif /* __SOUND_AK4XXX_ADDA_H */
|
||||||
|
|
|
@ -688,7 +688,7 @@ struct snd_timer_tread {
|
||||||
* *
|
* *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3)
|
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
|
||||||
|
|
||||||
struct snd_ctl_card_info {
|
struct snd_ctl_card_info {
|
||||||
int card; /* card number */
|
int card; /* card number */
|
||||||
|
@ -727,10 +727,15 @@ typedef int __bitwise snd_ctl_elem_iface_t;
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
|
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
|
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
|
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<2) /* when was control changed */
|
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */
|
||||||
|
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */
|
||||||
|
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */
|
||||||
|
#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
|
||||||
|
#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */
|
#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */
|
#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */
|
#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */
|
||||||
|
#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* kernel use a TLV callback */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */
|
#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */
|
#define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */
|
||||||
#define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */
|
#define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */
|
||||||
|
@ -818,6 +823,12 @@ struct snd_ctl_elem_value {
|
||||||
unsigned char reserved[128-sizeof(struct timespec)];
|
unsigned char reserved[128-sizeof(struct timespec)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct snd_ctl_tlv {
|
||||||
|
unsigned int numid; /* control element numeric identification */
|
||||||
|
unsigned int length; /* in bytes aligned to 4 */
|
||||||
|
unsigned int tlv[0]; /* first TLV */
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
|
SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
|
||||||
SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
|
SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
|
||||||
|
@ -831,6 +842,9 @@ enum {
|
||||||
SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
|
SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
|
||||||
SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
|
SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
|
||||||
SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
|
SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
|
||||||
|
SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
|
||||||
|
SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
|
||||||
|
SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct snd_ctl_tlv),
|
||||||
SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
|
SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
|
||||||
SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
|
SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
|
||||||
SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
|
SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
|
||||||
|
@ -855,6 +869,7 @@ enum sndrv_ctl_event_type {
|
||||||
#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */
|
#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */
|
||||||
#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */
|
#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */
|
||||||
#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */
|
#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */
|
||||||
|
#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) /* element TLV tree was changed */
|
||||||
#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */
|
#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */
|
||||||
|
|
||||||
struct snd_ctl_event {
|
struct snd_ctl_event {
|
||||||
|
|
|
@ -30,6 +30,11 @@ struct snd_kcontrol;
|
||||||
typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
|
typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
|
||||||
typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
|
typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
|
||||||
typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
|
typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
|
||||||
|
typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
|
||||||
|
int op_flag, /* 0=read,1=write,-1=command */
|
||||||
|
unsigned int size,
|
||||||
|
unsigned int __user *tlv);
|
||||||
|
|
||||||
|
|
||||||
struct snd_kcontrol_new {
|
struct snd_kcontrol_new {
|
||||||
snd_ctl_elem_iface_t iface; /* interface identifier */
|
snd_ctl_elem_iface_t iface; /* interface identifier */
|
||||||
|
@ -42,6 +47,10 @@ struct snd_kcontrol_new {
|
||||||
snd_kcontrol_info_t *info;
|
snd_kcontrol_info_t *info;
|
||||||
snd_kcontrol_get_t *get;
|
snd_kcontrol_get_t *get;
|
||||||
snd_kcontrol_put_t *put;
|
snd_kcontrol_put_t *put;
|
||||||
|
union {
|
||||||
|
snd_kcontrol_tlv_rw_t *c;
|
||||||
|
unsigned int *p;
|
||||||
|
} tlv;
|
||||||
unsigned long private_value;
|
unsigned long private_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,6 +67,10 @@ struct snd_kcontrol {
|
||||||
snd_kcontrol_info_t *info;
|
snd_kcontrol_info_t *info;
|
||||||
snd_kcontrol_get_t *get;
|
snd_kcontrol_get_t *get;
|
||||||
snd_kcontrol_put_t *put;
|
snd_kcontrol_put_t *put;
|
||||||
|
union {
|
||||||
|
snd_kcontrol_tlv_rw_t *c;
|
||||||
|
unsigned int *p;
|
||||||
|
} tlv;
|
||||||
unsigned long private_value;
|
unsigned long private_value;
|
||||||
void *private_data;
|
void *private_data;
|
||||||
void (*private_free)(struct snd_kcontrol *kcontrol);
|
void (*private_free)(struct snd_kcontrol *kcontrol);
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
#include <linux/sched.h> /* wake_up() */
|
#include <linux/sched.h> /* wake_up() */
|
||||||
#include <linux/mutex.h> /* struct mutex */
|
#include <linux/mutex.h> /* struct mutex */
|
||||||
#include <linux/rwsem.h> /* struct rw_semaphore */
|
#include <linux/rwsem.h> /* struct rw_semaphore */
|
||||||
#include <linux/workqueue.h> /* struct workqueue_struct */
|
|
||||||
#include <linux/pm.h> /* pm_message_t */
|
#include <linux/pm.h> /* pm_message_t */
|
||||||
|
#include <linux/device.h>
|
||||||
|
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
|
@ -71,7 +71,6 @@ struct snd_device_ops {
|
||||||
int (*dev_free)(struct snd_device *dev);
|
int (*dev_free)(struct snd_device *dev);
|
||||||
int (*dev_register)(struct snd_device *dev);
|
int (*dev_register)(struct snd_device *dev);
|
||||||
int (*dev_disconnect)(struct snd_device *dev);
|
int (*dev_disconnect)(struct snd_device *dev);
|
||||||
int (*dev_unregister)(struct snd_device *dev);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snd_device {
|
struct snd_device {
|
||||||
|
@ -131,8 +130,8 @@ struct snd_card {
|
||||||
state */
|
state */
|
||||||
spinlock_t files_lock; /* lock the files for this card */
|
spinlock_t files_lock; /* lock the files for this card */
|
||||||
int shutdown; /* this card is going down */
|
int shutdown; /* this card is going down */
|
||||||
|
int free_on_last_close; /* free in context of file_release */
|
||||||
wait_queue_head_t shutdown_sleep;
|
wait_queue_head_t shutdown_sleep;
|
||||||
struct work_struct free_workq; /* for free in workqueue */
|
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
@ -188,6 +187,7 @@ struct snd_minor {
|
||||||
int device; /* device number */
|
int device; /* device number */
|
||||||
const struct file_operations *f_ops; /* file operations */
|
const struct file_operations *f_ops; /* file operations */
|
||||||
void *private_data; /* private data for f_ops->open */
|
void *private_data; /* private data for f_ops->open */
|
||||||
|
struct class_device *class_dev; /* class device for sysfs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* sound.c */
|
/* sound.c */
|
||||||
|
@ -202,6 +202,8 @@ int snd_register_device(int type, struct snd_card *card, int dev,
|
||||||
const char *name);
|
const char *name);
|
||||||
int snd_unregister_device(int type, struct snd_card *card, int dev);
|
int snd_unregister_device(int type, struct snd_card *card, int dev);
|
||||||
void *snd_lookup_minor_data(unsigned int minor, int type);
|
void *snd_lookup_minor_data(unsigned int minor, int type);
|
||||||
|
int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
|
||||||
|
const struct class_device_attribute *attr);
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
||||||
|
@ -244,7 +246,7 @@ struct snd_card *snd_card_new(int idx, const char *id,
|
||||||
struct module *module, int extra_size);
|
struct module *module, int extra_size);
|
||||||
int snd_card_disconnect(struct snd_card *card);
|
int snd_card_disconnect(struct snd_card *card);
|
||||||
int snd_card_free(struct snd_card *card);
|
int snd_card_free(struct snd_card *card);
|
||||||
int snd_card_free_in_thread(struct snd_card *card);
|
int snd_card_free_when_closed(struct snd_card *card);
|
||||||
int snd_card_register(struct snd_card *card);
|
int snd_card_register(struct snd_card *card);
|
||||||
int snd_card_info_init(void);
|
int snd_card_info_init(void);
|
||||||
int snd_card_info_done(void);
|
int snd_card_info_done(void);
|
||||||
|
|
|
@ -1524,6 +1524,10 @@ struct snd_emu10k1_fx8010_control_gpr {
|
||||||
unsigned int value[32]; /* initial values */
|
unsigned int value[32]; /* initial values */
|
||||||
unsigned int min; /* minimum range */
|
unsigned int min; /* minimum range */
|
||||||
unsigned int max; /* maximum range */
|
unsigned int max; /* maximum range */
|
||||||
|
union {
|
||||||
|
snd_kcontrol_tlv_rw_t *c;
|
||||||
|
unsigned int *p;
|
||||||
|
} tlv;
|
||||||
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,6 @@ struct snd_info_entry {
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
long size;
|
long size;
|
||||||
unsigned short content;
|
unsigned short content;
|
||||||
unsigned short disconnected: 1;
|
|
||||||
union {
|
union {
|
||||||
struct snd_info_entry_text text;
|
struct snd_info_entry_text text;
|
||||||
struct snd_info_entry_ops *ops;
|
struct snd_info_entry_ops *ops;
|
||||||
|
@ -83,6 +82,8 @@ struct snd_info_entry {
|
||||||
void (*private_free)(struct snd_info_entry *entry);
|
void (*private_free)(struct snd_info_entry *entry);
|
||||||
struct proc_dir_entry *p;
|
struct proc_dir_entry *p;
|
||||||
struct mutex access;
|
struct mutex access;
|
||||||
|
struct list_head children;
|
||||||
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
|
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
|
||||||
|
@ -122,8 +123,8 @@ int snd_info_restore_text(struct snd_info_entry * entry);
|
||||||
int snd_info_card_create(struct snd_card * card);
|
int snd_info_card_create(struct snd_card * card);
|
||||||
int snd_info_card_register(struct snd_card * card);
|
int snd_info_card_register(struct snd_card * card);
|
||||||
int snd_info_card_free(struct snd_card * card);
|
int snd_info_card_free(struct snd_card * card);
|
||||||
|
void snd_info_card_disconnect(struct snd_card * card);
|
||||||
int snd_info_register(struct snd_info_entry * entry);
|
int snd_info_register(struct snd_info_entry * entry);
|
||||||
int snd_info_unregister(struct snd_info_entry * entry);
|
|
||||||
|
|
||||||
/* for card drivers */
|
/* for card drivers */
|
||||||
int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp);
|
int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp);
|
||||||
|
@ -156,8 +157,8 @@ static inline void snd_info_free_entry(struct snd_info_entry * entry) { ; }
|
||||||
static inline int snd_info_card_create(struct snd_card * card) { return 0; }
|
static inline int snd_info_card_create(struct snd_card * card) { return 0; }
|
||||||
static inline int snd_info_card_register(struct snd_card * card) { return 0; }
|
static inline int snd_info_card_register(struct snd_card * card) { return 0; }
|
||||||
static inline int snd_info_card_free(struct snd_card * card) { return 0; }
|
static inline int snd_info_card_free(struct snd_card * card) { return 0; }
|
||||||
|
static inline void snd_info_card_disconnect(struct snd_card * card) { }
|
||||||
static inline int snd_info_register(struct snd_info_entry * entry) { return 0; }
|
static inline int snd_info_register(struct snd_info_entry * entry) { return 0; }
|
||||||
static inline int snd_info_unregister(struct snd_info_entry * entry) { return 0; }
|
|
||||||
|
|
||||||
static inline int snd_card_proc_new(struct snd_card *card, const char *name,
|
static inline int snd_card_proc_new(struct snd_card *card, const char *name,
|
||||||
struct snd_info_entry **entryp) { return -EINVAL; }
|
struct snd_info_entry **entryp) { return -EINVAL; }
|
||||||
|
|
|
@ -190,7 +190,7 @@ struct snd_pcm_ops {
|
||||||
|
|
||||||
struct snd_pcm_file {
|
struct snd_pcm_file {
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
struct snd_pcm_file *next;
|
int no_compat_mmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snd_pcm_hw_rule;
|
struct snd_pcm_hw_rule;
|
||||||
|
@ -384,7 +384,6 @@ struct snd_pcm_substream {
|
||||||
struct snd_info_entry *proc_prealloc_entry;
|
struct snd_info_entry *proc_prealloc_entry;
|
||||||
#endif
|
#endif
|
||||||
/* misc flags */
|
/* misc flags */
|
||||||
unsigned int no_mmap_ctrl: 1;
|
|
||||||
unsigned int hw_opened: 1;
|
unsigned int hw_opened: 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -402,7 +401,6 @@ struct snd_pcm_str {
|
||||||
/* -- OSS things -- */
|
/* -- OSS things -- */
|
||||||
struct snd_pcm_oss_stream oss;
|
struct snd_pcm_oss_stream oss;
|
||||||
#endif
|
#endif
|
||||||
struct snd_pcm_file *files;
|
|
||||||
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
||||||
struct snd_info_entry *proc_root;
|
struct snd_info_entry *proc_root;
|
||||||
struct snd_info_entry *proc_info_entry;
|
struct snd_info_entry *proc_info_entry;
|
||||||
|
|
|
@ -129,7 +129,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
|
||||||
int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
|
int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
|
||||||
int snd_timer_global_free(struct snd_timer *timer);
|
int snd_timer_global_free(struct snd_timer *timer);
|
||||||
int snd_timer_global_register(struct snd_timer *timer);
|
int snd_timer_global_register(struct snd_timer *timer);
|
||||||
int snd_timer_global_unregister(struct snd_timer *timer);
|
|
||||||
|
|
||||||
int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id);
|
int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id);
|
||||||
int snd_timer_close(struct snd_timer_instance *timeri);
|
int snd_timer_close(struct snd_timer_instance *timeri);
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef __SOUND_TLV_H
|
||||||
|
#define __SOUND_TLV_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Advanced Linux Sound Architecture - ALSA - Driver
|
||||||
|
* Copyright (c) 2006 by Jaroslav Kysela <perex@suse.cz>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TLV structure is right behind the struct snd_ctl_tlv:
|
||||||
|
* unsigned int type - see SNDRV_CTL_TLVT_*
|
||||||
|
* unsigned int length
|
||||||
|
* .... data aligned to sizeof(unsigned int), use
|
||||||
|
* block_length = (length + (sizeof(unsigned int) - 1)) &
|
||||||
|
* ~(sizeof(unsigned int) - 1)) ....
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
|
||||||
|
#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
|
||||||
|
#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
|
||||||
|
#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
|
||||||
|
|
||||||
|
#define TLV_DB_SCALE_ITEM(min, step, mute) \
|
||||||
|
SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
|
||||||
|
(min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
|
||||||
|
#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
|
||||||
|
unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
|
||||||
|
|
||||||
|
/* linear volume between min_dB and max_dB (.01dB unit) */
|
||||||
|
#define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \
|
||||||
|
SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
|
||||||
|
(min_dB), (max_dB)
|
||||||
|
#define DECLARE_TLV_DB_LINEAR(name, min_dB, max_dB) \
|
||||||
|
unsigned int name[] = { TLV_DB_LINEAR_ITEM(min_dB, max_dB) }
|
||||||
|
|
||||||
|
/* dB range container */
|
||||||
|
/* Each item is: <min> <max> <TLV> */
|
||||||
|
/* The below assumes that each item TLV is 4 words like DB_SCALE or LINEAR */
|
||||||
|
#define TLV_DB_RANGE_HEAD(num) \
|
||||||
|
SNDRV_CTL_TLVT_DB_RANGE, 6 * (num) * sizeof(unsigned int)
|
||||||
|
|
||||||
|
#define TLV_DB_GAIN_MUTE -9999999
|
||||||
|
|
||||||
|
#endif /* __SOUND_TLV_H */
|
|
@ -128,6 +128,7 @@ struct snd_vx_hardware {
|
||||||
unsigned int num_ins;
|
unsigned int num_ins;
|
||||||
unsigned int num_outs;
|
unsigned int num_outs;
|
||||||
unsigned int output_level_max;
|
unsigned int output_level_max;
|
||||||
|
unsigned int *output_level_db_scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* hwdep id string */
|
/* hwdep id string */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
config SND_AOA_ONYX
|
config SND_AOA_ONYX
|
||||||
tristate "support Onyx chip"
|
tristate "support Onyx chip"
|
||||||
depends on SND_AOA
|
depends on SND_AOA
|
||||||
|
select I2C
|
||||||
|
select I2C_POWERMAC
|
||||||
---help---
|
---help---
|
||||||
This option enables support for the Onyx (pcm3052)
|
This option enables support for the Onyx (pcm3052)
|
||||||
codec chip found in the latest Apple machines
|
codec chip found in the latest Apple machines
|
||||||
|
@ -18,6 +20,8 @@ config SND_AOA_ONYX
|
||||||
config SND_AOA_TAS
|
config SND_AOA_TAS
|
||||||
tristate "support TAS chips"
|
tristate "support TAS chips"
|
||||||
depends on SND_AOA
|
depends on SND_AOA
|
||||||
|
select I2C
|
||||||
|
select I2C_POWERMAC
|
||||||
---help---
|
---help---
|
||||||
This option enables support for the tas chips
|
This option enables support for the tas chips
|
||||||
found in a lot of Apple Machines, especially
|
found in a lot of Apple Machines, especially
|
||||||
|
|
|
@ -66,6 +66,8 @@
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
|
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("tas codec driver for snd-aoa");
|
MODULE_DESCRIPTION("tas codec driver for snd-aoa");
|
||||||
|
@ -91,6 +93,10 @@ struct tas {
|
||||||
u8 bass, treble;
|
u8 bass, treble;
|
||||||
u8 acr;
|
u8 acr;
|
||||||
int drc_range;
|
int drc_range;
|
||||||
|
/* protects hardware access against concurrency from
|
||||||
|
* userspace when hitting controls and during
|
||||||
|
* codec init/suspend/resume */
|
||||||
|
struct mutex mtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tas_reset_init(struct tas *tas);
|
static int tas_reset_init(struct tas *tas);
|
||||||
|
@ -231,8 +237,10 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = tas->cached_volume_l;
|
ucontrol->value.integer.value[0] = tas->cached_volume_l;
|
||||||
ucontrol->value.integer.value[1] = tas->cached_volume_r;
|
ucontrol->value.integer.value[1] = tas->cached_volume_r;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,14 +249,18 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
if (tas->cached_volume_l == ucontrol->value.integer.value[0]
|
if (tas->cached_volume_l == ucontrol->value.integer.value[0]
|
||||||
&& tas->cached_volume_r == ucontrol->value.integer.value[1])
|
&& tas->cached_volume_r == ucontrol->value.integer.value[1]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->cached_volume_l = ucontrol->value.integer.value[0];
|
tas->cached_volume_l = ucontrol->value.integer.value[0];
|
||||||
tas->cached_volume_r = ucontrol->value.integer.value[1];
|
tas->cached_volume_r = ucontrol->value.integer.value[1];
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas_set_volume(tas);
|
tas_set_volume(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,8 +288,10 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = !tas->mute_l;
|
ucontrol->value.integer.value[0] = !tas->mute_l;
|
||||||
ucontrol->value.integer.value[1] = !tas->mute_r;
|
ucontrol->value.integer.value[1] = !tas->mute_r;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,14 +300,18 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
if (tas->mute_l == !ucontrol->value.integer.value[0]
|
if (tas->mute_l == !ucontrol->value.integer.value[0]
|
||||||
&& tas->mute_r == !ucontrol->value.integer.value[1])
|
&& tas->mute_r == !ucontrol->value.integer.value[1]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->mute_l = !ucontrol->value.integer.value[0];
|
tas->mute_l = !ucontrol->value.integer.value[0];
|
||||||
tas->mute_r = !ucontrol->value.integer.value[1];
|
tas->mute_r = !ucontrol->value.integer.value[1];
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas_set_volume(tas);
|
tas_set_volume(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,8 +340,10 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
int idx = kcontrol->private_value;
|
int idx = kcontrol->private_value;
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = tas->mixer_l[idx];
|
ucontrol->value.integer.value[0] = tas->mixer_l[idx];
|
||||||
ucontrol->value.integer.value[1] = tas->mixer_r[idx];
|
ucontrol->value.integer.value[1] = tas->mixer_r[idx];
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -334,15 +354,19 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
int idx = kcontrol->private_value;
|
int idx = kcontrol->private_value;
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
|
if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
|
||||||
&& tas->mixer_r[idx] == ucontrol->value.integer.value[1])
|
&& tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->mixer_l[idx] = ucontrol->value.integer.value[0];
|
tas->mixer_l[idx] = ucontrol->value.integer.value[0];
|
||||||
tas->mixer_r[idx] = ucontrol->value.integer.value[1];
|
tas->mixer_r[idx] = ucontrol->value.integer.value[1];
|
||||||
|
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas_set_mixer(tas);
|
tas_set_mixer(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +399,9 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = tas->drc_range;
|
ucontrol->value.integer.value[0] = tas->drc_range;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,12 +410,16 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
if (tas->drc_range == ucontrol->value.integer.value[0])
|
mutex_lock(&tas->mtx);
|
||||||
|
if (tas->drc_range == ucontrol->value.integer.value[0]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->drc_range = ucontrol->value.integer.value[0];
|
tas->drc_range = ucontrol->value.integer.value[0];
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas3004_set_drc(tas);
|
tas3004_set_drc(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +447,9 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = tas->drc_enabled;
|
ucontrol->value.integer.value[0] = tas->drc_enabled;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,12 +458,16 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
if (tas->drc_enabled == ucontrol->value.integer.value[0])
|
mutex_lock(&tas->mtx);
|
||||||
|
if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->drc_enabled = ucontrol->value.integer.value[0];
|
tas->drc_enabled = ucontrol->value.integer.value[0];
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas3004_set_drc(tas);
|
tas3004_set_drc(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,7 +499,9 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
|
ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,15 +509,21 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
int oldacr = tas->acr;
|
int oldacr;
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
|
oldacr = tas->acr;
|
||||||
|
|
||||||
tas->acr &= ~TAS_ACR_INPUT_B;
|
tas->acr &= ~TAS_ACR_INPUT_B;
|
||||||
if (ucontrol->value.enumerated.item[0])
|
if (ucontrol->value.enumerated.item[0])
|
||||||
tas->acr |= TAS_ACR_INPUT_B;
|
tas->acr |= TAS_ACR_INPUT_B;
|
||||||
if (oldacr == tas->acr)
|
if (oldacr == tas->acr) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
|
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +562,9 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = tas->treble;
|
ucontrol->value.integer.value[0] = tas->treble;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,12 +573,16 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
if (tas->treble == ucontrol->value.integer.value[0])
|
mutex_lock(&tas->mtx);
|
||||||
|
if (tas->treble == ucontrol->value.integer.value[0]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->treble = ucontrol->value.integer.value[0];
|
tas->treble = ucontrol->value.integer.value[0];
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas_set_treble(tas);
|
tas_set_treble(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +610,9 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
ucontrol->value.integer.value[0] = tas->bass;
|
ucontrol->value.integer.value[0] = tas->bass;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,12 +621,16 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
struct tas *tas = snd_kcontrol_chip(kcontrol);
|
||||||
|
|
||||||
if (tas->bass == ucontrol->value.integer.value[0])
|
mutex_lock(&tas->mtx);
|
||||||
|
if (tas->bass == ucontrol->value.integer.value[0]) {
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tas->bass = ucontrol->value.integer.value[0];
|
tas->bass = ucontrol->value.integer.value[0];
|
||||||
if (tas->hw_enabled)
|
if (tas->hw_enabled)
|
||||||
tas_set_bass(tas);
|
tas_set_bass(tas);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,16 +684,16 @@ static int tas_reset_init(struct tas *tas)
|
||||||
|
|
||||||
tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
|
tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
|
||||||
if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
|
if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
|
||||||
return -ENODEV;
|
goto outerr;
|
||||||
|
|
||||||
tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL |
|
tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL |
|
||||||
TAS_ACR_B_MON_SEL_RIGHT;
|
TAS_ACR_B_MON_SEL_RIGHT;
|
||||||
if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
|
if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
|
||||||
return -ENODEV;
|
goto outerr;
|
||||||
|
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
|
if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
|
||||||
return -ENODEV;
|
goto outerr;
|
||||||
|
|
||||||
tas3004_set_drc(tas);
|
tas3004_set_drc(tas);
|
||||||
|
|
||||||
|
@ -649,9 +705,11 @@ static int tas_reset_init(struct tas *tas)
|
||||||
|
|
||||||
tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
|
tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
|
||||||
if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
|
if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
|
||||||
return -ENODEV;
|
goto outerr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
outerr:
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock)
|
static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock)
|
||||||
|
@ -666,11 +724,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
|
||||||
break;
|
break;
|
||||||
case CLOCK_SWITCH_SLAVE:
|
case CLOCK_SWITCH_SLAVE:
|
||||||
/* Clocks are back, re-init the codec */
|
/* Clocks are back, re-init the codec */
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
tas_reset_init(tas);
|
tas_reset_init(tas);
|
||||||
tas_set_volume(tas);
|
tas_set_volume(tas);
|
||||||
tas_set_mixer(tas);
|
tas_set_mixer(tas);
|
||||||
tas->hw_enabled = 1;
|
tas->hw_enabled = 1;
|
||||||
tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
|
tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* doesn't happen as of now */
|
/* doesn't happen as of now */
|
||||||
|
@ -684,19 +744,23 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
|
||||||
* our i2c device is suspended, and then take note of that! */
|
* our i2c device is suspended, and then take note of that! */
|
||||||
static int tas_suspend(struct tas *tas)
|
static int tas_suspend(struct tas *tas)
|
||||||
{
|
{
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
tas->hw_enabled = 0;
|
tas->hw_enabled = 0;
|
||||||
tas->acr |= TAS_ACR_ANALOG_PDOWN;
|
tas->acr |= TAS_ACR_ANALOG_PDOWN;
|
||||||
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
|
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tas_resume(struct tas *tas)
|
static int tas_resume(struct tas *tas)
|
||||||
{
|
{
|
||||||
/* reset codec */
|
/* reset codec */
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
tas_reset_init(tas);
|
tas_reset_init(tas);
|
||||||
tas_set_volume(tas);
|
tas_set_volume(tas);
|
||||||
tas_set_mixer(tas);
|
tas_set_mixer(tas);
|
||||||
tas->hw_enabled = 1;
|
tas->hw_enabled = 1;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,11 +803,14 @@ static int tas_init_codec(struct aoa_codec *codec)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&tas->mtx);
|
||||||
if (tas_reset_init(tas)) {
|
if (tas_reset_init(tas)) {
|
||||||
printk(KERN_ERR PFX "tas failed to initialise\n");
|
printk(KERN_ERR PFX "tas failed to initialise\n");
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
tas->hw_enabled = 1;
|
tas->hw_enabled = 1;
|
||||||
|
mutex_unlock(&tas->mtx);
|
||||||
|
|
||||||
if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
|
if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
|
||||||
aoa_get_card(),
|
aoa_get_card(),
|
||||||
|
@ -822,6 +889,7 @@ static int tas_create(struct i2c_adapter *adapter,
|
||||||
if (!tas)
|
if (!tas)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mutex_init(&tas->mtx);
|
||||||
tas->i2c.driver = &tas_driver;
|
tas->i2c.driver = &tas_driver;
|
||||||
tas->i2c.adapter = adapter;
|
tas->i2c.adapter = adapter;
|
||||||
tas->i2c.addr = addr;
|
tas->i2c.addr = addr;
|
||||||
|
@ -850,6 +918,7 @@ static int tas_create(struct i2c_adapter *adapter,
|
||||||
detach:
|
detach:
|
||||||
i2c_detach_client(&tas->i2c);
|
i2c_detach_client(&tas->i2c);
|
||||||
fail:
|
fail:
|
||||||
|
mutex_destroy(&tas->mtx);
|
||||||
kfree(tas);
|
kfree(tas);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -908,6 +977,7 @@ static int tas_i2c_detach(struct i2c_client *client)
|
||||||
/* power down codec chip */
|
/* power down codec chip */
|
||||||
tas_write_reg(tas, TAS_REG_ACR, 1, &tmp);
|
tas_write_reg(tas, TAS_REG_ACR, 1, &tmp);
|
||||||
|
|
||||||
|
mutex_destroy(&tas->mtx);
|
||||||
kfree(tas);
|
kfree(tas);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
||||||
init_waitqueue_head(&ctl->change_sleep);
|
init_waitqueue_head(&ctl->change_sleep);
|
||||||
spin_lock_init(&ctl->read_lock);
|
spin_lock_init(&ctl->read_lock);
|
||||||
ctl->card = card;
|
ctl->card = card;
|
||||||
|
ctl->prefer_pcm_subdevice = -1;
|
||||||
|
ctl->prefer_rawmidi_subdevice = -1;
|
||||||
ctl->pid = current->pid;
|
ctl->pid = current->pid;
|
||||||
file->private_data = ctl;
|
file->private_data = ctl;
|
||||||
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||||||
|
@ -236,11 +238,16 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
|
||||||
kctl.id.index = ncontrol->index;
|
kctl.id.index = ncontrol->index;
|
||||||
kctl.count = ncontrol->count ? ncontrol->count : 1;
|
kctl.count = ncontrol->count ? ncontrol->count : 1;
|
||||||
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
||||||
(ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|
|
(ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
|
||||||
SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));
|
SNDRV_CTL_ELEM_ACCESS_INACTIVE|
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_DINDIRECT|
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_INDIRECT|
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
|
||||||
kctl.info = ncontrol->info;
|
kctl.info = ncontrol->info;
|
||||||
kctl.get = ncontrol->get;
|
kctl.get = ncontrol->get;
|
||||||
kctl.put = ncontrol->put;
|
kctl.put = ncontrol->put;
|
||||||
|
kctl.tlv.p = ncontrol->tlv.p;
|
||||||
kctl.private_value = ncontrol->private_value;
|
kctl.private_value = ncontrol->private_value;
|
||||||
kctl.private_data = private_data;
|
kctl.private_data = private_data;
|
||||||
return snd_ctl_new(&kctl, access);
|
return snd_ctl_new(&kctl, access);
|
||||||
|
@ -882,6 +889,8 @@ struct user_element {
|
||||||
struct snd_ctl_elem_info info;
|
struct snd_ctl_elem_info info;
|
||||||
void *elem_data; /* element data */
|
void *elem_data; /* element data */
|
||||||
unsigned long elem_data_size; /* size of element data in bytes */
|
unsigned long elem_data_size; /* size of element data in bytes */
|
||||||
|
void *tlv_data; /* TLV data */
|
||||||
|
unsigned long tlv_data_size; /* TLV data size */
|
||||||
void *priv_data; /* private data (like strings for enumerated type) */
|
void *priv_data; /* private data (like strings for enumerated type) */
|
||||||
unsigned long priv_data_size; /* size of private data in bytes */
|
unsigned long priv_data_size; /* size of private data in bytes */
|
||||||
};
|
};
|
||||||
|
@ -916,9 +925,48 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
|
||||||
|
int op_flag,
|
||||||
|
unsigned int size,
|
||||||
|
unsigned int __user *tlv)
|
||||||
|
{
|
||||||
|
struct user_element *ue = kcontrol->private_data;
|
||||||
|
int change = 0;
|
||||||
|
void *new_data;
|
||||||
|
|
||||||
|
if (op_flag > 0) {
|
||||||
|
if (size > 1024 * 128) /* sane value */
|
||||||
|
return -EINVAL;
|
||||||
|
new_data = kmalloc(size, GFP_KERNEL);
|
||||||
|
if (new_data == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
if (copy_from_user(new_data, tlv, size)) {
|
||||||
|
kfree(new_data);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
change = ue->tlv_data_size != size;
|
||||||
|
if (!change)
|
||||||
|
change = memcmp(ue->tlv_data, new_data, size);
|
||||||
|
kfree(ue->tlv_data);
|
||||||
|
ue->tlv_data = new_data;
|
||||||
|
ue->tlv_data_size = size;
|
||||||
|
} else {
|
||||||
|
if (! ue->tlv_data_size || ! ue->tlv_data)
|
||||||
|
return -ENXIO;
|
||||||
|
if (size < ue->tlv_data_size)
|
||||||
|
return -ENOSPC;
|
||||||
|
if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
|
static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
|
||||||
{
|
{
|
||||||
kfree(kcontrol->private_data);
|
struct user_element *ue = kcontrol->private_data;
|
||||||
|
if (ue->tlv_data)
|
||||||
|
kfree(ue->tlv_data);
|
||||||
|
kfree(ue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
|
@ -937,7 +985,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
||||||
(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
|
(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
|
||||||
SNDRV_CTL_ELEM_ACCESS_INACTIVE));
|
SNDRV_CTL_ELEM_ACCESS_INACTIVE|
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
|
||||||
info->id.numid = 0;
|
info->id.numid = 0;
|
||||||
memset(&kctl, 0, sizeof(kctl));
|
memset(&kctl, 0, sizeof(kctl));
|
||||||
down_write(&card->controls_rwsem);
|
down_write(&card->controls_rwsem);
|
||||||
|
@ -963,6 +1012,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
kctl.get = snd_ctl_elem_user_get;
|
kctl.get = snd_ctl_elem_user_get;
|
||||||
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
|
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
|
||||||
kctl.put = snd_ctl_elem_user_put;
|
kctl.put = snd_ctl_elem_user_put;
|
||||||
|
if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
|
||||||
|
kctl.tlv.c = snd_ctl_elem_user_tlv;
|
||||||
|
access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
|
||||||
|
}
|
||||||
switch (info->type) {
|
switch (info->type) {
|
||||||
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
|
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
|
||||||
private_size = sizeof(char);
|
private_size = sizeof(char);
|
||||||
|
@ -997,6 +1050,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||||
if (ue == NULL)
|
if (ue == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
ue->info = *info;
|
ue->info = *info;
|
||||||
|
ue->info.access = 0;
|
||||||
ue->elem_data = (char *)ue + sizeof(*ue);
|
ue->elem_data = (char *)ue + sizeof(*ue);
|
||||||
ue->elem_data_size = private_size;
|
ue->elem_data_size = private_size;
|
||||||
kctl.private_free = snd_ctl_elem_user_free;
|
kctl.private_free = snd_ctl_elem_user_free;
|
||||||
|
@ -1067,6 +1121,67 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||||
|
struct snd_ctl_tlv __user *_tlv,
|
||||||
|
int op_flag)
|
||||||
|
{
|
||||||
|
struct snd_card *card = file->card;
|
||||||
|
struct snd_ctl_tlv tlv;
|
||||||
|
struct snd_kcontrol *kctl;
|
||||||
|
struct snd_kcontrol_volatile *vd;
|
||||||
|
unsigned int len;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
|
||||||
|
return -EFAULT;
|
||||||
|
if (tlv.length < sizeof(unsigned int) * 3)
|
||||||
|
return -EINVAL;
|
||||||
|
down_read(&card->controls_rwsem);
|
||||||
|
kctl = snd_ctl_find_numid(card, tlv.numid);
|
||||||
|
if (kctl == NULL) {
|
||||||
|
err = -ENOENT;
|
||||||
|
goto __kctl_end;
|
||||||
|
}
|
||||||
|
if (kctl->tlv.p == NULL) {
|
||||||
|
err = -ENXIO;
|
||||||
|
goto __kctl_end;
|
||||||
|
}
|
||||||
|
vd = &kctl->vd[tlv.numid - kctl->id.numid];
|
||||||
|
if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
|
||||||
|
(op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
|
||||||
|
(op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
|
||||||
|
err = -ENXIO;
|
||||||
|
goto __kctl_end;
|
||||||
|
}
|
||||||
|
if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
|
||||||
|
if (file && vd->owner != NULL && vd->owner != file) {
|
||||||
|
err = -EPERM;
|
||||||
|
goto __kctl_end;
|
||||||
|
}
|
||||||
|
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
||||||
|
if (err > 0) {
|
||||||
|
up_read(&card->controls_rwsem);
|
||||||
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (op_flag) {
|
||||||
|
err = -ENXIO;
|
||||||
|
goto __kctl_end;
|
||||||
|
}
|
||||||
|
len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
|
||||||
|
if (tlv.length < len) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto __kctl_end;
|
||||||
|
}
|
||||||
|
if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
|
||||||
|
err = -EFAULT;
|
||||||
|
}
|
||||||
|
__kctl_end:
|
||||||
|
up_read(&card->controls_rwsem);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct snd_ctl_file *ctl;
|
struct snd_ctl_file *ctl;
|
||||||
|
@ -1086,11 +1201,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
||||||
case SNDRV_CTL_IOCTL_CARD_INFO:
|
case SNDRV_CTL_IOCTL_CARD_INFO:
|
||||||
return snd_ctl_card_info(card, ctl, cmd, argp);
|
return snd_ctl_card_info(card, ctl, cmd, argp);
|
||||||
case SNDRV_CTL_IOCTL_ELEM_LIST:
|
case SNDRV_CTL_IOCTL_ELEM_LIST:
|
||||||
return snd_ctl_elem_list(ctl->card, argp);
|
return snd_ctl_elem_list(card, argp);
|
||||||
case SNDRV_CTL_IOCTL_ELEM_INFO:
|
case SNDRV_CTL_IOCTL_ELEM_INFO:
|
||||||
return snd_ctl_elem_info_user(ctl, argp);
|
return snd_ctl_elem_info_user(ctl, argp);
|
||||||
case SNDRV_CTL_IOCTL_ELEM_READ:
|
case SNDRV_CTL_IOCTL_ELEM_READ:
|
||||||
return snd_ctl_elem_read_user(ctl->card, argp);
|
return snd_ctl_elem_read_user(card, argp);
|
||||||
case SNDRV_CTL_IOCTL_ELEM_WRITE:
|
case SNDRV_CTL_IOCTL_ELEM_WRITE:
|
||||||
return snd_ctl_elem_write_user(ctl, argp);
|
return snd_ctl_elem_write_user(ctl, argp);
|
||||||
case SNDRV_CTL_IOCTL_ELEM_LOCK:
|
case SNDRV_CTL_IOCTL_ELEM_LOCK:
|
||||||
|
@ -1105,6 +1220,12 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
||||||
return snd_ctl_elem_remove(ctl, argp);
|
return snd_ctl_elem_remove(ctl, argp);
|
||||||
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
|
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
|
||||||
return snd_ctl_subscribe_events(ctl, ip);
|
return snd_ctl_subscribe_events(ctl, ip);
|
||||||
|
case SNDRV_CTL_IOCTL_TLV_READ:
|
||||||
|
return snd_ctl_tlv_ioctl(ctl, argp, 0);
|
||||||
|
case SNDRV_CTL_IOCTL_TLV_WRITE:
|
||||||
|
return snd_ctl_tlv_ioctl(ctl, argp, 1);
|
||||||
|
case SNDRV_CTL_IOCTL_TLV_COMMAND:
|
||||||
|
return snd_ctl_tlv_ioctl(ctl, argp, -1);
|
||||||
case SNDRV_CTL_IOCTL_POWER:
|
case SNDRV_CTL_IOCTL_POWER:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
case SNDRV_CTL_IOCTL_POWER_STATE:
|
case SNDRV_CTL_IOCTL_POWER_STATE:
|
||||||
|
@ -1338,6 +1459,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
|
||||||
struct snd_card *card = device->device_data;
|
struct snd_card *card = device->device_data;
|
||||||
struct list_head *flist;
|
struct list_head *flist;
|
||||||
struct snd_ctl_file *ctl;
|
struct snd_ctl_file *ctl;
|
||||||
|
int err, cardnum;
|
||||||
|
|
||||||
|
snd_assert(card != NULL, return -ENXIO);
|
||||||
|
cardnum = card->number;
|
||||||
|
snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
|
||||||
|
|
||||||
down_read(&card->controls_rwsem);
|
down_read(&card->controls_rwsem);
|
||||||
list_for_each(flist, &card->ctl_files) {
|
list_for_each(flist, &card->ctl_files) {
|
||||||
|
@ -1346,6 +1472,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
|
||||||
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
|
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
|
||||||
}
|
}
|
||||||
up_read(&card->controls_rwsem);
|
up_read(&card->controls_rwsem);
|
||||||
|
|
||||||
|
if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
|
||||||
|
card, -1)) < 0)
|
||||||
|
return err;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1366,23 +1496,6 @@ static int snd_ctl_dev_free(struct snd_device *device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* de-registration of the control device
|
|
||||||
*/
|
|
||||||
static int snd_ctl_dev_unregister(struct snd_device *device)
|
|
||||||
{
|
|
||||||
struct snd_card *card = device->device_data;
|
|
||||||
int err, cardnum;
|
|
||||||
|
|
||||||
snd_assert(card != NULL, return -ENXIO);
|
|
||||||
cardnum = card->number;
|
|
||||||
snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
|
|
||||||
if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
|
|
||||||
card, -1)) < 0)
|
|
||||||
return err;
|
|
||||||
return snd_ctl_dev_free(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create control core:
|
* create control core:
|
||||||
* called from init.c
|
* called from init.c
|
||||||
|
@ -1393,7 +1506,6 @@ int snd_ctl_create(struct snd_card *card)
|
||||||
.dev_free = snd_ctl_dev_free,
|
.dev_free = snd_ctl_dev_free,
|
||||||
.dev_register = snd_ctl_dev_register,
|
.dev_register = snd_ctl_dev_register,
|
||||||
.dev_disconnect = snd_ctl_dev_disconnect,
|
.dev_disconnect = snd_ctl_dev_disconnect,
|
||||||
.dev_unregister = snd_ctl_dev_unregister
|
|
||||||
};
|
};
|
||||||
|
|
||||||
snd_assert(card != NULL, return -ENXIO);
|
snd_assert(card != NULL, return -ENXIO);
|
||||||
|
|
|
@ -407,6 +407,10 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
|
||||||
case SNDRV_CTL_IOCTL_POWER_STATE:
|
case SNDRV_CTL_IOCTL_POWER_STATE:
|
||||||
case SNDRV_CTL_IOCTL_ELEM_LOCK:
|
case SNDRV_CTL_IOCTL_ELEM_LOCK:
|
||||||
case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
|
case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
|
||||||
|
case SNDRV_CTL_IOCTL_ELEM_REMOVE:
|
||||||
|
case SNDRV_CTL_IOCTL_TLV_READ:
|
||||||
|
case SNDRV_CTL_IOCTL_TLV_WRITE:
|
||||||
|
case SNDRV_CTL_IOCTL_TLV_COMMAND:
|
||||||
return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
|
return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
|
||||||
case SNDRV_CTL_IOCTL_ELEM_LIST32:
|
case SNDRV_CTL_IOCTL_ELEM_LIST32:
|
||||||
return snd_ctl_elem_list_compat(ctl->card, argp);
|
return snd_ctl_elem_list_compat(ctl->card, argp);
|
||||||
|
|
|
@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new);
|
||||||
* @device_data: the data pointer to release
|
* @device_data: the data pointer to release
|
||||||
*
|
*
|
||||||
* Removes the device from the list on the card and invokes the
|
* Removes the device from the list on the card and invokes the
|
||||||
* callback, dev_unregister or dev_free, corresponding to the state.
|
* callbacks, dev_disconnect and dev_free, corresponding to the state.
|
||||||
* Then release the device.
|
* Then release the device.
|
||||||
*
|
*
|
||||||
* Returns zero if successful, or a negative error code on failure or if the
|
* Returns zero if successful, or a negative error code on failure or if the
|
||||||
|
@ -90,17 +90,15 @@ int snd_device_free(struct snd_card *card, void *device_data)
|
||||||
continue;
|
continue;
|
||||||
/* unlink */
|
/* unlink */
|
||||||
list_del(&dev->list);
|
list_del(&dev->list);
|
||||||
if ((dev->state == SNDRV_DEV_REGISTERED ||
|
if (dev->state == SNDRV_DEV_REGISTERED &&
|
||||||
dev->state == SNDRV_DEV_DISCONNECTED) &&
|
dev->ops->dev_disconnect)
|
||||||
dev->ops->dev_unregister) {
|
if (dev->ops->dev_disconnect(dev))
|
||||||
if (dev->ops->dev_unregister(dev))
|
snd_printk(KERN_ERR
|
||||||
snd_printk(KERN_ERR "device unregister failure\n");
|
"device disconnect failure\n");
|
||||||
} else {
|
|
||||||
if (dev->ops->dev_free) {
|
if (dev->ops->dev_free) {
|
||||||
if (dev->ops->dev_free(dev))
|
if (dev->ops->dev_free(dev))
|
||||||
snd_printk(KERN_ERR "device free failure\n");
|
snd_printk(KERN_ERR "device free failure\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex);
|
||||||
static int snd_hwdep_free(struct snd_hwdep *hwdep);
|
static int snd_hwdep_free(struct snd_hwdep *hwdep);
|
||||||
static int snd_hwdep_dev_free(struct snd_device *device);
|
static int snd_hwdep_dev_free(struct snd_device *device);
|
||||||
static int snd_hwdep_dev_register(struct snd_device *device);
|
static int snd_hwdep_dev_register(struct snd_device *device);
|
||||||
static int snd_hwdep_dev_unregister(struct snd_device *device);
|
static int snd_hwdep_dev_disconnect(struct snd_device *device);
|
||||||
|
|
||||||
|
|
||||||
static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
|
static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
|
||||||
|
@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
|
||||||
static struct snd_device_ops ops = {
|
static struct snd_device_ops ops = {
|
||||||
.dev_free = snd_hwdep_dev_free,
|
.dev_free = snd_hwdep_dev_free,
|
||||||
.dev_register = snd_hwdep_dev_register,
|
.dev_register = snd_hwdep_dev_register,
|
||||||
.dev_unregister = snd_hwdep_dev_unregister
|
.dev_disconnect = snd_hwdep_dev_disconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
snd_assert(rhwdep != NULL, return -EINVAL);
|
snd_assert(rhwdep != NULL, return -EINVAL);
|
||||||
|
@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_hwdep_dev_unregister(struct snd_device *device)
|
static int snd_hwdep_dev_disconnect(struct snd_device *device)
|
||||||
{
|
{
|
||||||
struct snd_hwdep *hwdep = device->device_data;
|
struct snd_hwdep *hwdep = device->device_data;
|
||||||
|
|
||||||
|
@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device)
|
||||||
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
|
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
|
||||||
#endif
|
#endif
|
||||||
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
|
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
|
||||||
list_del(&hwdep->list);
|
list_del_init(&hwdep->list);
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
return snd_hwdep_free(hwdep);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
@ -497,7 +497,7 @@ static void __init snd_hwdep_proc_init(void)
|
||||||
|
|
||||||
static void __exit snd_hwdep_proc_done(void)
|
static void __exit snd_hwdep_proc_done(void)
|
||||||
{
|
{
|
||||||
snd_info_unregister(snd_hwdep_proc_entry);
|
snd_info_free_entry(snd_hwdep_proc_entry);
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_PROC_FS */
|
#else /* !CONFIG_PROC_FS */
|
||||||
#define snd_hwdep_proc_init()
|
#define snd_hwdep_proc_init()
|
||||||
|
|
|
@ -78,6 +78,7 @@ struct snd_info_private_data {
|
||||||
|
|
||||||
static int snd_info_version_init(void);
|
static int snd_info_version_init(void);
|
||||||
static int snd_info_version_done(void);
|
static int snd_info_version_done(void);
|
||||||
|
static void snd_info_disconnect(struct snd_info_entry *entry);
|
||||||
|
|
||||||
|
|
||||||
/* resize the proc r/w buffer */
|
/* resize the proc r/w buffer */
|
||||||
|
@ -174,15 +175,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
|
||||||
switch (entry->content) {
|
switch (entry->content) {
|
||||||
case SNDRV_INFO_CONTENT_TEXT:
|
case SNDRV_INFO_CONTENT_TEXT:
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
case 0: /* SEEK_SET */
|
case SEEK_SET:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
ret = file->f_pos;
|
ret = file->f_pos;
|
||||||
goto out;
|
goto out;
|
||||||
case 1: /* SEEK_CUR */
|
case SEEK_CUR:
|
||||||
file->f_pos += offset;
|
file->f_pos += offset;
|
||||||
ret = file->f_pos;
|
ret = file->f_pos;
|
||||||
goto out;
|
goto out;
|
||||||
case 2: /* SEEK_END */
|
case SEEK_END:
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -304,7 +305,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
|
||||||
mutex_lock(&info_mutex);
|
mutex_lock(&info_mutex);
|
||||||
p = PDE(inode);
|
p = PDE(inode);
|
||||||
entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
|
entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
|
||||||
if (entry == NULL || entry->disconnected) {
|
if (entry == NULL || ! entry->p) {
|
||||||
mutex_unlock(&info_mutex);
|
mutex_unlock(&info_mutex);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -586,10 +587,10 @@ int __exit snd_info_done(void)
|
||||||
snd_info_version_done();
|
snd_info_version_done();
|
||||||
if (snd_proc_root) {
|
if (snd_proc_root) {
|
||||||
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
|
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
|
||||||
snd_info_unregister(snd_seq_root);
|
snd_info_free_entry(snd_seq_root);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
snd_info_unregister(snd_oss_root);
|
snd_info_free_entry(snd_oss_root);
|
||||||
#endif
|
#endif
|
||||||
snd_remove_proc_entry(&proc_root, snd_proc_root);
|
snd_remove_proc_entry(&proc_root, snd_proc_root);
|
||||||
}
|
}
|
||||||
|
@ -648,17 +649,28 @@ int snd_info_card_register(struct snd_card *card)
|
||||||
* de-register the card proc file
|
* de-register the card proc file
|
||||||
* called from init.c
|
* called from init.c
|
||||||
*/
|
*/
|
||||||
int snd_info_card_free(struct snd_card *card)
|
void snd_info_card_disconnect(struct snd_card *card)
|
||||||
{
|
{
|
||||||
snd_assert(card != NULL, return -ENXIO);
|
snd_assert(card != NULL, return);
|
||||||
|
mutex_lock(&info_mutex);
|
||||||
if (card->proc_root_link) {
|
if (card->proc_root_link) {
|
||||||
snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
|
snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
|
||||||
card->proc_root_link = NULL;
|
card->proc_root_link = NULL;
|
||||||
}
|
}
|
||||||
if (card->proc_root) {
|
if (card->proc_root)
|
||||||
snd_info_unregister(card->proc_root);
|
snd_info_disconnect(card->proc_root);
|
||||||
card->proc_root = NULL;
|
mutex_unlock(&info_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* release the card proc file resources
|
||||||
|
* called from init.c
|
||||||
|
*/
|
||||||
|
int snd_info_card_free(struct snd_card *card)
|
||||||
|
{
|
||||||
|
snd_assert(card != NULL, return -ENXIO);
|
||||||
|
snd_info_free_entry(card->proc_root);
|
||||||
|
card->proc_root = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,6 +779,8 @@ static struct snd_info_entry *snd_info_create_entry(const char *name)
|
||||||
entry->mode = S_IFREG | S_IRUGO;
|
entry->mode = S_IFREG | S_IRUGO;
|
||||||
entry->content = SNDRV_INFO_CONTENT_TEXT;
|
entry->content = SNDRV_INFO_CONTENT_TEXT;
|
||||||
mutex_init(&entry->access);
|
mutex_init(&entry->access);
|
||||||
|
INIT_LIST_HEAD(&entry->children);
|
||||||
|
INIT_LIST_HEAD(&entry->list);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,6 +833,24 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_info_create_card_entry);
|
EXPORT_SYMBOL(snd_info_create_card_entry);
|
||||||
|
|
||||||
|
static void snd_info_disconnect(struct snd_info_entry *entry)
|
||||||
|
{
|
||||||
|
struct list_head *p, *n;
|
||||||
|
struct proc_dir_entry *root;
|
||||||
|
|
||||||
|
list_for_each_safe(p, n, &entry->children) {
|
||||||
|
snd_info_disconnect(list_entry(p, struct snd_info_entry, list));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! entry->p)
|
||||||
|
return;
|
||||||
|
list_del_init(&entry->list);
|
||||||
|
root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
|
||||||
|
snd_assert(root, return);
|
||||||
|
snd_remove_proc_entry(root, entry->p);
|
||||||
|
entry->p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_info_dev_free_entry(struct snd_device *device)
|
static int snd_info_dev_free_entry(struct snd_device *device)
|
||||||
{
|
{
|
||||||
struct snd_info_entry *entry = device->device_data;
|
struct snd_info_entry *entry = device->device_data;
|
||||||
|
@ -832,19 +864,6 @@ static int snd_info_dev_register_entry(struct snd_device *device)
|
||||||
return snd_info_register(entry);
|
return snd_info_register(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_info_dev_disconnect_entry(struct snd_device *device)
|
|
||||||
{
|
|
||||||
struct snd_info_entry *entry = device->device_data;
|
|
||||||
entry->disconnected = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_info_dev_unregister_entry(struct snd_device *device)
|
|
||||||
{
|
|
||||||
struct snd_info_entry *entry = device->device_data;
|
|
||||||
return snd_info_unregister(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_card_proc_new - create an info entry for the given card
|
* snd_card_proc_new - create an info entry for the given card
|
||||||
* @card: the card instance
|
* @card: the card instance
|
||||||
|
@ -871,8 +890,7 @@ int snd_card_proc_new(struct snd_card *card, const char *name,
|
||||||
static struct snd_device_ops ops = {
|
static struct snd_device_ops ops = {
|
||||||
.dev_free = snd_info_dev_free_entry,
|
.dev_free = snd_info_dev_free_entry,
|
||||||
.dev_register = snd_info_dev_register_entry,
|
.dev_register = snd_info_dev_register_entry,
|
||||||
.dev_disconnect = snd_info_dev_disconnect_entry,
|
/* disconnect is done via snd_info_card_disconnect() */
|
||||||
.dev_unregister = snd_info_dev_unregister_entry
|
|
||||||
};
|
};
|
||||||
struct snd_info_entry *entry;
|
struct snd_info_entry *entry;
|
||||||
int err;
|
int err;
|
||||||
|
@ -901,6 +919,11 @@ void snd_info_free_entry(struct snd_info_entry * entry)
|
||||||
{
|
{
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return;
|
return;
|
||||||
|
if (entry->p) {
|
||||||
|
mutex_lock(&info_mutex);
|
||||||
|
snd_info_disconnect(entry);
|
||||||
|
mutex_unlock(&info_mutex);
|
||||||
|
}
|
||||||
kfree(entry->name);
|
kfree(entry->name);
|
||||||
if (entry->private_free)
|
if (entry->private_free)
|
||||||
entry->private_free(entry);
|
entry->private_free(entry);
|
||||||
|
@ -935,38 +958,14 @@ int snd_info_register(struct snd_info_entry * entry)
|
||||||
p->size = entry->size;
|
p->size = entry->size;
|
||||||
p->data = entry;
|
p->data = entry;
|
||||||
entry->p = p;
|
entry->p = p;
|
||||||
|
if (entry->parent)
|
||||||
|
list_add_tail(&entry->list, &entry->parent->children);
|
||||||
mutex_unlock(&info_mutex);
|
mutex_unlock(&info_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_info_register);
|
EXPORT_SYMBOL(snd_info_register);
|
||||||
|
|
||||||
/**
|
|
||||||
* snd_info_unregister - de-register the info entry
|
|
||||||
* @entry: the info entry
|
|
||||||
*
|
|
||||||
* De-registers the info entry and releases the instance.
|
|
||||||
*
|
|
||||||
* Returns zero if successful, or a negative error code on failure.
|
|
||||||
*/
|
|
||||||
int snd_info_unregister(struct snd_info_entry * entry)
|
|
||||||
{
|
|
||||||
struct proc_dir_entry *root;
|
|
||||||
|
|
||||||
if (! entry)
|
|
||||||
return 0;
|
|
||||||
snd_assert(entry->p != NULL, return -ENXIO);
|
|
||||||
root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
|
|
||||||
snd_assert(root, return -ENXIO);
|
|
||||||
mutex_lock(&info_mutex);
|
|
||||||
snd_remove_proc_entry(root, entry->p);
|
|
||||||
mutex_unlock(&info_mutex);
|
|
||||||
snd_info_free_entry(entry);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_info_unregister);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -999,8 +998,7 @@ static int __init snd_info_version_init(void)
|
||||||
|
|
||||||
static int __exit snd_info_version_done(void)
|
static int __exit snd_info_version_done(void)
|
||||||
{
|
{
|
||||||
if (snd_info_version_entry)
|
snd_info_free_entry(snd_info_version_entry);
|
||||||
snd_info_unregister(snd_info_version_entry);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,10 +131,8 @@ int snd_info_minor_register(void)
|
||||||
|
|
||||||
int snd_info_minor_unregister(void)
|
int snd_info_minor_unregister(void)
|
||||||
{
|
{
|
||||||
if (snd_sndstat_proc_entry) {
|
snd_info_free_entry(snd_sndstat_proc_entry);
|
||||||
snd_info_unregister(snd_sndstat_proc_entry);
|
|
||||||
snd_sndstat_proc_entry = NULL;
|
snd_sndstat_proc_entry = NULL;
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,6 @@ static inline int init_info_for_card(struct snd_card *card)
|
||||||
#define init_info_for_card(card)
|
#define init_info_for_card(card)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void snd_card_free_thread(void * __card);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_card_new - create and initialize a soundcard structure
|
* snd_card_new - create and initialize a soundcard structure
|
||||||
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
|
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
|
||||||
|
@ -145,7 +143,6 @@ struct snd_card *snd_card_new(int idx, const char *xid,
|
||||||
INIT_LIST_HEAD(&card->ctl_files);
|
INIT_LIST_HEAD(&card->ctl_files);
|
||||||
spin_lock_init(&card->files_lock);
|
spin_lock_init(&card->files_lock);
|
||||||
init_waitqueue_head(&card->shutdown_sleep);
|
init_waitqueue_head(&card->shutdown_sleep);
|
||||||
INIT_WORK(&card->free_workq, snd_card_free_thread, card);
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
mutex_init(&card->power_lock);
|
mutex_init(&card->power_lock);
|
||||||
init_waitqueue_head(&card->power_sleep);
|
init_waitqueue_head(&card->power_sleep);
|
||||||
|
@ -310,6 +307,7 @@ int snd_card_disconnect(struct snd_card *card)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
|
snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
|
||||||
|
|
||||||
|
snd_info_card_disconnect(card);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,22 +324,10 @@ EXPORT_SYMBOL(snd_card_disconnect);
|
||||||
* Returns zero. Frees all associated devices and frees the control
|
* Returns zero. Frees all associated devices and frees the control
|
||||||
* interface associated to given soundcard.
|
* interface associated to given soundcard.
|
||||||
*/
|
*/
|
||||||
int snd_card_free(struct snd_card *card)
|
static int snd_card_do_free(struct snd_card *card)
|
||||||
{
|
{
|
||||||
struct snd_shutdown_f_ops *s_f_ops;
|
struct snd_shutdown_f_ops *s_f_ops;
|
||||||
|
|
||||||
if (card == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
mutex_lock(&snd_card_mutex);
|
|
||||||
snd_cards[card->number] = NULL;
|
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
wake_up(&card->power_sleep);
|
|
||||||
#endif
|
|
||||||
/* wait, until all devices are ready for the free operation */
|
|
||||||
wait_event(card->shutdown_sleep, card->files == NULL);
|
|
||||||
|
|
||||||
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
|
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
|
||||||
if (snd_mixer_oss_notify_callback)
|
if (snd_mixer_oss_notify_callback)
|
||||||
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
|
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
|
||||||
|
@ -360,7 +346,7 @@ int snd_card_free(struct snd_card *card)
|
||||||
}
|
}
|
||||||
if (card->private_free)
|
if (card->private_free)
|
||||||
card->private_free(card);
|
card->private_free(card);
|
||||||
snd_info_unregister(card->proc_id);
|
snd_info_free_entry(card->proc_id);
|
||||||
if (snd_info_card_free(card) < 0) {
|
if (snd_info_card_free(card) < 0) {
|
||||||
snd_printk(KERN_WARNING "unable to free card info\n");
|
snd_printk(KERN_WARNING "unable to free card info\n");
|
||||||
/* Not fatal error */
|
/* Not fatal error */
|
||||||
|
@ -370,62 +356,60 @@ int snd_card_free(struct snd_card *card)
|
||||||
card->s_f_ops = s_f_ops->next;
|
card->s_f_ops = s_f_ops->next;
|
||||||
kfree(s_f_ops);
|
kfree(s_f_ops);
|
||||||
}
|
}
|
||||||
mutex_lock(&snd_card_mutex);
|
|
||||||
snd_cards_lock &= ~(1 << card->number);
|
|
||||||
mutex_unlock(&snd_card_mutex);
|
|
||||||
kfree(card);
|
kfree(card);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snd_card_free_prepare(struct snd_card *card)
|
||||||
|
{
|
||||||
|
if (card == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
(void) snd_card_disconnect(card);
|
||||||
|
mutex_lock(&snd_card_mutex);
|
||||||
|
snd_cards[card->number] = NULL;
|
||||||
|
snd_cards_lock &= ~(1 << card->number);
|
||||||
|
mutex_unlock(&snd_card_mutex);
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
wake_up(&card->power_sleep);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_card_free_when_closed(struct snd_card *card)
|
||||||
|
{
|
||||||
|
int free_now = 0;
|
||||||
|
int ret = snd_card_free_prepare(card);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
spin_lock(&card->files_lock);
|
||||||
|
if (card->files == NULL)
|
||||||
|
free_now = 1;
|
||||||
|
else
|
||||||
|
card->free_on_last_close = 1;
|
||||||
|
spin_unlock(&card->files_lock);
|
||||||
|
|
||||||
|
if (free_now)
|
||||||
|
snd_card_do_free(card);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_card_free_when_closed);
|
||||||
|
|
||||||
|
int snd_card_free(struct snd_card *card)
|
||||||
|
{
|
||||||
|
int ret = snd_card_free_prepare(card);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* wait, until all devices are ready for the free operation */
|
||||||
|
wait_event(card->shutdown_sleep, card->files == NULL);
|
||||||
|
snd_card_do_free(card);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_card_free);
|
EXPORT_SYMBOL(snd_card_free);
|
||||||
|
|
||||||
static void snd_card_free_thread(void * __card)
|
|
||||||
{
|
|
||||||
struct snd_card *card = __card;
|
|
||||||
struct module * module = card->module;
|
|
||||||
|
|
||||||
if (!try_module_get(module)) {
|
|
||||||
snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
|
|
||||||
module = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_card_free(card);
|
|
||||||
|
|
||||||
module_put(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* snd_card_free_in_thread - call snd_card_free() in thread
|
|
||||||
* @card: soundcard structure
|
|
||||||
*
|
|
||||||
* This function schedules the call of snd_card_free() function in a
|
|
||||||
* work queue. When all devices are released (non-busy), the work
|
|
||||||
* is woken up and calls snd_card_free().
|
|
||||||
*
|
|
||||||
* When a card can be disconnected at any time by hotplug service,
|
|
||||||
* this function should be used in disconnect (or detach) callback
|
|
||||||
* instead of calling snd_card_free() directly.
|
|
||||||
*
|
|
||||||
* Returns - zero otherwise a negative error code if the start of thread failed.
|
|
||||||
*/
|
|
||||||
int snd_card_free_in_thread(struct snd_card *card)
|
|
||||||
{
|
|
||||||
if (card->files == NULL) {
|
|
||||||
snd_card_free(card);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schedule_work(&card->free_workq))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number);
|
|
||||||
/* try to free the structure immediately */
|
|
||||||
snd_card_free(card);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_card_free_in_thread);
|
|
||||||
|
|
||||||
static void choose_default_id(struct snd_card *card)
|
static void choose_default_id(struct snd_card *card)
|
||||||
{
|
{
|
||||||
int i, len, idx_flag = 0, loops = SNDRV_CARDS;
|
int i, len, idx_flag = 0, loops = SNDRV_CARDS;
|
||||||
|
@ -625,9 +609,9 @@ int __init snd_card_info_init(void)
|
||||||
|
|
||||||
int __exit snd_card_info_done(void)
|
int __exit snd_card_info_done(void)
|
||||||
{
|
{
|
||||||
snd_info_unregister(snd_card_info_entry);
|
snd_info_free_entry(snd_card_info_entry);
|
||||||
#ifdef MODULE
|
#ifdef MODULE
|
||||||
snd_info_unregister(snd_card_module_info_entry);
|
snd_info_free_entry(snd_card_module_info_entry);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -708,15 +692,16 @@ EXPORT_SYMBOL(snd_card_file_add);
|
||||||
*
|
*
|
||||||
* This function removes the file formerly added to the card via
|
* This function removes the file formerly added to the card via
|
||||||
* snd_card_file_add() function.
|
* snd_card_file_add() function.
|
||||||
* If all files are removed and the release of the card is
|
* If all files are removed and snd_card_free_when_closed() was
|
||||||
* scheduled, it will wake up the the thread to call snd_card_free()
|
* called beforehand, it processes the pending release of
|
||||||
* (see snd_card_free_in_thread() function).
|
* resources.
|
||||||
*
|
*
|
||||||
* Returns zero or a negative error code.
|
* Returns zero or a negative error code.
|
||||||
*/
|
*/
|
||||||
int snd_card_file_remove(struct snd_card *card, struct file *file)
|
int snd_card_file_remove(struct snd_card *card, struct file *file)
|
||||||
{
|
{
|
||||||
struct snd_monitor_file *mfile, *pfile = NULL;
|
struct snd_monitor_file *mfile, *pfile = NULL;
|
||||||
|
int last_close = 0;
|
||||||
|
|
||||||
spin_lock(&card->files_lock);
|
spin_lock(&card->files_lock);
|
||||||
mfile = card->files;
|
mfile = card->files;
|
||||||
|
@ -731,9 +716,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
|
||||||
pfile = mfile;
|
pfile = mfile;
|
||||||
mfile = mfile->next;
|
mfile = mfile->next;
|
||||||
}
|
}
|
||||||
spin_unlock(&card->files_lock);
|
|
||||||
if (card->files == NULL)
|
if (card->files == NULL)
|
||||||
|
last_close = 1;
|
||||||
|
spin_unlock(&card->files_lock);
|
||||||
|
if (last_close) {
|
||||||
wake_up(&card->shutdown_sleep);
|
wake_up(&card->shutdown_sleep);
|
||||||
|
if (card->free_on_last_close)
|
||||||
|
snd_card_do_free(card);
|
||||||
|
}
|
||||||
if (!mfile) {
|
if (!mfile) {
|
||||||
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
|
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
|
@ -1193,11 +1193,9 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
|
||||||
|
|
||||||
static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
|
static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
|
||||||
{
|
{
|
||||||
if (mixer->proc_entry) {
|
snd_info_free_entry(mixer->proc_entry);
|
||||||
snd_info_unregister(mixer->proc_entry);
|
|
||||||
mixer->proc_entry = NULL;
|
mixer->proc_entry = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else /* !CONFIG_PROC_FS */
|
#else /* !CONFIG_PROC_FS */
|
||||||
#define snd_mixer_oss_proc_init(mix)
|
#define snd_mixer_oss_proc_init(mix)
|
||||||
#define snd_mixer_oss_proc_done(mix)
|
#define snd_mixer_oss_proc_done(mix)
|
||||||
|
@ -1312,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
|
||||||
card->mixer_oss = mixer;
|
card->mixer_oss = mixer;
|
||||||
snd_mixer_oss_build(mixer);
|
snd_mixer_oss_build(mixer);
|
||||||
snd_mixer_oss_proc_init(mixer);
|
snd_mixer_oss_proc_init(mixer);
|
||||||
} else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
|
} else {
|
||||||
mixer = card->mixer_oss;
|
|
||||||
if (mixer == NULL || !mixer->oss_dev_alloc)
|
|
||||||
return 0;
|
|
||||||
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
|
|
||||||
mixer->oss_dev_alloc = 0;
|
|
||||||
} else { /* free */
|
|
||||||
mixer = card->mixer_oss;
|
mixer = card->mixer_oss;
|
||||||
if (mixer == NULL)
|
if (mixer == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (mixer->oss_dev_alloc) {
|
||||||
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
|
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
|
||||||
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
|
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
|
||||||
#endif
|
#endif
|
||||||
if (mixer->oss_dev_alloc)
|
|
||||||
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
|
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
|
||||||
|
mixer->oss_dev_alloc = 0;
|
||||||
|
}
|
||||||
|
if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
|
||||||
|
return 0;
|
||||||
snd_mixer_oss_proc_done(mixer);
|
snd_mixer_oss_proc_done(mixer);
|
||||||
return snd_mixer_oss_free1(mixer);
|
return snd_mixer_oss_free1(mixer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2846,13 +2846,11 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
|
||||||
int stream;
|
int stream;
|
||||||
for (stream = 0; stream < 2; ++stream) {
|
for (stream = 0; stream < 2; ++stream) {
|
||||||
struct snd_pcm_str *pstr = &pcm->streams[stream];
|
struct snd_pcm_str *pstr = &pcm->streams[stream];
|
||||||
if (pstr->oss.proc_entry) {
|
snd_info_free_entry(pstr->oss.proc_entry);
|
||||||
snd_info_unregister(pstr->oss.proc_entry);
|
|
||||||
pstr->oss.proc_entry = NULL;
|
pstr->oss.proc_entry = NULL;
|
||||||
snd_pcm_oss_proc_free_setup_list(pstr);
|
snd_pcm_oss_proc_free_setup_list(pstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else /* !CONFIG_SND_VERBOSE_PROCFS */
|
#else /* !CONFIG_SND_VERBOSE_PROCFS */
|
||||||
#define snd_pcm_oss_proc_init(pcm)
|
#define snd_pcm_oss_proc_init(pcm)
|
||||||
#define snd_pcm_oss_proc_done(pcm)
|
#define snd_pcm_oss_proc_done(pcm)
|
||||||
|
@ -2931,6 +2929,12 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
|
||||||
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
|
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
|
||||||
pcm->card, 1);
|
pcm->card, 1);
|
||||||
}
|
}
|
||||||
|
if (dsp_map[pcm->card->number] == (int)pcm->device) {
|
||||||
|
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
|
||||||
|
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
pcm->oss.reg = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2938,15 +2942,7 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
|
||||||
static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
|
static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
|
||||||
{
|
{
|
||||||
snd_pcm_oss_disconnect_minor(pcm);
|
snd_pcm_oss_disconnect_minor(pcm);
|
||||||
if (pcm->oss.reg) {
|
|
||||||
if (dsp_map[pcm->card->number] == (int)pcm->device) {
|
|
||||||
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
|
|
||||||
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
pcm->oss.reg = 0;
|
|
||||||
snd_pcm_oss_proc_done(pcm);
|
snd_pcm_oss_proc_done(pcm);
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
108
sound/core/pcm.c
108
sound/core/pcm.c
|
@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm);
|
||||||
static int snd_pcm_dev_free(struct snd_device *device);
|
static int snd_pcm_dev_free(struct snd_device *device);
|
||||||
static int snd_pcm_dev_register(struct snd_device *device);
|
static int snd_pcm_dev_register(struct snd_device *device);
|
||||||
static int snd_pcm_dev_disconnect(struct snd_device *device);
|
static int snd_pcm_dev_disconnect(struct snd_device *device);
|
||||||
static int snd_pcm_dev_unregister(struct snd_device *device);
|
|
||||||
|
|
||||||
static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
|
static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
|
||||||
{
|
{
|
||||||
|
@ -494,19 +493,13 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
|
||||||
static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
|
static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
||||||
if (pstr->proc_xrun_debug_entry) {
|
snd_info_free_entry(pstr->proc_xrun_debug_entry);
|
||||||
snd_info_unregister(pstr->proc_xrun_debug_entry);
|
|
||||||
pstr->proc_xrun_debug_entry = NULL;
|
pstr->proc_xrun_debug_entry = NULL;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (pstr->proc_info_entry) {
|
snd_info_free_entry(pstr->proc_info_entry);
|
||||||
snd_info_unregister(pstr->proc_info_entry);
|
|
||||||
pstr->proc_info_entry = NULL;
|
pstr->proc_info_entry = NULL;
|
||||||
}
|
snd_info_free_entry(pstr->proc_root);
|
||||||
if (pstr->proc_root) {
|
|
||||||
snd_info_unregister(pstr->proc_root);
|
|
||||||
pstr->proc_root = NULL;
|
pstr->proc_root = NULL;
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,26 +566,16 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
|
static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
if (substream->proc_info_entry) {
|
snd_info_free_entry(substream->proc_info_entry);
|
||||||
snd_info_unregister(substream->proc_info_entry);
|
|
||||||
substream->proc_info_entry = NULL;
|
substream->proc_info_entry = NULL;
|
||||||
}
|
snd_info_free_entry(substream->proc_hw_params_entry);
|
||||||
if (substream->proc_hw_params_entry) {
|
|
||||||
snd_info_unregister(substream->proc_hw_params_entry);
|
|
||||||
substream->proc_hw_params_entry = NULL;
|
substream->proc_hw_params_entry = NULL;
|
||||||
}
|
snd_info_free_entry(substream->proc_sw_params_entry);
|
||||||
if (substream->proc_sw_params_entry) {
|
|
||||||
snd_info_unregister(substream->proc_sw_params_entry);
|
|
||||||
substream->proc_sw_params_entry = NULL;
|
substream->proc_sw_params_entry = NULL;
|
||||||
}
|
snd_info_free_entry(substream->proc_status_entry);
|
||||||
if (substream->proc_status_entry) {
|
|
||||||
snd_info_unregister(substream->proc_status_entry);
|
|
||||||
substream->proc_status_entry = NULL;
|
substream->proc_status_entry = NULL;
|
||||||
}
|
snd_info_free_entry(substream->proc_root);
|
||||||
if (substream->proc_root) {
|
|
||||||
snd_info_unregister(substream->proc_root);
|
|
||||||
substream->proc_root = NULL;
|
substream->proc_root = NULL;
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_SND_VERBOSE_PROCFS */
|
#else /* !CONFIG_SND_VERBOSE_PROCFS */
|
||||||
|
@ -696,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
|
||||||
.dev_free = snd_pcm_dev_free,
|
.dev_free = snd_pcm_dev_free,
|
||||||
.dev_register = snd_pcm_dev_register,
|
.dev_register = snd_pcm_dev_register,
|
||||||
.dev_disconnect = snd_pcm_dev_disconnect,
|
.dev_disconnect = snd_pcm_dev_disconnect,
|
||||||
.dev_unregister = snd_pcm_dev_unregister
|
|
||||||
};
|
};
|
||||||
|
|
||||||
snd_assert(rpcm != NULL, return -EINVAL);
|
snd_assert(rpcm != NULL, return -EINVAL);
|
||||||
|
@ -740,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
|
||||||
substream = pstr->substream;
|
substream = pstr->substream;
|
||||||
while (substream) {
|
while (substream) {
|
||||||
substream_next = substream->next;
|
substream_next = substream->next;
|
||||||
|
snd_pcm_timer_done(substream);
|
||||||
snd_pcm_substream_proc_done(substream);
|
snd_pcm_substream_proc_done(substream);
|
||||||
kfree(substream);
|
kfree(substream);
|
||||||
substream = substream_next;
|
substream = substream_next;
|
||||||
|
@ -756,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
|
||||||
|
|
||||||
static int snd_pcm_free(struct snd_pcm *pcm)
|
static int snd_pcm_free(struct snd_pcm *pcm)
|
||||||
{
|
{
|
||||||
|
struct snd_pcm_notify *notify;
|
||||||
|
|
||||||
snd_assert(pcm != NULL, return -ENXIO);
|
snd_assert(pcm != NULL, return -ENXIO);
|
||||||
|
list_for_each_entry(notify, &snd_pcm_notify_list, list) {
|
||||||
|
notify->n_unregister(pcm);
|
||||||
|
}
|
||||||
if (pcm->private_free)
|
if (pcm->private_free)
|
||||||
pcm->private_free(pcm);
|
pcm->private_free(pcm);
|
||||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||||
|
@ -804,6 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
||||||
kctl = snd_ctl_file(list);
|
kctl = snd_ctl_file(list);
|
||||||
if (kctl->pid == current->pid) {
|
if (kctl->pid == current->pid) {
|
||||||
prefer_subdevice = kctl->prefer_pcm_subdevice;
|
prefer_subdevice = kctl->prefer_pcm_subdevice;
|
||||||
|
if (prefer_subdevice != -1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -918,6 +907,28 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
||||||
substream->pstr->substream_opened--;
|
substream->pstr->substream_opened--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t show_pcm_class(struct class_device *class_device, char *buf)
|
||||||
|
{
|
||||||
|
struct snd_pcm *pcm;
|
||||||
|
const char *str;
|
||||||
|
static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
|
||||||
|
[SNDRV_PCM_CLASS_GENERIC] = "generic",
|
||||||
|
[SNDRV_PCM_CLASS_MULTI] = "multi",
|
||||||
|
[SNDRV_PCM_CLASS_MODEM] = "modem",
|
||||||
|
[SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (! (pcm = class_get_devdata(class_device)) ||
|
||||||
|
pcm->dev_class > SNDRV_PCM_CLASS_LAST)
|
||||||
|
str = "none";
|
||||||
|
else
|
||||||
|
str = strs[pcm->dev_class];
|
||||||
|
return snprintf(buf, PAGE_SIZE, "%s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct class_device_attribute pcm_attrs =
|
||||||
|
__ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
|
||||||
|
|
||||||
static int snd_pcm_dev_register(struct snd_device *device)
|
static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
{
|
{
|
||||||
int cidx, err;
|
int cidx, err;
|
||||||
|
@ -956,6 +967,8 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
|
||||||
|
&pcm_attrs);
|
||||||
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
||||||
snd_pcm_timer_init(substream);
|
snd_pcm_timer_init(substream);
|
||||||
}
|
}
|
||||||
|
@ -971,35 +984,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
static int snd_pcm_dev_disconnect(struct snd_device *device)
|
static int snd_pcm_dev_disconnect(struct snd_device *device)
|
||||||
{
|
{
|
||||||
struct snd_pcm *pcm = device->device_data;
|
struct snd_pcm *pcm = device->device_data;
|
||||||
struct list_head *list;
|
struct snd_pcm_notify *notify;
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
int cidx;
|
int cidx, devtype;
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
mutex_lock(®ister_mutex);
|
||||||
|
if (list_empty(&pcm->list))
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
list_del_init(&pcm->list);
|
list_del_init(&pcm->list);
|
||||||
for (cidx = 0; cidx < 2; cidx++)
|
for (cidx = 0; cidx < 2; cidx++)
|
||||||
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
||||||
if (substream->runtime)
|
if (substream->runtime)
|
||||||
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
|
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
|
||||||
list_for_each(list, &snd_pcm_notify_list) {
|
list_for_each_entry(notify, &snd_pcm_notify_list, list) {
|
||||||
struct snd_pcm_notify *notify;
|
|
||||||
notify = list_entry(list, struct snd_pcm_notify, list);
|
|
||||||
notify->n_disconnect(pcm);
|
notify->n_disconnect(pcm);
|
||||||
}
|
}
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_pcm_dev_unregister(struct snd_device *device)
|
|
||||||
{
|
|
||||||
int cidx, devtype;
|
|
||||||
struct snd_pcm_substream *substream;
|
|
||||||
struct list_head *list;
|
|
||||||
struct snd_pcm *pcm = device->device_data;
|
|
||||||
|
|
||||||
snd_assert(pcm != NULL, return -ENXIO);
|
|
||||||
mutex_lock(®ister_mutex);
|
|
||||||
list_del(&pcm->list);
|
|
||||||
for (cidx = 0; cidx < 2; cidx++) {
|
for (cidx = 0; cidx < 2; cidx++) {
|
||||||
devtype = -1;
|
devtype = -1;
|
||||||
switch (cidx) {
|
switch (cidx) {
|
||||||
|
@ -1011,23 +1011,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snd_unregister_device(devtype, pcm->card, pcm->device);
|
snd_unregister_device(devtype, pcm->card, pcm->device);
|
||||||
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
|
||||||
snd_pcm_timer_done(substream);
|
|
||||||
}
|
|
||||||
list_for_each(list, &snd_pcm_notify_list) {
|
|
||||||
struct snd_pcm_notify *notify;
|
|
||||||
notify = list_entry(list, struct snd_pcm_notify, list);
|
|
||||||
notify->n_unregister(pcm);
|
|
||||||
}
|
}
|
||||||
|
unlock:
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
return snd_pcm_free(pcm);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
|
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
|
||||||
{
|
{
|
||||||
struct list_head *p;
|
struct list_head *p;
|
||||||
|
|
||||||
snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
|
snd_assert(notify != NULL &&
|
||||||
|
notify->n_register != NULL &&
|
||||||
|
notify->n_unregister != NULL &&
|
||||||
|
notify->n_disconnect, return -EINVAL);
|
||||||
mutex_lock(®ister_mutex);
|
mutex_lock(®ister_mutex);
|
||||||
if (nfree) {
|
if (nfree) {
|
||||||
list_del(¬ify->list);
|
list_del(¬ify->list);
|
||||||
|
@ -1090,8 +1087,7 @@ static void snd_pcm_proc_init(void)
|
||||||
|
|
||||||
static void snd_pcm_proc_done(void)
|
static void snd_pcm_proc_done(void)
|
||||||
{
|
{
|
||||||
if (snd_pcm_proc_entry)
|
snd_info_free_entry(snd_pcm_proc_entry);
|
||||||
snd_info_unregister(snd_pcm_proc_entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* !CONFIG_PROC_FS */
|
#else /* !CONFIG_PROC_FS */
|
||||||
|
|
|
@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
|
||||||
* mmap of PCM status/control records because of the size
|
* mmap of PCM status/control records because of the size
|
||||||
* incompatibility.
|
* incompatibility.
|
||||||
*/
|
*/
|
||||||
substream->no_mmap_ctrl = 1;
|
pcm_file->no_compat_mmap = 1;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_IOCTL_PVERSION:
|
case SNDRV_PCM_IOCTL_PVERSION:
|
||||||
|
|
|
@ -101,7 +101,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
snd_pcm_lib_preallocate_dma_free(substream);
|
snd_pcm_lib_preallocate_dma_free(substream);
|
||||||
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
||||||
snd_info_unregister(substream->proc_prealloc_entry);
|
snd_info_free_entry(substream->proc_prealloc_entry);
|
||||||
substream->proc_prealloc_entry = NULL;
|
substream->proc_prealloc_entry = NULL;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1992,35 +1992,9 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_pcm_add_file(struct snd_pcm_str *str,
|
|
||||||
struct snd_pcm_file *pcm_file)
|
|
||||||
{
|
|
||||||
pcm_file->next = str->files;
|
|
||||||
str->files = pcm_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void snd_pcm_remove_file(struct snd_pcm_str *str,
|
|
||||||
struct snd_pcm_file *pcm_file)
|
|
||||||
{
|
|
||||||
struct snd_pcm_file * pcm_file1;
|
|
||||||
if (str->files == pcm_file) {
|
|
||||||
str->files = pcm_file->next;
|
|
||||||
} else {
|
|
||||||
pcm_file1 = str->files;
|
|
||||||
while (pcm_file1 && pcm_file1->next != pcm_file)
|
|
||||||
pcm_file1 = pcm_file1->next;
|
|
||||||
if (pcm_file1 != NULL)
|
|
||||||
pcm_file1->next = pcm_file->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pcm_release_private(struct snd_pcm_substream *substream)
|
static void pcm_release_private(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_file *pcm_file = substream->file;
|
|
||||||
|
|
||||||
snd_pcm_unlink(substream);
|
snd_pcm_unlink(substream);
|
||||||
snd_pcm_remove_file(substream->pstr, pcm_file);
|
|
||||||
kfree(pcm_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
|
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
|
||||||
|
@ -2060,7 +2034,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
substream->no_mmap_ctrl = 0;
|
|
||||||
err = snd_pcm_hw_constraints_init(substream);
|
err = snd_pcm_hw_constraints_init(substream);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
snd_printd("snd_pcm_hw_constraints_init failed\n");
|
snd_printd("snd_pcm_hw_constraints_init failed\n");
|
||||||
|
@ -2105,19 +2078,16 @@ static int snd_pcm_open_file(struct file *file,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (substream->ref_count > 1)
|
|
||||||
pcm_file = substream->file;
|
|
||||||
else {
|
|
||||||
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
|
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
|
||||||
if (pcm_file == NULL) {
|
if (pcm_file == NULL) {
|
||||||
snd_pcm_release_substream(substream);
|
snd_pcm_release_substream(substream);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
pcm_file->substream = substream;
|
||||||
|
if (substream->ref_count == 1) {
|
||||||
str = substream->pstr;
|
str = substream->pstr;
|
||||||
substream->file = pcm_file;
|
substream->file = pcm_file;
|
||||||
substream->pcm_release = pcm_release_private;
|
substream->pcm_release = pcm_release_private;
|
||||||
pcm_file->substream = substream;
|
|
||||||
snd_pcm_add_file(str, pcm_file);
|
|
||||||
}
|
}
|
||||||
file->private_data = pcm_file;
|
file->private_data = pcm_file;
|
||||||
*rpcm_file = pcm_file;
|
*rpcm_file = pcm_file;
|
||||||
|
@ -2209,6 +2179,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
|
||||||
fasync_helper(-1, file, 0, &substream->runtime->fasync);
|
fasync_helper(-1, file, 0, &substream->runtime->fasync);
|
||||||
mutex_lock(&pcm->open_mutex);
|
mutex_lock(&pcm->open_mutex);
|
||||||
snd_pcm_release_substream(substream);
|
snd_pcm_release_substream(substream);
|
||||||
|
kfree(pcm_file);
|
||||||
mutex_unlock(&pcm->open_mutex);
|
mutex_unlock(&pcm->open_mutex);
|
||||||
wake_up(&pcm->open_wait);
|
wake_up(&pcm->open_wait);
|
||||||
module_put(pcm->card->module);
|
module_put(pcm->card->module);
|
||||||
|
@ -3270,11 +3241,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
|
||||||
offset = area->vm_pgoff << PAGE_SHIFT;
|
offset = area->vm_pgoff << PAGE_SHIFT;
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case SNDRV_PCM_MMAP_OFFSET_STATUS:
|
case SNDRV_PCM_MMAP_OFFSET_STATUS:
|
||||||
if (substream->no_mmap_ctrl)
|
if (pcm_file->no_compat_mmap)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
return snd_pcm_mmap_status(substream, file, area);
|
return snd_pcm_mmap_status(substream, file, area);
|
||||||
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
|
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
|
||||||
if (substream->no_mmap_ctrl)
|
if (pcm_file->no_compat_mmap)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
return snd_pcm_mmap_control(substream, file, area);
|
return snd_pcm_mmap_control(substream, file, area);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
|
||||||
static int snd_rawmidi_dev_free(struct snd_device *device);
|
static int snd_rawmidi_dev_free(struct snd_device *device);
|
||||||
static int snd_rawmidi_dev_register(struct snd_device *device);
|
static int snd_rawmidi_dev_register(struct snd_device *device);
|
||||||
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
|
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
|
||||||
static int snd_rawmidi_dev_unregister(struct snd_device *device);
|
|
||||||
|
|
||||||
static LIST_HEAD(snd_rawmidi_devices);
|
static LIST_HEAD(snd_rawmidi_devices);
|
||||||
static DEFINE_MUTEX(register_mutex);
|
static DEFINE_MUTEX(register_mutex);
|
||||||
|
@ -431,6 +430,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
||||||
kctl = snd_ctl_file(list);
|
kctl = snd_ctl_file(list);
|
||||||
if (kctl->pid == current->pid) {
|
if (kctl->pid == current->pid) {
|
||||||
subdevice = kctl->prefer_rawmidi_subdevice;
|
subdevice = kctl->prefer_rawmidi_subdevice;
|
||||||
|
if (subdevice != -1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1426,7 +1426,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
|
||||||
.dev_free = snd_rawmidi_dev_free,
|
.dev_free = snd_rawmidi_dev_free,
|
||||||
.dev_register = snd_rawmidi_dev_register,
|
.dev_register = snd_rawmidi_dev_register,
|
||||||
.dev_disconnect = snd_rawmidi_dev_disconnect,
|
.dev_disconnect = snd_rawmidi_dev_disconnect,
|
||||||
.dev_unregister = snd_rawmidi_dev_unregister
|
|
||||||
};
|
};
|
||||||
|
|
||||||
snd_assert(rrawmidi != NULL, return -EINVAL);
|
snd_assert(rrawmidi != NULL, return -EINVAL);
|
||||||
|
@ -1479,6 +1478,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
|
||||||
static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
|
static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
|
||||||
{
|
{
|
||||||
snd_assert(rmidi != NULL, return -ENXIO);
|
snd_assert(rmidi != NULL, return -ENXIO);
|
||||||
|
|
||||||
|
snd_info_free_entry(rmidi->proc_entry);
|
||||||
|
rmidi->proc_entry = NULL;
|
||||||
|
mutex_lock(®ister_mutex);
|
||||||
|
if (rmidi->ops && rmidi->ops->dev_unregister)
|
||||||
|
rmidi->ops->dev_unregister(rmidi);
|
||||||
|
mutex_unlock(®ister_mutex);
|
||||||
|
|
||||||
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
|
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
|
||||||
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
|
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
|
||||||
if (rmidi->private_free)
|
if (rmidi->private_free)
|
||||||
|
@ -1587,21 +1594,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
|
||||||
|
|
||||||
mutex_lock(®ister_mutex);
|
mutex_lock(®ister_mutex);
|
||||||
list_del_init(&rmidi->list);
|
list_del_init(&rmidi->list);
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_rawmidi_dev_unregister(struct snd_device *device)
|
|
||||||
{
|
|
||||||
struct snd_rawmidi *rmidi = device->device_data;
|
|
||||||
|
|
||||||
snd_assert(rmidi != NULL, return -ENXIO);
|
|
||||||
mutex_lock(®ister_mutex);
|
|
||||||
list_del(&rmidi->list);
|
|
||||||
if (rmidi->proc_entry) {
|
|
||||||
snd_info_unregister(rmidi->proc_entry);
|
|
||||||
rmidi->proc_entry = NULL;
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
if (rmidi->ossreg) {
|
if (rmidi->ossreg) {
|
||||||
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
|
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
|
||||||
|
@ -1615,17 +1607,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device)
|
||||||
rmidi->ossreg = 0;
|
rmidi->ossreg = 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_OSSEMUL */
|
#endif /* CONFIG_SND_OSSEMUL */
|
||||||
if (rmidi->ops && rmidi->ops->dev_unregister)
|
|
||||||
rmidi->ops->dev_unregister(rmidi);
|
|
||||||
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
|
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
|
return 0;
|
||||||
if (rmidi->seq_dev) {
|
|
||||||
snd_device_free(rmidi->card, rmidi->seq_dev);
|
|
||||||
rmidi->seq_dev = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return snd_rawmidi_free(rmidi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -156,7 +156,7 @@ static int __init rtctimer_init(void)
|
||||||
static void __exit rtctimer_exit(void)
|
static void __exit rtctimer_exit(void)
|
||||||
{
|
{
|
||||||
if (rtctimer) {
|
if (rtctimer) {
|
||||||
snd_timer_global_unregister(rtctimer);
|
snd_timer_global_free(rtctimer);
|
||||||
rtctimer = NULL;
|
rtctimer = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,8 +303,7 @@ register_proc(void)
|
||||||
static void
|
static void
|
||||||
unregister_proc(void)
|
unregister_proc(void)
|
||||||
{
|
{
|
||||||
if (info_entry)
|
snd_info_free_entry(info_entry);
|
||||||
snd_info_unregister(info_entry);
|
|
||||||
info_entry = NULL;
|
info_entry = NULL;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PROC_FS */
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
|
@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev);
|
||||||
static int snd_seq_device_dev_free(struct snd_device *device);
|
static int snd_seq_device_dev_free(struct snd_device *device);
|
||||||
static int snd_seq_device_dev_register(struct snd_device *device);
|
static int snd_seq_device_dev_register(struct snd_device *device);
|
||||||
static int snd_seq_device_dev_disconnect(struct snd_device *device);
|
static int snd_seq_device_dev_disconnect(struct snd_device *device);
|
||||||
static int snd_seq_device_dev_unregister(struct snd_device *device);
|
|
||||||
|
|
||||||
static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
|
static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
|
||||||
static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
|
static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
|
||||||
|
@ -189,7 +188,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
|
||||||
.dev_free = snd_seq_device_dev_free,
|
.dev_free = snd_seq_device_dev_free,
|
||||||
.dev_register = snd_seq_device_dev_register,
|
.dev_register = snd_seq_device_dev_register,
|
||||||
.dev_disconnect = snd_seq_device_dev_disconnect,
|
.dev_disconnect = snd_seq_device_dev_disconnect,
|
||||||
.dev_unregister = snd_seq_device_dev_unregister
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -308,15 +306,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* unregister the existing device
|
|
||||||
*/
|
|
||||||
static int snd_seq_device_dev_unregister(struct snd_device *device)
|
|
||||||
{
|
|
||||||
struct snd_seq_device *dev = device->device_data;
|
|
||||||
return snd_seq_device_free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* register device driver
|
* register device driver
|
||||||
* id = driver id
|
* id = driver id
|
||||||
|
@ -573,7 +562,7 @@ static void __exit alsa_seq_device_exit(void)
|
||||||
{
|
{
|
||||||
remove_drivers();
|
remove_drivers();
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
snd_info_unregister(info_entry);
|
snd_info_free_entry(info_entry);
|
||||||
#endif
|
#endif
|
||||||
if (num_ops)
|
if (num_ops)
|
||||||
snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
|
snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
|
||||||
|
|
|
@ -64,9 +64,9 @@ int __init snd_seq_info_init(void)
|
||||||
|
|
||||||
int __exit snd_seq_info_done(void)
|
int __exit snd_seq_info_done(void)
|
||||||
{
|
{
|
||||||
snd_info_unregister(queues_entry);
|
snd_info_free_entry(queues_entry);
|
||||||
snd_info_unregister(clients_entry);
|
snd_info_free_entry(clients_entry);
|
||||||
snd_info_unregister(timer_entry);
|
snd_info_free_entry(timer_entry);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -268,7 +268,11 @@ int snd_register_device(int type, struct snd_card *card, int dev,
|
||||||
snd_minors[minor] = preg;
|
snd_minors[minor] = preg;
|
||||||
if (card)
|
if (card)
|
||||||
device = card->dev;
|
device = card->dev;
|
||||||
class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
|
preg->class_dev = class_device_create(sound_class, NULL,
|
||||||
|
MKDEV(major, minor),
|
||||||
|
device, "%s", name);
|
||||||
|
if (preg->class_dev)
|
||||||
|
class_set_devdata(preg->class_dev, private_data);
|
||||||
|
|
||||||
mutex_unlock(&sound_mutex);
|
mutex_unlock(&sound_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -276,6 +280,24 @@ int snd_register_device(int type, struct snd_card *card, int dev,
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_register_device);
|
EXPORT_SYMBOL(snd_register_device);
|
||||||
|
|
||||||
|
/* find the matching minor record
|
||||||
|
* return the index of snd_minor, or -1 if not found
|
||||||
|
*/
|
||||||
|
static int find_snd_minor(int type, struct snd_card *card, int dev)
|
||||||
|
{
|
||||||
|
int cardnum, minor;
|
||||||
|
struct snd_minor *mptr;
|
||||||
|
|
||||||
|
cardnum = card ? card->number : -1;
|
||||||
|
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
|
||||||
|
if ((mptr = snd_minors[minor]) != NULL &&
|
||||||
|
mptr->type == type &&
|
||||||
|
mptr->card == cardnum &&
|
||||||
|
mptr->device == dev)
|
||||||
|
return minor;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_unregister_device - unregister the device on the given card
|
* snd_unregister_device - unregister the device on the given card
|
||||||
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
|
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
|
||||||
|
@ -289,32 +311,42 @@ EXPORT_SYMBOL(snd_register_device);
|
||||||
*/
|
*/
|
||||||
int snd_unregister_device(int type, struct snd_card *card, int dev)
|
int snd_unregister_device(int type, struct snd_card *card, int dev)
|
||||||
{
|
{
|
||||||
int cardnum, minor;
|
int minor;
|
||||||
struct snd_minor *mptr;
|
|
||||||
|
|
||||||
cardnum = card ? card->number : -1;
|
|
||||||
mutex_lock(&sound_mutex);
|
mutex_lock(&sound_mutex);
|
||||||
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
|
minor = find_snd_minor(type, card, dev);
|
||||||
if ((mptr = snd_minors[minor]) != NULL &&
|
if (minor < 0) {
|
||||||
mptr->type == type &&
|
|
||||||
mptr->card == cardnum &&
|
|
||||||
mptr->device == dev)
|
|
||||||
break;
|
|
||||||
if (minor == ARRAY_SIZE(snd_minors)) {
|
|
||||||
mutex_unlock(&sound_mutex);
|
mutex_unlock(&sound_mutex);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
class_device_destroy(sound_class, MKDEV(major, minor));
|
class_device_destroy(sound_class, MKDEV(major, minor));
|
||||||
|
|
||||||
|
kfree(snd_minors[minor]);
|
||||||
snd_minors[minor] = NULL;
|
snd_minors[minor] = NULL;
|
||||||
mutex_unlock(&sound_mutex);
|
mutex_unlock(&sound_mutex);
|
||||||
kfree(mptr);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_unregister_device);
|
EXPORT_SYMBOL(snd_unregister_device);
|
||||||
|
|
||||||
|
int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
|
||||||
|
const struct class_device_attribute *attr)
|
||||||
|
{
|
||||||
|
int minor, ret = -EINVAL;
|
||||||
|
struct class_device *cdev;
|
||||||
|
|
||||||
|
mutex_lock(&sound_mutex);
|
||||||
|
minor = find_snd_minor(type, card, dev);
|
||||||
|
if (minor >= 0 && (cdev = snd_minors[minor]->class_dev) != NULL)
|
||||||
|
ret = class_device_create_file(cdev, attr);
|
||||||
|
mutex_unlock(&sound_mutex);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_add_device_sysfs_file);
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
/*
|
/*
|
||||||
* INFO PART
|
* INFO PART
|
||||||
|
@ -387,8 +419,7 @@ int __init snd_minor_info_init(void)
|
||||||
|
|
||||||
int __exit snd_minor_info_done(void)
|
int __exit snd_minor_info_done(void)
|
||||||
{
|
{
|
||||||
if (snd_minor_info_entry)
|
snd_info_free_entry(snd_minor_info_entry);
|
||||||
snd_info_unregister(snd_minor_info_entry);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PROC_FS */
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
|
@ -270,8 +270,7 @@ int __init snd_minor_info_oss_init(void)
|
||||||
|
|
||||||
int __exit snd_minor_info_oss_done(void)
|
int __exit snd_minor_info_oss_done(void)
|
||||||
{
|
{
|
||||||
if (snd_minor_info_oss_entry)
|
snd_info_free_entry(snd_minor_info_oss_entry);
|
||||||
snd_info_unregister(snd_minor_info_oss_entry);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PROC_FS */
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
|
@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex);
|
||||||
static int snd_timer_free(struct snd_timer *timer);
|
static int snd_timer_free(struct snd_timer *timer);
|
||||||
static int snd_timer_dev_free(struct snd_device *device);
|
static int snd_timer_dev_free(struct snd_device *device);
|
||||||
static int snd_timer_dev_register(struct snd_device *device);
|
static int snd_timer_dev_register(struct snd_device *device);
|
||||||
static int snd_timer_dev_unregister(struct snd_device *device);
|
static int snd_timer_dev_disconnect(struct snd_device *device);
|
||||||
|
|
||||||
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
|
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
|
||||||
|
|
||||||
|
@ -718,7 +718,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
|
if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
|
||||||
snd_timer_reschedule(timer, ticks_left);
|
snd_timer_reschedule(timer, timer->sticks);
|
||||||
if (timer->running) {
|
if (timer->running) {
|
||||||
if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
|
if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
|
||||||
timer->hw.stop(timer);
|
timer->hw.stop(timer);
|
||||||
|
@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
|
||||||
static struct snd_device_ops ops = {
|
static struct snd_device_ops ops = {
|
||||||
.dev_free = snd_timer_dev_free,
|
.dev_free = snd_timer_dev_free,
|
||||||
.dev_register = snd_timer_dev_register,
|
.dev_register = snd_timer_dev_register,
|
||||||
.dev_unregister = snd_timer_dev_unregister
|
.dev_disconnect = snd_timer_dev_disconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
snd_assert(tid != NULL, return -EINVAL);
|
snd_assert(tid != NULL, return -EINVAL);
|
||||||
|
@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
|
||||||
static int snd_timer_free(struct snd_timer *timer)
|
static int snd_timer_free(struct snd_timer *timer)
|
||||||
{
|
{
|
||||||
snd_assert(timer != NULL, return -ENXIO);
|
snd_assert(timer != NULL, return -ENXIO);
|
||||||
|
|
||||||
|
mutex_lock(®ister_mutex);
|
||||||
|
if (! list_empty(&timer->open_list_head)) {
|
||||||
|
struct list_head *p, *n;
|
||||||
|
struct snd_timer_instance *ti;
|
||||||
|
snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
|
||||||
|
list_for_each_safe(p, n, &timer->open_list_head) {
|
||||||
|
list_del_init(p);
|
||||||
|
ti = list_entry(p, struct snd_timer_instance, open_list);
|
||||||
|
ti->timer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_del(&timer->device_list);
|
||||||
|
mutex_unlock(®ister_mutex);
|
||||||
|
|
||||||
if (timer->private_free)
|
if (timer->private_free)
|
||||||
timer->private_free(timer);
|
timer->private_free(timer);
|
||||||
kfree(timer);
|
kfree(timer);
|
||||||
|
@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_timer_unregister(struct snd_timer *timer)
|
static int snd_timer_dev_disconnect(struct snd_device *device)
|
||||||
{
|
|
||||||
struct list_head *p, *n;
|
|
||||||
struct snd_timer_instance *ti;
|
|
||||||
|
|
||||||
snd_assert(timer != NULL, return -ENXIO);
|
|
||||||
mutex_lock(®ister_mutex);
|
|
||||||
if (! list_empty(&timer->open_list_head)) {
|
|
||||||
snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
|
|
||||||
list_for_each_safe(p, n, &timer->open_list_head) {
|
|
||||||
list_del_init(p);
|
|
||||||
ti = list_entry(p, struct snd_timer_instance, open_list);
|
|
||||||
ti->timer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_del(&timer->device_list);
|
|
||||||
mutex_unlock(®ister_mutex);
|
|
||||||
return snd_timer_free(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_timer_dev_unregister(struct snd_device *device)
|
|
||||||
{
|
{
|
||||||
struct snd_timer *timer = device->device_data;
|
struct snd_timer *timer = device->device_data;
|
||||||
return snd_timer_unregister(timer);
|
mutex_lock(®ister_mutex);
|
||||||
|
list_del_init(&timer->device_list);
|
||||||
|
mutex_unlock(®ister_mutex);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
|
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
|
||||||
|
@ -955,18 +953,12 @@ int snd_timer_global_register(struct snd_timer *timer)
|
||||||
return snd_timer_dev_register(&dev);
|
return snd_timer_dev_register(&dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_timer_global_unregister(struct snd_timer *timer)
|
|
||||||
{
|
|
||||||
return snd_timer_unregister(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* System timer
|
* System timer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct snd_timer_system_private {
|
struct snd_timer_system_private {
|
||||||
struct timer_list tlist;
|
struct timer_list tlist;
|
||||||
struct timer * timer;
|
|
||||||
unsigned long last_expires;
|
unsigned long last_expires;
|
||||||
unsigned long last_jiffies;
|
unsigned long last_jiffies;
|
||||||
unsigned long correction;
|
unsigned long correction;
|
||||||
|
@ -978,7 +970,7 @@ static void snd_timer_s_function(unsigned long data)
|
||||||
struct snd_timer_system_private *priv = timer->private_data;
|
struct snd_timer_system_private *priv = timer->private_data;
|
||||||
unsigned long jiff = jiffies;
|
unsigned long jiff = jiffies;
|
||||||
if (time_after(jiff, priv->last_expires))
|
if (time_after(jiff, priv->last_expires))
|
||||||
priv->correction = (long)jiff - (long)priv->last_expires;
|
priv->correction += (long)jiff - (long)priv->last_expires;
|
||||||
snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
|
snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,7 +986,7 @@ static int snd_timer_s_start(struct snd_timer * timer)
|
||||||
njiff++;
|
njiff++;
|
||||||
} else {
|
} else {
|
||||||
njiff += timer->sticks - priv->correction;
|
njiff += timer->sticks - priv->correction;
|
||||||
priv->correction -= timer->sticks;
|
priv->correction = 0;
|
||||||
}
|
}
|
||||||
priv->last_expires = priv->tlist.expires = njiff;
|
priv->last_expires = priv->tlist.expires = njiff;
|
||||||
add_timer(&priv->tlist);
|
add_timer(&priv->tlist);
|
||||||
|
@ -1013,6 +1005,7 @@ static int snd_timer_s_stop(struct snd_timer * timer)
|
||||||
timer->sticks = priv->last_expires - jiff;
|
timer->sticks = priv->last_expires - jiff;
|
||||||
else
|
else
|
||||||
timer->sticks = 1;
|
timer->sticks = 1;
|
||||||
|
priv->correction = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1126,7 +1119,7 @@ static void __init snd_timer_proc_init(void)
|
||||||
|
|
||||||
static void __exit snd_timer_proc_done(void)
|
static void __exit snd_timer_proc_done(void)
|
||||||
{
|
{
|
||||||
snd_info_unregister(snd_timer_proc_entry);
|
snd_info_free_entry(snd_timer_proc_entry);
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_PROC_FS */
|
#else /* !CONFIG_PROC_FS */
|
||||||
#define snd_timer_proc_init()
|
#define snd_timer_proc_init()
|
||||||
|
@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void)
|
||||||
/* unregister the system timer */
|
/* unregister the system timer */
|
||||||
list_for_each_safe(p, n, &snd_timer_list) {
|
list_for_each_safe(p, n, &snd_timer_list) {
|
||||||
struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
|
struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
|
||||||
snd_timer_unregister(timer);
|
snd_timer_free(timer);
|
||||||
}
|
}
|
||||||
snd_timer_proc_done();
|
snd_timer_proc_done();
|
||||||
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
|
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
|
||||||
|
@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify);
|
||||||
EXPORT_SYMBOL(snd_timer_global_new);
|
EXPORT_SYMBOL(snd_timer_global_new);
|
||||||
EXPORT_SYMBOL(snd_timer_global_free);
|
EXPORT_SYMBOL(snd_timer_global_free);
|
||||||
EXPORT_SYMBOL(snd_timer_global_register);
|
EXPORT_SYMBOL(snd_timer_global_register);
|
||||||
EXPORT_SYMBOL(snd_timer_global_unregister);
|
|
||||||
EXPORT_SYMBOL(snd_timer_interrupt);
|
EXPORT_SYMBOL(snd_timer_interrupt);
|
||||||
|
|
|
@ -73,6 +73,19 @@ config SND_MTPAV
|
||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called snd-mtpav.
|
will be called snd-mtpav.
|
||||||
|
|
||||||
|
config SND_MTS64
|
||||||
|
tristate "ESI Miditerminal 4140 driver"
|
||||||
|
depends on SND && PARPORT
|
||||||
|
select SND_RAWMIDI
|
||||||
|
help
|
||||||
|
The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with
|
||||||
|
additional SMPTE Timecode capabilities for the parallel port.
|
||||||
|
|
||||||
|
Say 'Y' to include support for this device.
|
||||||
|
|
||||||
|
To compile this driver as a module, chose 'M' here: the module
|
||||||
|
will be called snd-mts64.
|
||||||
|
|
||||||
config SND_SERIAL_U16550
|
config SND_SERIAL_U16550
|
||||||
tristate "UART16550 serial MIDI driver"
|
tristate "UART16550 serial MIDI driver"
|
||||||
depends on SND
|
depends on SND
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
snd-dummy-objs := dummy.o
|
snd-dummy-objs := dummy.o
|
||||||
snd-mtpav-objs := mtpav.o
|
snd-mtpav-objs := mtpav.o
|
||||||
|
snd-mts64-objs := mts64.o
|
||||||
snd-serial-u16550-objs := serial-u16550.o
|
snd-serial-u16550-objs := serial-u16550.o
|
||||||
snd-virmidi-objs := virmidi.o
|
snd-virmidi-objs := virmidi.o
|
||||||
|
|
||||||
|
@ -13,5 +14,6 @@ obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
|
||||||
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
|
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
|
||||||
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
|
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
|
||||||
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
|
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
|
||||||
|
obj-$(CONFIG_SND_MTS64) += snd-mts64.o
|
||||||
|
|
||||||
obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
|
obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/rawmidi.h>
|
#include <sound/rawmidi.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
@ -285,7 +286,7 @@ static struct snd_pcm_hardware snd_card_dummy_playback =
|
||||||
.channels_max = USE_CHANNELS_MAX,
|
.channels_max = USE_CHANNELS_MAX,
|
||||||
.buffer_bytes_max = MAX_BUFFER_SIZE,
|
.buffer_bytes_max = MAX_BUFFER_SIZE,
|
||||||
.period_bytes_min = 64,
|
.period_bytes_min = 64,
|
||||||
.period_bytes_max = MAX_BUFFER_SIZE,
|
.period_bytes_max = MAX_PERIOD_SIZE,
|
||||||
.periods_min = USE_PERIODS_MIN,
|
.periods_min = USE_PERIODS_MIN,
|
||||||
.periods_max = USE_PERIODS_MAX,
|
.periods_max = USE_PERIODS_MAX,
|
||||||
.fifo_size = 0,
|
.fifo_size = 0,
|
||||||
|
@ -443,10 +444,13 @@ static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int su
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DUMMY_VOLUME(xname, xindex, addr) \
|
#define DUMMY_VOLUME(xname, xindex, addr) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
.info = snd_dummy_volume_info, \
|
.info = snd_dummy_volume_info, \
|
||||||
.get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
|
.get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
|
||||||
.private_value = addr }
|
.private_value = addr, \
|
||||||
|
.tlv = { .p = db_scale_dummy } }
|
||||||
|
|
||||||
static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
|
static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo)
|
struct snd_ctl_elem_info *uinfo)
|
||||||
|
@ -497,6 +501,8 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
|
||||||
|
|
||||||
#define DUMMY_CAPSRC(xname, xindex, addr) \
|
#define DUMMY_CAPSRC(xname, xindex, addr) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||||
.info = snd_dummy_capsrc_info, \
|
.info = snd_dummy_capsrc_info, \
|
||||||
|
@ -547,13 +553,13 @@ static struct snd_kcontrol_new snd_dummy_controls[] = {
|
||||||
DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
|
DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
|
||||||
DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
|
DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
|
||||||
DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
|
DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
|
||||||
DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER),
|
DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
|
||||||
DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
|
DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
|
||||||
DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER),
|
DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
|
||||||
DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
|
DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
|
||||||
DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER),
|
DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
|
||||||
DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
|
DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
|
||||||
DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER)
|
DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy)
|
static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy)
|
||||||
|
|
|
@ -211,7 +211,7 @@ static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev)
|
||||||
struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev);
|
struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev);
|
||||||
|
|
||||||
snd_card_disconnect(card);
|
snd_card_disconnect(card);
|
||||||
snd_card_free_in_thread(card);
|
snd_card_free_when_closed(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pnp_driver snd_mpu401_pnp_driver = {
|
static struct pnp_driver snd_mpu401_pnp_driver = {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -105,13 +105,13 @@ static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *fi
|
||||||
struct file *file, long long offset, int orig)
|
struct file *file, long long offset, int orig)
|
||||||
{
|
{
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
case 0: /* SEEK_SET */
|
case SEEK_SET:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
break;
|
break;
|
||||||
case 1: /* SEEK_CUR */
|
case SEEK_CUR:
|
||||||
file->f_pos += offset;
|
file->f_pos += offset;
|
||||||
break;
|
break;
|
||||||
case 2: /* SEEK_END, offset is negative */
|
case SEEK_END: /* offset is negative */
|
||||||
file->f_pos = entry->size + offset;
|
file->f_pos = entry->size + offset;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -159,8 +159,7 @@ int snd_opl4_create_proc(struct snd_opl4 *opl4)
|
||||||
|
|
||||||
void snd_opl4_free_proc(struct snd_opl4 *opl4)
|
void snd_opl4_free_proc(struct snd_opl4 *opl4)
|
||||||
{
|
{
|
||||||
if (opl4->proc_entry)
|
snd_info_free_entry(opl4->proc_entry);
|
||||||
snd_info_unregister(opl4->proc_entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PROC_FS */
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <sound/driver.h>
|
#include <sound/driver.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/vx_core.h>
|
#include <sound/vx_core.h>
|
||||||
#include "vx_cmd.h"
|
#include "vx_cmd.h"
|
||||||
|
|
||||||
|
@ -455,10 +456,13 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
|
||||||
|
|
||||||
static struct snd_kcontrol_new vx_control_output_level = {
|
static struct snd_kcontrol_new vx_control_output_level = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Master Playback Volume",
|
.name = "Master Playback Volume",
|
||||||
.info = vx_output_level_info,
|
.info = vx_output_level_info,
|
||||||
.get = vx_output_level_get,
|
.get = vx_output_level_get,
|
||||||
.put = vx_output_level_put,
|
.put = vx_output_level_put,
|
||||||
|
/* tlv will be filled later */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -712,12 +716,17 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new vx_control_audio_gain = {
|
static struct snd_kcontrol_new vx_control_audio_gain = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
/* name will be filled later */
|
/* name will be filled later */
|
||||||
.info = vx_audio_gain_info,
|
.info = vx_audio_gain_info,
|
||||||
.get = vx_audio_gain_get,
|
.get = vx_audio_gain_get,
|
||||||
.put = vx_audio_gain_put
|
.put = vx_audio_gain_put,
|
||||||
|
.tlv = { .p = db_scale_audio_gain },
|
||||||
};
|
};
|
||||||
static struct snd_kcontrol_new vx_control_output_switch = {
|
static struct snd_kcontrol_new vx_control_output_switch = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -729,9 +738,12 @@ static struct snd_kcontrol_new vx_control_output_switch = {
|
||||||
static struct snd_kcontrol_new vx_control_monitor_gain = {
|
static struct snd_kcontrol_new vx_control_monitor_gain = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
.name = "Monitoring Volume",
|
.name = "Monitoring Volume",
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.info = vx_audio_gain_info, /* shared */
|
.info = vx_audio_gain_info, /* shared */
|
||||||
.get = vx_audio_monitor_get,
|
.get = vx_audio_monitor_get,
|
||||||
.put = vx_audio_monitor_put
|
.put = vx_audio_monitor_put,
|
||||||
|
.tlv = { .p = db_scale_audio_gain },
|
||||||
};
|
};
|
||||||
static struct snd_kcontrol_new vx_control_monitor_switch = {
|
static struct snd_kcontrol_new vx_control_monitor_switch = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -918,6 +930,7 @@ int snd_vx_mixer_new(struct vx_core *chip)
|
||||||
for (i = 0; i < chip->hw->num_outs; i++) {
|
for (i = 0; i < chip->hw->num_outs; i++) {
|
||||||
temp = vx_control_output_level;
|
temp = vx_control_output_level;
|
||||||
temp.index = i;
|
temp.index = i;
|
||||||
|
temp.tlv.p = chip->hw->output_level_db_scale;
|
||||||
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
|
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,14 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ak4xxx-adda.h>
|
#include <sound/ak4xxx-adda.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
|
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
|
||||||
MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
|
MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
/* write the given register and save the data to the cache */
|
||||||
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
||||||
unsigned char val)
|
unsigned char val)
|
||||||
{
|
{
|
||||||
|
@ -41,15 +43,7 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
||||||
ak->ops.write(ak, chip, reg, val);
|
ak->ops.write(ak, chip, reg, val);
|
||||||
|
|
||||||
/* save the data */
|
/* save the data */
|
||||||
if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
|
|
||||||
if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0)
|
|
||||||
snd_akm4xxx_set(ak, chip, reg, val);
|
snd_akm4xxx_set(ak, chip, reg, val);
|
||||||
else
|
|
||||||
snd_akm4xxx_set_ipga(ak, chip, reg, val);
|
|
||||||
} else {
|
|
||||||
/* AK4529, or else */
|
|
||||||
snd_akm4xxx_set(ak, chip, reg, val);
|
|
||||||
}
|
|
||||||
ak->ops.unlock(ak, chip);
|
ak->ops.unlock(ak, chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,12 +67,6 @@ static void ak4524_reset(struct snd_akm4xxx *ak, int state)
|
||||||
for (reg = 0x04; reg < maxreg; reg++)
|
for (reg = 0x04; reg < maxreg; reg++)
|
||||||
snd_akm4xxx_write(ak, chip, reg,
|
snd_akm4xxx_write(ak, chip, reg,
|
||||||
snd_akm4xxx_get(ak, chip, reg));
|
snd_akm4xxx_get(ak, chip, reg));
|
||||||
if (ak->type == SND_AK4528)
|
|
||||||
continue;
|
|
||||||
/* IPGA */
|
|
||||||
for (reg = 0x04; reg < 0x06; reg++)
|
|
||||||
snd_akm4xxx_write(ak, chip, reg,
|
|
||||||
snd_akm4xxx_get_ipga(ak, chip, reg));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +125,48 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
|
||||||
case SND_AK4381:
|
case SND_AK4381:
|
||||||
ak4381_reset(ak, state);
|
ak4381_reset(ak, state);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_akm4xxx_reset);
|
EXPORT_SYMBOL(snd_akm4xxx_reset);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Volume conversion table for non-linear volumes
|
||||||
|
* from -63.5dB (mute) to 0dB step 0.5dB
|
||||||
|
*
|
||||||
|
* Used for AK4524 input/ouput attenuation, AK4528, and
|
||||||
|
* AK5365 input attenuation
|
||||||
|
*/
|
||||||
|
static unsigned char vol_cvt_datt[128] = {
|
||||||
|
0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
|
||||||
|
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
|
||||||
|
0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
|
||||||
|
0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
|
||||||
|
0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
|
||||||
|
0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
|
||||||
|
0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
|
||||||
|
0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
|
||||||
|
0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||||
|
0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
|
||||||
|
0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
|
||||||
|
0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
|
||||||
|
0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
|
||||||
|
0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
|
||||||
|
0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
|
||||||
|
0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dB tables
|
||||||
|
*/
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
|
||||||
|
static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize all the ak4xxx chips
|
* initialize all the ak4xxx chips
|
||||||
*/
|
*/
|
||||||
|
@ -155,8 +180,6 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||||
0x01, 0x03, /* 1: ADC/DAC enable */
|
0x01, 0x03, /* 1: ADC/DAC enable */
|
||||||
0x04, 0x00, /* 4: ADC left muted */
|
0x04, 0x00, /* 4: ADC left muted */
|
||||||
0x05, 0x00, /* 5: ADC right muted */
|
0x05, 0x00, /* 5: ADC right muted */
|
||||||
0x04, 0x80, /* 4: ADC IPGA gain 0dB */
|
|
||||||
0x05, 0x80, /* 5: ADC IPGA gain 0dB */
|
|
||||||
0x06, 0x00, /* 6: DAC left muted */
|
0x06, 0x00, /* 6: DAC left muted */
|
||||||
0x07, 0x00, /* 7: DAC right muted */
|
0x07, 0x00, /* 7: DAC right muted */
|
||||||
0xff, 0xff
|
0xff, 0xff
|
||||||
|
@ -238,6 +261,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||||
int chip, num_chips;
|
int chip, num_chips;
|
||||||
unsigned char *ptr, reg, data, *inits;
|
unsigned char *ptr, reg, data, *inits;
|
||||||
|
|
||||||
|
memset(ak->images, 0, sizeof(ak->images));
|
||||||
|
memset(ak->volumes, 0, sizeof(ak->volumes));
|
||||||
|
|
||||||
switch (ak->type) {
|
switch (ak->type) {
|
||||||
case SND_AK4524:
|
case SND_AK4524:
|
||||||
inits = inits_ak4524;
|
inits = inits_ak4524;
|
||||||
|
@ -263,6 +289,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||||
inits = inits_ak4381;
|
inits = inits_ak4381;
|
||||||
num_chips = ak->num_dacs / 2;
|
num_chips = ak->num_dacs / 2;
|
||||||
break;
|
break;
|
||||||
|
case SND_AK5365:
|
||||||
|
/* FIXME: any init sequence? */
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
snd_BUG();
|
snd_BUG();
|
||||||
return;
|
return;
|
||||||
|
@ -280,14 +309,23 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_akm4xxx_init);
|
EXPORT_SYMBOL(snd_akm4xxx_init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mixer callbacks
|
||||||
|
*/
|
||||||
|
#define AK_IPGA (1<<20) /* including IPGA */
|
||||||
|
#define AK_VOL_CVT (1<<21) /* need dB conversion */
|
||||||
|
#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
|
||||||
|
#define AK_INVERT (1<<23) /* data is inverted */
|
||||||
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
|
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
|
||||||
#define AK_GET_ADDR(val) ((val) & 0xff)
|
#define AK_GET_ADDR(val) ((val) & 0xff)
|
||||||
#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f)
|
#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
|
||||||
|
#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
|
||||||
|
#define AK_GET_IPGA(val) (((val) >> 20) & 1)
|
||||||
|
#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
|
||||||
#define AK_GET_INVERT(val) (((val) >> 23) & 1)
|
#define AK_GET_INVERT(val) (((val) >> 23) & 1)
|
||||||
#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
|
#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
|
||||||
#define AK_COMPOSE(chip,addr,shift,mask) \
|
#define AK_COMPOSE(chip,addr,shift,mask) \
|
||||||
(((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
|
(((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
|
||||||
#define AK_INVERT (1<<23)
|
|
||||||
|
|
||||||
static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
|
static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo)
|
struct snd_ctl_elem_info *uinfo)
|
||||||
|
@ -307,31 +345,39 @@ static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||||
int invert = AK_GET_INVERT(kcontrol->private_value);
|
|
||||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
|
||||||
unsigned char val = snd_akm4xxx_get(ak, chip, addr);
|
|
||||||
|
|
||||||
ucontrol->value.integer.value[0] = invert ? mask - val : val;
|
ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
|
||||||
|
unsigned char nval)
|
||||||
|
{
|
||||||
|
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||||
|
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
||||||
|
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||||
|
|
||||||
|
if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
snd_akm4xxx_set_vol(ak, chip, addr, nval);
|
||||||
|
if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
|
||||||
|
nval = vol_cvt_datt[nval];
|
||||||
|
if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
|
||||||
|
nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
|
||||||
|
if (AK_GET_INVERT(kcontrol->private_value))
|
||||||
|
nval = mask - nval;
|
||||||
|
if (AK_GET_NEEDSMSB(kcontrol->private_value))
|
||||||
|
nval |= 0x80;
|
||||||
|
snd_akm4xxx_write(ak, chip, addr, nval);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
|
static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
|
||||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
ucontrol->value.integer.value[0]);
|
||||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
|
||||||
int invert = AK_GET_INVERT(kcontrol->private_value);
|
|
||||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
|
||||||
unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
|
|
||||||
int change;
|
|
||||||
|
|
||||||
if (invert)
|
|
||||||
nval = mask - nval;
|
|
||||||
change = snd_akm4xxx_get(ak, chip, addr) != nval;
|
|
||||||
if (change)
|
|
||||||
snd_akm4xxx_write(ak, chip, addr, nval);
|
|
||||||
return change;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
|
static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
|
@ -352,77 +398,21 @@ static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||||
int invert = AK_GET_INVERT(kcontrol->private_value);
|
|
||||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
|
||||||
unsigned char val = snd_akm4xxx_get(ak, chip, addr);
|
|
||||||
|
|
||||||
ucontrol->value.integer.value[0] = invert ? mask - val : val;
|
|
||||||
|
|
||||||
val = snd_akm4xxx_get(ak, chip, addr+1);
|
|
||||||
ucontrol->value.integer.value[1] = invert ? mask - val : val;
|
|
||||||
|
|
||||||
|
ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
|
||||||
|
ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
|
static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
|
||||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
|
||||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||||
int invert = AK_GET_INVERT(kcontrol->private_value);
|
int change;
|
||||||
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
|
|
||||||
unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
|
|
||||||
int change0, change1;
|
|
||||||
|
|
||||||
if (invert)
|
change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
|
||||||
nval = mask - nval;
|
change |= put_ak_reg(kcontrol, addr + 1,
|
||||||
change0 = snd_akm4xxx_get(ak, chip, addr) != nval;
|
ucontrol->value.integer.value[1]);
|
||||||
if (change0)
|
|
||||||
snd_akm4xxx_write(ak, chip, addr, nval);
|
|
||||||
|
|
||||||
nval = ucontrol->value.integer.value[1] % (mask+1);
|
|
||||||
if (invert)
|
|
||||||
nval = mask - nval;
|
|
||||||
change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval;
|
|
||||||
if (change1)
|
|
||||||
snd_akm4xxx_write(ak, chip, addr+1, nval);
|
|
||||||
|
|
||||||
|
|
||||||
return change0 || change1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_info *uinfo)
|
|
||||||
{
|
|
||||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
||||||
uinfo->count = 1;
|
|
||||||
uinfo->value.integer.min = 0;
|
|
||||||
uinfo->value.integer.max = 36;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
|
||||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
|
||||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
|
||||||
ucontrol->value.integer.value[0] =
|
|
||||||
snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_akm4xxx_ipga_gain_put(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
|
||||||
int chip = AK_GET_CHIP(kcontrol->private_value);
|
|
||||||
int addr = AK_GET_ADDR(kcontrol->private_value);
|
|
||||||
unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
|
|
||||||
int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval;
|
|
||||||
if (change)
|
|
||||||
snd_akm4xxx_write(ak, chip, addr, nval);
|
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,178 +462,279 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_info *uinfo)
|
||||||
|
{
|
||||||
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||||
|
uinfo->count = 1;
|
||||||
|
uinfo->value.integer.min = 0;
|
||||||
|
uinfo->value.integer.max = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||||
|
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||||
|
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||||
|
int shift = AK_GET_SHIFT(kcontrol->private_value);
|
||||||
|
int invert = AK_GET_INVERT(kcontrol->private_value);
|
||||||
|
unsigned char val = snd_akm4xxx_get(ak, chip, addr);
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
val = ! val;
|
||||||
|
ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
|
||||||
|
int chip = AK_GET_CHIP(kcontrol->private_value);
|
||||||
|
int addr = AK_GET_ADDR(kcontrol->private_value);
|
||||||
|
int shift = AK_GET_SHIFT(kcontrol->private_value);
|
||||||
|
int invert = AK_GET_INVERT(kcontrol->private_value);
|
||||||
|
long flag = ucontrol->value.integer.value[0];
|
||||||
|
unsigned char val, oval;
|
||||||
|
int change;
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
flag = ! flag;
|
||||||
|
oval = snd_akm4xxx_get(ak, chip, addr);
|
||||||
|
if (flag)
|
||||||
|
val = oval | (1<<shift);
|
||||||
|
else
|
||||||
|
val = oval & ~(1<<shift);
|
||||||
|
change = (oval != val);
|
||||||
|
if (change)
|
||||||
|
snd_akm4xxx_write(ak, chip, addr, val);
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* build AK4xxx controls
|
* build AK4xxx controls
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
static int build_dac_controls(struct snd_akm4xxx *ak)
|
||||||
{
|
{
|
||||||
unsigned int idx, num_emphs;
|
int idx, err, mixer_ch, num_stereo;
|
||||||
struct snd_kcontrol *ctl;
|
struct snd_kcontrol_new knew;
|
||||||
int err;
|
|
||||||
int mixer_ch = 0;
|
|
||||||
int num_stereo;
|
|
||||||
|
|
||||||
ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
|
|
||||||
if (! ctl)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
|
mixer_ch = 0;
|
||||||
for (idx = 0; idx < ak->num_dacs; ) {
|
for (idx = 0; idx < ak->num_dacs; ) {
|
||||||
memset(ctl, 0, sizeof(*ctl));
|
memset(&knew, 0, sizeof(knew));
|
||||||
if (ak->channel_names == NULL) {
|
if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
|
||||||
strcpy(ctl->id.name, "DAC Volume");
|
knew.name = "DAC Volume";
|
||||||
|
knew.index = mixer_ch + ak->idx_offset * 2;
|
||||||
num_stereo = 1;
|
num_stereo = 1;
|
||||||
ctl->id.index = mixer_ch + ak->idx_offset * 2;
|
|
||||||
} else {
|
} else {
|
||||||
strcpy(ctl->id.name, ak->channel_names[mixer_ch]);
|
knew.name = ak->dac_info[mixer_ch].name;
|
||||||
num_stereo = ak->num_stereo[mixer_ch];
|
num_stereo = ak->dac_info[mixer_ch].num_channels;
|
||||||
ctl->id.index = 0;
|
|
||||||
}
|
}
|
||||||
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||||
ctl->count = 1;
|
knew.count = 1;
|
||||||
|
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||||
if (num_stereo == 2) {
|
if (num_stereo == 2) {
|
||||||
ctl->info = snd_akm4xxx_stereo_volume_info;
|
knew.info = snd_akm4xxx_stereo_volume_info;
|
||||||
ctl->get = snd_akm4xxx_stereo_volume_get;
|
knew.get = snd_akm4xxx_stereo_volume_get;
|
||||||
ctl->put = snd_akm4xxx_stereo_volume_put;
|
knew.put = snd_akm4xxx_stereo_volume_put;
|
||||||
} else {
|
} else {
|
||||||
ctl->info = snd_akm4xxx_volume_info;
|
knew.info = snd_akm4xxx_volume_info;
|
||||||
ctl->get = snd_akm4xxx_volume_get;
|
knew.get = snd_akm4xxx_volume_get;
|
||||||
ctl->put = snd_akm4xxx_volume_put;
|
knew.put = snd_akm4xxx_volume_put;
|
||||||
}
|
}
|
||||||
switch (ak->type) {
|
switch (ak->type) {
|
||||||
case SND_AK4524:
|
case SND_AK4524:
|
||||||
/* register 6 & 7 */
|
/* register 6 & 7 */
|
||||||
ctl->private_value =
|
knew.private_value =
|
||||||
AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127);
|
AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
|
||||||
|
AK_VOL_CVT;
|
||||||
|
knew.tlv.p = db_scale_vol_datt;
|
||||||
break;
|
break;
|
||||||
case SND_AK4528:
|
case SND_AK4528:
|
||||||
/* register 4 & 5 */
|
/* register 4 & 5 */
|
||||||
ctl->private_value =
|
knew.private_value =
|
||||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
|
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
|
||||||
|
AK_VOL_CVT;
|
||||||
|
knew.tlv.p = db_scale_vol_datt;
|
||||||
break;
|
break;
|
||||||
case SND_AK4529: {
|
case SND_AK4529: {
|
||||||
/* registers 2-7 and b,c */
|
/* registers 2-7 and b,c */
|
||||||
int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
|
int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
|
||||||
ctl->private_value =
|
knew.private_value =
|
||||||
AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
|
AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
|
||||||
|
knew.tlv.p = db_scale_8bit;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SND_AK4355:
|
case SND_AK4355:
|
||||||
/* register 4-9, chip #0 only */
|
/* register 4-9, chip #0 only */
|
||||||
ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255);
|
knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
|
||||||
|
knew.tlv.p = db_scale_8bit;
|
||||||
break;
|
break;
|
||||||
case SND_AK4358:
|
case SND_AK4358: {
|
||||||
if (idx >= 6)
|
/* register 4-9 and 11-12, chip #0 only */
|
||||||
/* register 4-9, chip #0 only */
|
int addr = idx < 6 ? idx + 4 : idx + 5;
|
||||||
ctl->private_value =
|
knew.private_value =
|
||||||
AK_COMPOSE(0, idx + 5, 0, 255);
|
AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
|
||||||
else
|
knew.tlv.p = db_scale_7bit;
|
||||||
/* register 4-9, chip #0 only */
|
|
||||||
ctl->private_value =
|
|
||||||
AK_COMPOSE(0, idx + 4, 0, 255);
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SND_AK4381:
|
case SND_AK4381:
|
||||||
/* register 3 & 4 */
|
/* register 3 & 4 */
|
||||||
ctl->private_value =
|
knew.private_value =
|
||||||
AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
|
AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
|
||||||
|
knew.tlv.p = db_scale_linear;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
goto __error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl->private_data = ak;
|
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||||
err = snd_ctl_add(ak->card,
|
|
||||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
|
||||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto __error;
|
return err;
|
||||||
|
|
||||||
idx += num_stereo;
|
idx += num_stereo;
|
||||||
mixer_ch++;
|
mixer_ch++;
|
||||||
}
|
}
|
||||||
for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
|
return 0;
|
||||||
memset(ctl, 0, sizeof(*ctl));
|
|
||||||
strcpy(ctl->id.name, "ADC Volume");
|
|
||||||
ctl->id.index = idx + ak->idx_offset * 2;
|
|
||||||
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
|
||||||
ctl->count = 1;
|
|
||||||
ctl->info = snd_akm4xxx_volume_info;
|
|
||||||
ctl->get = snd_akm4xxx_volume_get;
|
|
||||||
ctl->put = snd_akm4xxx_volume_put;
|
|
||||||
/* register 4 & 5 */
|
|
||||||
ctl->private_value =
|
|
||||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127);
|
|
||||||
ctl->private_data = ak;
|
|
||||||
err = snd_ctl_add(ak->card,
|
|
||||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
|
||||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
|
||||||
if (err < 0)
|
|
||||||
goto __error;
|
|
||||||
|
|
||||||
memset(ctl, 0, sizeof(*ctl));
|
|
||||||
strcpy(ctl->id.name, "IPGA Analog Capture Volume");
|
|
||||||
ctl->id.index = idx + ak->idx_offset * 2;
|
|
||||||
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
|
||||||
ctl->count = 1;
|
|
||||||
ctl->info = snd_akm4xxx_ipga_gain_info;
|
|
||||||
ctl->get = snd_akm4xxx_ipga_gain_get;
|
|
||||||
ctl->put = snd_akm4xxx_ipga_gain_put;
|
|
||||||
/* register 4 & 5 */
|
|
||||||
ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0);
|
|
||||||
ctl->private_data = ak;
|
|
||||||
err = snd_ctl_add(ak->card,
|
|
||||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
|
||||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
|
||||||
if (err < 0)
|
|
||||||
goto __error;
|
|
||||||
}
|
}
|
||||||
if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
|
|
||||||
num_emphs = 1;
|
static int build_adc_controls(struct snd_akm4xxx *ak)
|
||||||
|
{
|
||||||
|
int idx, err, mixer_ch, num_stereo;
|
||||||
|
struct snd_kcontrol_new knew;
|
||||||
|
|
||||||
|
mixer_ch = 0;
|
||||||
|
for (idx = 0; idx < ak->num_adcs;) {
|
||||||
|
memset(&knew, 0, sizeof(knew));
|
||||||
|
if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
|
||||||
|
knew.name = "ADC Volume";
|
||||||
|
knew.index = mixer_ch + ak->idx_offset * 2;
|
||||||
|
num_stereo = 1;
|
||||||
|
} else {
|
||||||
|
knew.name = ak->adc_info[mixer_ch].name;
|
||||||
|
num_stereo = ak->adc_info[mixer_ch].num_channels;
|
||||||
|
}
|
||||||
|
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||||
|
knew.count = 1;
|
||||||
|
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||||
|
if (num_stereo == 2) {
|
||||||
|
knew.info = snd_akm4xxx_stereo_volume_info;
|
||||||
|
knew.get = snd_akm4xxx_stereo_volume_get;
|
||||||
|
knew.put = snd_akm4xxx_stereo_volume_put;
|
||||||
|
} else {
|
||||||
|
knew.info = snd_akm4xxx_volume_info;
|
||||||
|
knew.get = snd_akm4xxx_volume_get;
|
||||||
|
knew.put = snd_akm4xxx_volume_put;
|
||||||
|
}
|
||||||
|
/* register 4 & 5 */
|
||||||
|
if (ak->type == SND_AK5365)
|
||||||
|
knew.private_value =
|
||||||
|
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
|
||||||
|
AK_VOL_CVT | AK_IPGA;
|
||||||
else
|
else
|
||||||
num_emphs = ak->num_dacs / 2;
|
knew.private_value =
|
||||||
|
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
|
||||||
|
AK_VOL_CVT | AK_IPGA;
|
||||||
|
knew.tlv.p = db_scale_vol_datt;
|
||||||
|
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (ak->type == SND_AK5365 && (idx % 2) == 0) {
|
||||||
|
if (! ak->adc_info ||
|
||||||
|
! ak->adc_info[mixer_ch].switch_name)
|
||||||
|
knew.name = "Capture Switch";
|
||||||
|
else
|
||||||
|
knew.name = ak->adc_info[mixer_ch].switch_name;
|
||||||
|
knew.info = ak4xxx_switch_info;
|
||||||
|
knew.get = ak4xxx_switch_get;
|
||||||
|
knew.put = ak4xxx_switch_put;
|
||||||
|
knew.access = 0;
|
||||||
|
/* register 2, bit 0 (SMUTE): 0 = normal operation,
|
||||||
|
1 = mute */
|
||||||
|
knew.private_value =
|
||||||
|
AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
|
||||||
|
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx += num_stereo;
|
||||||
|
mixer_ch++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
|
||||||
|
{
|
||||||
|
int idx, err;
|
||||||
|
struct snd_kcontrol_new knew;
|
||||||
|
|
||||||
for (idx = 0; idx < num_emphs; idx++) {
|
for (idx = 0; idx < num_emphs; idx++) {
|
||||||
memset(ctl, 0, sizeof(*ctl));
|
memset(&knew, 0, sizeof(knew));
|
||||||
strcpy(ctl->id.name, "Deemphasis");
|
knew.name = "Deemphasis";
|
||||||
ctl->id.index = idx + ak->idx_offset;
|
knew.index = idx + ak->idx_offset;
|
||||||
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||||
ctl->count = 1;
|
knew.count = 1;
|
||||||
ctl->info = snd_akm4xxx_deemphasis_info;
|
knew.info = snd_akm4xxx_deemphasis_info;
|
||||||
ctl->get = snd_akm4xxx_deemphasis_get;
|
knew.get = snd_akm4xxx_deemphasis_get;
|
||||||
ctl->put = snd_akm4xxx_deemphasis_put;
|
knew.put = snd_akm4xxx_deemphasis_put;
|
||||||
switch (ak->type) {
|
switch (ak->type) {
|
||||||
case SND_AK4524:
|
case SND_AK4524:
|
||||||
case SND_AK4528:
|
case SND_AK4528:
|
||||||
/* register 3 */
|
/* register 3 */
|
||||||
ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
|
knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
|
||||||
break;
|
break;
|
||||||
case SND_AK4529: {
|
case SND_AK4529: {
|
||||||
int shift = idx == 3 ? 6 : (2 - idx) * 2;
|
int shift = idx == 3 ? 6 : (2 - idx) * 2;
|
||||||
/* register 8 with shift */
|
/* register 8 with shift */
|
||||||
ctl->private_value = AK_COMPOSE(0, 8, shift, 0);
|
knew.private_value = AK_COMPOSE(0, 8, shift, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SND_AK4355:
|
case SND_AK4355:
|
||||||
case SND_AK4358:
|
case SND_AK4358:
|
||||||
ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
|
knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
|
||||||
break;
|
break;
|
||||||
case SND_AK4381:
|
case SND_AK4381:
|
||||||
ctl->private_value = AK_COMPOSE(idx, 1, 1, 0);
|
knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
ctl->private_data = ak;
|
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||||
err = snd_ctl_add(ak->card,
|
|
||||||
snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|
|
|
||||||
SNDRV_CTL_ELEM_ACCESS_WRITE));
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
__error:
|
|
||||||
kfree(ctl);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
||||||
|
{
|
||||||
|
int err, num_emphs;
|
||||||
|
|
||||||
|
err = build_dac_controls(ak);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = build_adc_controls(ak);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
|
||||||
|
num_emphs = 1;
|
||||||
|
else
|
||||||
|
num_emphs = ak->num_dacs / 2;
|
||||||
|
err = build_deemphasis(ak, num_emphs);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
|
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ad1816a.h>
|
#include <sound/ad1816a.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
@ -765,6 +766,13 @@ static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define AD1816A_SINGLE_TLV(xname, reg, shift, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .info = snd_ad1816a_info_single, \
|
||||||
|
.get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
|
||||||
|
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
#define AD1816A_SINGLE(xname, reg, shift, mask, invert) \
|
#define AD1816A_SINGLE(xname, reg, shift, mask, invert) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \
|
||||||
.get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
|
.get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \
|
||||||
|
@ -822,6 +830,14 @@ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define AD1816A_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .info = snd_ad1816a_info_double, \
|
||||||
|
.get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
|
||||||
|
.private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
|
|
||||||
#define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
|
#define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \
|
||||||
.get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
|
.get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \
|
||||||
|
@ -890,28 +906,44 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
|
static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
|
||||||
AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1),
|
AD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1,
|
||||||
|
db_scale_5bit),
|
||||||
AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1),
|
AD1816A_DOUBLE_TLV("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1,
|
||||||
|
db_scale_6bit),
|
||||||
AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1),
|
AD1816A_DOUBLE_TLV("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1),
|
AD1816A_DOUBLE_TLV("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1),
|
AD1816A_DOUBLE_TLV("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1),
|
AD1816A_DOUBLE_TLV("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1,
|
||||||
|
db_scale_6bit),
|
||||||
AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
|
AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
|
||||||
AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1),
|
AD1816A_SINGLE_TLV("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
|
AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
|
||||||
AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
|
AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1),
|
AD1816A_DOUBLE_TLV("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1),
|
AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1),
|
||||||
AD1816A_SINGLE("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1),
|
AD1816A_SINGLE_TLV("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1,
|
||||||
|
db_scale_4bit),
|
||||||
AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1),
|
AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1),
|
||||||
AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1),
|
AD1816A_SINGLE_TLV("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1,
|
||||||
|
db_scale_5bit),
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
.name = "Capture Source",
|
.name = "Capture Source",
|
||||||
|
@ -920,7 +952,8 @@ AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1),
|
||||||
.put = snd_ad1816a_put_mux,
|
.put = snd_ad1816a_put_mux,
|
||||||
},
|
},
|
||||||
AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1),
|
AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1),
|
||||||
AD1816A_DOUBLE("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0),
|
AD1816A_DOUBLE_TLV("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0,
|
||||||
|
db_scale_rec_gain),
|
||||||
AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1),
|
AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1),
|
||||||
AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0),
|
AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0),
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/ad1848.h>
|
#include <sound/ad1848.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
@ -118,6 +119,8 @@ void snd_ad1848_out(struct snd_ad1848 *chip,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ad1848_out);
|
||||||
|
|
||||||
static void snd_ad1848_dout(struct snd_ad1848 *chip,
|
static void snd_ad1848_dout(struct snd_ad1848 *chip,
|
||||||
unsigned char reg, unsigned char value)
|
unsigned char reg, unsigned char value)
|
||||||
{
|
{
|
||||||
|
@ -941,6 +944,8 @@ int snd_ad1848_create(struct snd_card *card,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ad1848_create);
|
||||||
|
|
||||||
static struct snd_pcm_ops snd_ad1848_playback_ops = {
|
static struct snd_pcm_ops snd_ad1848_playback_ops = {
|
||||||
.open = snd_ad1848_playback_open,
|
.open = snd_ad1848_playback_open,
|
||||||
.close = snd_ad1848_playback_close,
|
.close = snd_ad1848_playback_close,
|
||||||
|
@ -988,12 +993,16 @@ int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ad1848_pcm);
|
||||||
|
|
||||||
const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
|
const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
|
||||||
{
|
{
|
||||||
return direction == SNDRV_PCM_STREAM_PLAYBACK ?
|
return direction == SNDRV_PCM_STREAM_PLAYBACK ?
|
||||||
&snd_ad1848_playback_ops : &snd_ad1848_capture_ops;
|
&snd_ad1848_playback_ops : &snd_ad1848_capture_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIXER part
|
* MIXER part
|
||||||
*/
|
*/
|
||||||
|
@ -1171,7 +1180,8 @@ static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value)
|
int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip,
|
||||||
|
const struct ad1848_mix_elem *c)
|
||||||
{
|
{
|
||||||
static struct snd_kcontrol_new newctls[] = {
|
static struct snd_kcontrol_new newctls[] = {
|
||||||
[AD1848_MIX_SINGLE] = {
|
[AD1848_MIX_SINGLE] = {
|
||||||
|
@ -1196,32 +1206,46 @@ int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int
|
||||||
struct snd_kcontrol *ctl;
|
struct snd_kcontrol *ctl;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ctl = snd_ctl_new1(&newctls[type], chip);
|
ctl = snd_ctl_new1(&newctls[c->type], chip);
|
||||||
if (! ctl)
|
if (! ctl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
|
strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name));
|
||||||
ctl->id.index = index;
|
ctl->id.index = c->index;
|
||||||
ctl->private_value = value;
|
ctl->private_value = c->private_value;
|
||||||
|
if (c->tlv) {
|
||||||
|
ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||||
|
ctl->tlv.p = c->tlv;
|
||||||
|
}
|
||||||
if ((err = snd_ctl_add(chip->card, ctl)) < 0)
|
if ((err = snd_ctl_add(chip->card, ctl)) < 0)
|
||||||
return err;
|
return err;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||||
|
|
||||||
static struct ad1848_mix_elem snd_ad1848_controls[] = {
|
static struct ad1848_mix_elem snd_ad1848_controls[] = {
|
||||||
AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
|
AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||||
AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
|
AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||||
|
db_scale_6bit),
|
||||||
AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||||
AD1848_DOUBLE("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
|
AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||||
AD1848_DOUBLE("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
|
AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||||
AD1848_DOUBLE("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0),
|
db_scale_5bit_12db_max),
|
||||||
|
AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0,
|
||||||
|
db_scale_rec_gain),
|
||||||
{
|
{
|
||||||
.name = "Capture Source",
|
.name = "Capture Source",
|
||||||
.type = AD1848_MIX_CAPTURE,
|
.type = AD1848_MIX_CAPTURE,
|
||||||
},
|
},
|
||||||
AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
|
AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
|
||||||
AD1848_SINGLE("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0)
|
AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0,
|
||||||
|
db_scale_6bit),
|
||||||
};
|
};
|
||||||
|
|
||||||
int snd_ad1848_mixer(struct snd_ad1848 *chip)
|
int snd_ad1848_mixer(struct snd_ad1848 *chip)
|
||||||
|
@ -1245,12 +1269,7 @@ int snd_ad1848_mixer(struct snd_ad1848 *chip)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_ad1848_out);
|
|
||||||
EXPORT_SYMBOL(snd_ad1848_create);
|
|
||||||
EXPORT_SYMBOL(snd_ad1848_pcm);
|
|
||||||
EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
|
|
||||||
EXPORT_SYMBOL(snd_ad1848_mixer);
|
EXPORT_SYMBOL(snd_ad1848_mixer);
|
||||||
EXPORT_SYMBOL(snd_ad1848_add_ctl);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* INIT part
|
* INIT part
|
||||||
|
|
|
@ -2038,7 +2038,80 @@ MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver.");
|
||||||
static struct platform_device *platform_devices[SNDRV_CARDS];
|
static struct platform_device *platform_devices[SNDRV_CARDS];
|
||||||
|
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
static int pnp_registered;
|
static int pnp_registered, pnpc_registered;
|
||||||
|
|
||||||
|
static struct pnp_device_id snd_audiodrive_pnpbiosids[] = {
|
||||||
|
{ .id = "ESS1869" },
|
||||||
|
{ .id = "" } /* end */
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);
|
||||||
|
|
||||||
|
/* PnP main device initialization */
|
||||||
|
static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev,
|
||||||
|
struct pnp_resource_table *cfg)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
pnp_init_resource_table(cfg);
|
||||||
|
if (port[dev] != SNDRV_AUTO_PORT)
|
||||||
|
pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
|
||||||
|
if (fm_port[dev] != SNDRV_AUTO_PORT)
|
||||||
|
pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
|
||||||
|
if (mpu_port[dev] != SNDRV_AUTO_PORT)
|
||||||
|
pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
|
||||||
|
if (dma1[dev] != SNDRV_AUTO_DMA)
|
||||||
|
pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
|
||||||
|
if (dma2[dev] != SNDRV_AUTO_DMA)
|
||||||
|
pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
|
||||||
|
if (irq[dev] != SNDRV_AUTO_IRQ)
|
||||||
|
pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
|
||||||
|
if (pnp_device_is_isapnp(pdev)) {
|
||||||
|
err = pnp_manual_config_dev(pdev, cfg, 0);
|
||||||
|
if (err < 0)
|
||||||
|
snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
|
||||||
|
}
|
||||||
|
err = pnp_activate_dev(pdev);
|
||||||
|
if (err < 0) {
|
||||||
|
snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
/* ok. hack using Vendor-Defined Card-Level registers */
|
||||||
|
/* skip csn and logdev initialization - already done in isapnp_configure */
|
||||||
|
if (pnp_device_is_isapnp(pdev)) {
|
||||||
|
isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
|
||||||
|
isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */
|
||||||
|
if (mpu_port[dev] != SNDRV_AUTO_PORT)
|
||||||
|
isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
|
||||||
|
isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */
|
||||||
|
isapnp_cfg_end();
|
||||||
|
}
|
||||||
|
port[dev] = pnp_port_start(pdev, 0);
|
||||||
|
fm_port[dev] = pnp_port_start(pdev, 1);
|
||||||
|
mpu_port[dev] = pnp_port_start(pdev, 2);
|
||||||
|
dma1[dev] = pnp_dma(pdev, 0);
|
||||||
|
dma2[dev] = pnp_dma(pdev, 1);
|
||||||
|
irq[dev] = pnp_irq(pdev, 0);
|
||||||
|
snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
|
||||||
|
snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
|
||||||
|
struct pnp_dev *pdev)
|
||||||
|
{
|
||||||
|
struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!cfg)
|
||||||
|
return -ENOMEM;
|
||||||
|
acard->dev = pdev;
|
||||||
|
if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) {
|
||||||
|
kfree(cfg);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
kfree(cfg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
|
static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
|
||||||
/* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */
|
/* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */
|
||||||
|
@ -2061,13 +2134,11 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
|
MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
|
||||||
|
|
||||||
static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
|
static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
|
||||||
struct pnp_card_link *card,
|
struct pnp_card_link *card,
|
||||||
const struct pnp_card_device_id *id)
|
const struct pnp_card_device_id *id)
|
||||||
{
|
{
|
||||||
struct pnp_dev *pdev;
|
|
||||||
struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
|
struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!cfg)
|
if (!cfg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -2082,58 +2153,16 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
/* Control port initialization */
|
/* Control port initialization */
|
||||||
err = pnp_activate_dev(acard->devc);
|
if (pnp_activate_dev(acard->devc) < 0) {
|
||||||
if (err < 0) {
|
|
||||||
snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
|
snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
|
||||||
kfree(cfg);
|
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
snd_printdd("pnp: port=0x%llx\n",
|
snd_printdd("pnp: port=0x%llx\n",
|
||||||
(unsigned long long)pnp_port_start(acard->devc, 0));
|
(unsigned long long)pnp_port_start(acard->devc, 0));
|
||||||
/* PnP initialization */
|
if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) {
|
||||||
pdev = acard->dev;
|
|
||||||
pnp_init_resource_table(cfg);
|
|
||||||
if (port[dev] != SNDRV_AUTO_PORT)
|
|
||||||
pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
|
|
||||||
if (fm_port[dev] != SNDRV_AUTO_PORT)
|
|
||||||
pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
|
|
||||||
if (mpu_port[dev] != SNDRV_AUTO_PORT)
|
|
||||||
pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
|
|
||||||
if (dma1[dev] != SNDRV_AUTO_DMA)
|
|
||||||
pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
|
|
||||||
if (dma2[dev] != SNDRV_AUTO_DMA)
|
|
||||||
pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
|
|
||||||
if (irq[dev] != SNDRV_AUTO_IRQ)
|
|
||||||
pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
|
|
||||||
err = pnp_manual_config_dev(pdev, cfg, 0);
|
|
||||||
if (err < 0)
|
|
||||||
snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
|
|
||||||
err = pnp_activate_dev(pdev);
|
|
||||||
if (err < 0) {
|
|
||||||
snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
|
|
||||||
kfree(cfg);
|
kfree(cfg);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
/* ok. hack using Vendor-Defined Card-Level registers */
|
|
||||||
/* skip csn and logdev initialization - already done in isapnp_configure */
|
|
||||||
if (pnp_device_is_isapnp(pdev)) {
|
|
||||||
isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev));
|
|
||||||
isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */
|
|
||||||
if (mpu_port[dev] != SNDRV_AUTO_PORT)
|
|
||||||
isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */
|
|
||||||
isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */
|
|
||||||
isapnp_cfg_end();
|
|
||||||
} else {
|
|
||||||
snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n");
|
|
||||||
}
|
|
||||||
port[dev] = pnp_port_start(pdev, 0);
|
|
||||||
fm_port[dev] = pnp_port_start(pdev, 1);
|
|
||||||
mpu_port[dev] = pnp_port_start(pdev, 2);
|
|
||||||
dma1[dev] = pnp_dma(pdev, 0);
|
|
||||||
dma2[dev] = pnp_dma(pdev, 1);
|
|
||||||
irq[dev] = pnp_irq(pdev, 0);
|
|
||||||
snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
|
|
||||||
snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
|
|
||||||
kfree(cfg);
|
kfree(cfg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2302,7 +2331,69 @@ static struct platform_driver snd_es18xx_nonpnp_driver = {
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
static unsigned int __devinitdata es18xx_pnp_devices;
|
static unsigned int __devinitdata es18xx_pnp_devices;
|
||||||
|
|
||||||
static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
|
static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
|
||||||
|
const struct pnp_device_id *id)
|
||||||
|
{
|
||||||
|
static int dev;
|
||||||
|
int err;
|
||||||
|
struct snd_card *card;
|
||||||
|
|
||||||
|
if (pnp_device_is_isapnp(pdev))
|
||||||
|
return -ENOENT; /* we have another procedure - card */
|
||||||
|
for (; dev < SNDRV_CARDS; dev++) {
|
||||||
|
if (enable[dev] && isapnp[dev])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dev >= SNDRV_CARDS)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
card = snd_es18xx_card_new(dev);
|
||||||
|
if (! card)
|
||||||
|
return -ENOMEM;
|
||||||
|
if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
|
||||||
|
snd_card_free(card);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
snd_card_set_dev(card, &pdev->dev);
|
||||||
|
if ((err = snd_audiodrive_probe(card, dev)) < 0) {
|
||||||
|
snd_card_free(card);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
pnp_set_drvdata(pdev, card);
|
||||||
|
dev++;
|
||||||
|
es18xx_pnp_devices++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev)
|
||||||
|
{
|
||||||
|
snd_card_free(pnp_get_drvdata(pdev));
|
||||||
|
pnp_set_drvdata(pdev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
|
||||||
|
{
|
||||||
|
return snd_es18xx_suspend(pnp_get_drvdata(pdev), state);
|
||||||
|
}
|
||||||
|
static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev)
|
||||||
|
{
|
||||||
|
return snd_es18xx_resume(pnp_get_drvdata(pdev));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct pnp_driver es18xx_pnp_driver = {
|
||||||
|
.name = "es18xx-pnpbios",
|
||||||
|
.id_table = snd_audiodrive_pnpbiosids,
|
||||||
|
.probe = snd_audiodrive_pnp_detect,
|
||||||
|
.remove = __devexit_p(snd_audiodrive_pnp_remove),
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.suspend = snd_audiodrive_pnp_suspend,
|
||||||
|
.resume = snd_audiodrive_pnp_resume,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
|
||||||
const struct pnp_card_device_id *pid)
|
const struct pnp_card_device_id *pid)
|
||||||
{
|
{
|
||||||
static int dev;
|
static int dev;
|
||||||
|
@ -2320,7 +2411,7 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
|
||||||
if (! card)
|
if (! card)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) {
|
if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
|
||||||
snd_card_free(card);
|
snd_card_free(card);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -2336,19 +2427,19 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard)
|
static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard)
|
||||||
{
|
{
|
||||||
snd_card_free(pnp_get_card_drvdata(pcard));
|
snd_card_free(pnp_get_card_drvdata(pcard));
|
||||||
pnp_set_card_drvdata(pcard, NULL);
|
pnp_set_card_drvdata(pcard, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
|
static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
|
||||||
{
|
{
|
||||||
return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state);
|
return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard)
|
static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard)
|
||||||
{
|
{
|
||||||
return snd_es18xx_resume(pnp_get_card_drvdata(pcard));
|
return snd_es18xx_resume(pnp_get_card_drvdata(pcard));
|
||||||
}
|
}
|
||||||
|
@ -2359,11 +2450,11 @@ static struct pnp_card_driver es18xx_pnpc_driver = {
|
||||||
.flags = PNP_DRIVER_RES_DISABLE,
|
.flags = PNP_DRIVER_RES_DISABLE,
|
||||||
.name = "es18xx",
|
.name = "es18xx",
|
||||||
.id_table = snd_audiodrive_pnpids,
|
.id_table = snd_audiodrive_pnpids,
|
||||||
.probe = snd_audiodrive_pnp_detect,
|
.probe = snd_audiodrive_pnpc_detect,
|
||||||
.remove = __devexit_p(snd_audiodrive_pnp_remove),
|
.remove = __devexit_p(snd_audiodrive_pnpc_remove),
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.suspend = snd_audiodrive_pnp_suspend,
|
.suspend = snd_audiodrive_pnpc_suspend,
|
||||||
.resume = snd_audiodrive_pnp_resume,
|
.resume = snd_audiodrive_pnpc_resume,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_PNP */
|
#endif /* CONFIG_PNP */
|
||||||
|
@ -2373,8 +2464,10 @@ static void __init_or_module snd_es18xx_unregister_all(void)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
if (pnp_registered)
|
if (pnpc_registered)
|
||||||
pnp_unregister_card_driver(&es18xx_pnpc_driver);
|
pnp_unregister_card_driver(&es18xx_pnpc_driver);
|
||||||
|
if (pnp_registered)
|
||||||
|
pnp_unregister_driver(&es18xx_pnp_driver);
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
|
for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
|
||||||
platform_device_unregister(platform_devices[i]);
|
platform_device_unregister(platform_devices[i]);
|
||||||
|
@ -2405,11 +2498,13 @@ static int __init alsa_card_es18xx_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
err = pnp_register_card_driver(&es18xx_pnpc_driver);
|
err = pnp_register_driver(&es18xx_pnp_driver);
|
||||||
if (!err) {
|
if (!err)
|
||||||
pnp_registered = 1;
|
pnp_registered = 1;
|
||||||
|
err = pnp_register_card_driver(&es18xx_pnpc_driver);
|
||||||
|
if (!err)
|
||||||
|
pnpc_registered = 1;
|
||||||
cards += es18xx_pnp_devices;
|
cards += es18xx_pnp_devices;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!cards) {
|
if(!cards) {
|
||||||
|
|
|
@ -61,13 +61,13 @@ static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
|
||||||
struct gus_proc_private *priv = entry->private_data;
|
struct gus_proc_private *priv = entry->private_data;
|
||||||
|
|
||||||
switch (orig) {
|
switch (orig) {
|
||||||
case 0: /* SEEK_SET */
|
case SEEK_SET:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
break;
|
break;
|
||||||
case 1: /* SEEK_CUR */
|
case SEEK_CUR:
|
||||||
file->f_pos += offset;
|
file->f_pos += offset;
|
||||||
break;
|
break;
|
||||||
case 2: /* SEEK_END, offset is negative */
|
case SEEK_END: /* offset is negative */
|
||||||
file->f_pos = priv->size + offset;
|
file->f_pos = priv->size + offset;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <sound/mpu401.h>
|
#include <sound/mpu401.h>
|
||||||
#include <sound/opl3.h>
|
#include <sound/opl3.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
@ -337,6 +338,14 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *
|
||||||
.info = snd_opl3sa2_info_single, \
|
.info = snd_opl3sa2_info_single, \
|
||||||
.get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
|
.get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
|
||||||
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
|
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
|
||||||
|
#define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
|
.info = snd_opl3sa2_info_single, \
|
||||||
|
.get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \
|
||||||
|
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
|
|
||||||
static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
@ -395,6 +404,14 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||||
.info = snd_opl3sa2_info_double, \
|
.info = snd_opl3sa2_info_double, \
|
||||||
.get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
|
.get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
|
||||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
|
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
|
||||||
|
#define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
|
.info = snd_opl3sa2_info_double, \
|
||||||
|
.get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \
|
||||||
|
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
|
|
||||||
static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
@ -469,11 +486,16 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
|
static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
|
||||||
OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),
|
OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),
|
||||||
OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1),
|
OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1,
|
||||||
|
db_scale_master),
|
||||||
OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1),
|
OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1),
|
||||||
OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1)
|
OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1,
|
||||||
|
db_scale_5bit_12db_max),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = {
|
static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = {
|
||||||
|
|
|
@ -475,6 +475,7 @@ config SND_FM801_TEA575X
|
||||||
depends on SND_FM801_TEA575X_BOOL
|
depends on SND_FM801_TEA575X_BOOL
|
||||||
default SND_FM801
|
default SND_FM801
|
||||||
select VIDEO_V4L1
|
select VIDEO_V4L1
|
||||||
|
select VIDEO_DEV
|
||||||
|
|
||||||
config SND_HDA_INTEL
|
config SND_HDA_INTEL
|
||||||
tristate "Intel HD Audio"
|
tristate "Intel HD Audio"
|
||||||
|
@ -743,4 +744,17 @@ config SND_YMFPCI
|
||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called snd-ymfpci.
|
will be called snd-ymfpci.
|
||||||
|
|
||||||
|
config SND_AC97_POWER_SAVE
|
||||||
|
bool "AC97 Power-Saving Mode"
|
||||||
|
depends on SND_AC97_CODEC && EXPERIMENTAL
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Say Y here to enable the aggressive power-saving support of
|
||||||
|
AC97 codecs. In this mode, the power-mode is dynamically
|
||||||
|
controlled at each open/close.
|
||||||
|
|
||||||
|
The mode is activated by passing power_save=1 option to
|
||||||
|
snd-ac97-codec driver. You can toggle it dynamically over
|
||||||
|
sysfs, too.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
@ -47,6 +48,11 @@ static int enable_loopback;
|
||||||
module_param(enable_loopback, bool, 0444);
|
module_param(enable_loopback, bool, 0444);
|
||||||
MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
|
MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
static int power_save;
|
||||||
|
module_param(power_save, bool, 0644);
|
||||||
|
MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -151,7 +157,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
|
||||||
{ 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk
|
{ 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk
|
||||||
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
|
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
|
||||||
{ 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix
|
{ 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix
|
||||||
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
|
{ 0x50534304, 0xffffffff, "UCB1400", patch_ucb1400, NULL },
|
||||||
{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH },
|
{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH },
|
||||||
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
|
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
|
||||||
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
|
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
|
||||||
|
@ -187,6 +193,8 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void update_power_regs(struct snd_ac97 *ac97);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I/O routines
|
* I/O routines
|
||||||
*/
|
*/
|
||||||
|
@ -554,6 +562,18 @@ int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
|
||||||
}
|
}
|
||||||
err = snd_ac97_update_bits(ac97, reg, val_mask, val);
|
err = snd_ac97_update_bits(ac97, reg, val_mask, val);
|
||||||
snd_ac97_page_restore(ac97, page_save);
|
snd_ac97_page_restore(ac97, page_save);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
/* check analog mixer power-down */
|
||||||
|
if ((val_mask & 0x8000) &&
|
||||||
|
(kcontrol->private_value & (1<<30))) {
|
||||||
|
if (val & 0x8000)
|
||||||
|
ac97->power_up &= ~(1 << (reg>>1));
|
||||||
|
else
|
||||||
|
ac97->power_up |= 1 << (reg>>1);
|
||||||
|
if (power_save)
|
||||||
|
update_power_regs(ac97);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,6 +982,10 @@ static int snd_ac97_bus_dev_free(struct snd_device *device)
|
||||||
static int snd_ac97_free(struct snd_ac97 *ac97)
|
static int snd_ac97_free(struct snd_ac97 *ac97)
|
||||||
{
|
{
|
||||||
if (ac97) {
|
if (ac97) {
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
if (ac97->power_workq)
|
||||||
|
destroy_workqueue(ac97->power_workq);
|
||||||
|
#endif
|
||||||
snd_ac97_proc_done(ac97);
|
snd_ac97_proc_done(ac97);
|
||||||
if (ac97->bus)
|
if (ac97->bus)
|
||||||
ac97->bus->codec[ac97->num] = NULL;
|
ac97->bus->codec[ac97->num] = NULL;
|
||||||
|
@ -1117,7 +1141,9 @@ struct snd_kcontrol *snd_ac97_cnew(const struct snd_kcontrol_new *_template, str
|
||||||
/*
|
/*
|
||||||
* create mute switch(es) for normal stereo controls
|
* create mute switch(es) for normal stereo controls
|
||||||
*/
|
*/
|
||||||
static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97)
|
static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
|
||||||
|
int check_stereo, int check_amix,
|
||||||
|
struct snd_ac97 *ac97)
|
||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
int err;
|
int err;
|
||||||
|
@ -1137,10 +1163,14 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
|
||||||
}
|
}
|
||||||
if (mute_mask == 0x8080) {
|
if (mute_mask == 0x8080) {
|
||||||
struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
|
struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
|
||||||
|
if (check_amix)
|
||||||
|
tmp.private_value |= (1 << 30);
|
||||||
tmp.index = ac97->num;
|
tmp.index = ac97->num;
|
||||||
kctl = snd_ctl_new1(&tmp, ac97);
|
kctl = snd_ctl_new1(&tmp, ac97);
|
||||||
} else {
|
} else {
|
||||||
struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1);
|
struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1);
|
||||||
|
if (check_amix)
|
||||||
|
tmp.private_value |= (1 << 30);
|
||||||
tmp.index = ac97->num;
|
tmp.index = ac97->num;
|
||||||
kctl = snd_ctl_new1(&tmp, ac97);
|
kctl = snd_ctl_new1(&tmp, ac97);
|
||||||
}
|
}
|
||||||
|
@ -1152,6 +1182,32 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set dB information
|
||||||
|
*/
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||||
|
|
||||||
|
static unsigned int *find_db_scale(unsigned int maxval)
|
||||||
|
{
|
||||||
|
switch (maxval) {
|
||||||
|
case 0x0f: return db_scale_4bit;
|
||||||
|
case 0x1f: return db_scale_5bit;
|
||||||
|
case 0x3f: return db_scale_6bit;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
|
||||||
|
{
|
||||||
|
kctl->tlv.p = tlv;
|
||||||
|
if (tlv)
|
||||||
|
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a volume for normal stereo/mono controls
|
* create a volume for normal stereo/mono controls
|
||||||
*/
|
*/
|
||||||
|
@ -1174,6 +1230,10 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne
|
||||||
tmp.index = ac97->num;
|
tmp.index = ac97->num;
|
||||||
kctl = snd_ctl_new1(&tmp, ac97);
|
kctl = snd_ctl_new1(&tmp, ac97);
|
||||||
}
|
}
|
||||||
|
if (reg >= AC97_PHONE && reg <= AC97_PCM)
|
||||||
|
set_tlv_db_scale(kctl, db_scale_5bit_12db_max);
|
||||||
|
else
|
||||||
|
set_tlv_db_scale(kctl, find_db_scale(lo_max));
|
||||||
err = snd_ctl_add(card, kctl);
|
err = snd_ctl_add(card, kctl);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -1186,7 +1246,9 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne
|
||||||
/*
|
/*
|
||||||
* create a mute-switch and a volume for normal stereo/mono controls
|
* create a mute-switch and a volume for normal stereo/mono controls
|
||||||
*/
|
*/
|
||||||
static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97)
|
static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
|
||||||
|
int reg, int check_stereo, int check_amix,
|
||||||
|
struct snd_ac97 *ac97)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char name[44];
|
char name[44];
|
||||||
|
@ -1197,7 +1259,9 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int
|
||||||
|
|
||||||
if (snd_ac97_try_bit(ac97, reg, 15)) {
|
if (snd_ac97_try_bit(ac97, reg, 15)) {
|
||||||
sprintf(name, "%s Switch", pfx);
|
sprintf(name, "%s Switch", pfx);
|
||||||
if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0)
|
if ((err = snd_ac97_cmute_new_stereo(card, name, reg,
|
||||||
|
check_stereo, check_amix,
|
||||||
|
ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
check_volume_resolution(ac97, reg, &lo_max, &hi_max);
|
check_volume_resolution(ac97, reg, &lo_max, &hi_max);
|
||||||
|
@ -1209,8 +1273,10 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97)
|
#define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \
|
||||||
#define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97)
|
snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97)
|
||||||
|
#define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \
|
||||||
|
snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97)
|
||||||
|
|
||||||
static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
|
static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);
|
||||||
|
|
||||||
|
@ -1226,9 +1292,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
|
/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
|
||||||
if (ac97->flags & AC97_HAS_NO_MASTER_VOL)
|
if (ac97->flags & AC97_HAS_NO_MASTER_VOL)
|
||||||
err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97);
|
err = snd_ac97_cmute_new(card, "Master Playback Switch",
|
||||||
|
AC97_MASTER, 0, ac97);
|
||||||
else
|
else
|
||||||
err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97);
|
err = snd_ac97_cmix_new(card, "Master Playback",
|
||||||
|
AC97_MASTER, 0, ac97);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1245,6 +1313,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max);
|
snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max);
|
||||||
kctl->private_value &= ~(0xff << 16);
|
kctl->private_value &= ~(0xff << 16);
|
||||||
kctl->private_value |= (int)max << 16;
|
kctl->private_value |= (int)max << 16;
|
||||||
|
set_tlv_db_scale(kctl, find_db_scale(max));
|
||||||
snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max);
|
snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,6 +1327,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max);
|
snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max);
|
||||||
kctl->private_value &= ~(0xff << 16);
|
kctl->private_value &= ~(0xff << 16);
|
||||||
kctl->private_value |= (int)max << 16;
|
kctl->private_value |= (int)max << 16;
|
||||||
|
set_tlv_db_scale(kctl, find_db_scale(max));
|
||||||
snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8);
|
snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1265,19 +1335,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
|
if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER))
|
||||||
&& !(ac97->flags & AC97_AD_MULTI)) {
|
&& !(ac97->flags & AC97_AD_MULTI)) {
|
||||||
/* Surround Master (0x38) is with stereo mutes */
|
/* Surround Master (0x38) is with stereo mutes */
|
||||||
if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback",
|
||||||
|
AC97_SURROUND_MASTER, 1, 0,
|
||||||
|
ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build headphone controls */
|
/* build headphone controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Headphone Playback",
|
||||||
|
AC97_HEADPHONE, 0, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build master mono controls */
|
/* build master mono controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Master Mono Playback",
|
||||||
|
AC97_MASTER_MONO, 0, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1301,8 +1375,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
((ac97->flags & AC97_HAS_PC_BEEP) ||
|
((ac97->flags & AC97_HAS_PC_BEEP) ||
|
||||||
snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) {
|
snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) {
|
||||||
for (idx = 0; idx < 2; idx++)
|
for (idx = 0; idx < 2; idx++)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_4bit);
|
||||||
snd_ac97_write_cache(ac97, AC97_PC_BEEP,
|
snd_ac97_write_cache(ac97, AC97_PC_BEEP,
|
||||||
snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e);
|
snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e);
|
||||||
}
|
}
|
||||||
|
@ -1310,7 +1385,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
/* build Phone controls */
|
/* build Phone controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
|
if (!(ac97->flags & AC97_HAS_NO_PHONE)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Phone Playback",
|
||||||
|
AC97_PHONE, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1318,7 +1394,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
/* build MIC controls */
|
/* build MIC controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_MIC)) {
|
if (!(ac97->flags & AC97_HAS_NO_MIC)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Mic Playback",
|
||||||
|
AC97_MIC, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -1327,14 +1404,16 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
|
|
||||||
/* build Line controls */
|
/* build Line controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Line Playback",
|
||||||
|
AC97_LINE, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build CD controls */
|
/* build CD controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_CD)) {
|
if (!(ac97->flags & AC97_HAS_NO_CD)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "CD Playback",
|
||||||
|
AC97_CD, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1342,7 +1421,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
/* build Video controls */
|
/* build Video controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
|
if (!(ac97->flags & AC97_HAS_NO_VIDEO)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Video Playback",
|
||||||
|
AC97_VIDEO, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1350,7 +1430,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
/* build Aux controls */
|
/* build Aux controls */
|
||||||
if (!(ac97->flags & AC97_HAS_NO_AUX)) {
|
if (!(ac97->flags & AC97_HAS_NO_AUX)) {
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
|
||||||
if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
|
if ((err = snd_ac97_cmix_new(card, "Aux Playback",
|
||||||
|
AC97_AUX, 1, ac97)) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1363,31 +1444,38 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
else
|
else
|
||||||
init_val = 0x9f1f;
|
init_val = 0x9f1f;
|
||||||
for (idx = 0; idx < 2; idx++)
|
for (idx = 0; idx < 2; idx++)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_5bit);
|
||||||
ac97->spec.ad18xx.pcmreg[0] = init_val;
|
ac97->spec.ad18xx.pcmreg[0] = init_val;
|
||||||
if (ac97->scaps & AC97_SCAP_SURROUND_DAC) {
|
if (ac97->scaps & AC97_SCAP_SURROUND_DAC) {
|
||||||
for (idx = 0; idx < 2; idx++)
|
for (idx = 0; idx < 2; idx++)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_5bit);
|
||||||
ac97->spec.ad18xx.pcmreg[1] = init_val;
|
ac97->spec.ad18xx.pcmreg[1] = init_val;
|
||||||
}
|
}
|
||||||
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) {
|
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) {
|
||||||
for (idx = 0; idx < 2; idx++)
|
for (idx = 0; idx < 2; idx++)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_5bit);
|
||||||
for (idx = 0; idx < 2; idx++)
|
for (idx = 0; idx < 2; idx++)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_5bit);
|
||||||
ac97->spec.ad18xx.pcmreg[2] = init_val;
|
ac97->spec.ad18xx.pcmreg[2] = init_val;
|
||||||
}
|
}
|
||||||
snd_ac97_write_cache(ac97, AC97_PCM, init_val);
|
snd_ac97_write_cache(ac97, AC97_PCM, init_val);
|
||||||
} else {
|
} else {
|
||||||
if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
|
if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
|
||||||
if (ac97->flags & AC97_HAS_NO_PCM_VOL)
|
if (ac97->flags & AC97_HAS_NO_PCM_VOL)
|
||||||
err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
|
err = snd_ac97_cmute_new(card,
|
||||||
|
"PCM Playback Switch",
|
||||||
|
AC97_PCM, 0, ac97);
|
||||||
else
|
else
|
||||||
err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
|
err = snd_ac97_cmix_new(card, "PCM Playback",
|
||||||
|
AC97_PCM, 0, ac97);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1398,19 +1486,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
|
if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) {
|
||||||
if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0)
|
err = snd_ac97_cmute_new(card, "Capture Switch",
|
||||||
|
AC97_REC_GAIN, 0, ac97);
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_rec_gain);
|
||||||
snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);
|
snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);
|
||||||
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);
|
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);
|
||||||
}
|
}
|
||||||
/* build MIC Capture controls */
|
/* build MIC Capture controls */
|
||||||
if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) {
|
if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) {
|
||||||
for (idx = 0; idx < 2; idx++)
|
for (idx = 0; idx < 2; idx++)
|
||||||
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0)
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
set_tlv_db_scale(kctl, db_scale_rec_gain);
|
||||||
snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000);
|
snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1481,6 +1573,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build S/PDIF controls */
|
/* build S/PDIF controls */
|
||||||
|
|
||||||
|
/* Hack for ASUS P5P800-VM, which does not indicate S/PDIF capability */
|
||||||
|
if (ac97->subsystem_vendor == 0x1043 &&
|
||||||
|
ac97->subsystem_device == 0x810f)
|
||||||
|
ac97->ext_id |= AC97_EI_SPDIF;
|
||||||
|
|
||||||
if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) {
|
if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) {
|
||||||
if (ac97->build_ops->build_spdif) {
|
if (ac97->build_ops->build_spdif) {
|
||||||
if ((err = ac97->build_ops->build_spdif(ac97)) < 0)
|
if ((err = ac97->build_ops->build_spdif(ac97)) < 0)
|
||||||
|
@ -1817,18 +1915,25 @@ static int snd_ac97_dev_register(struct snd_device *device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unregister ac97 codec */
|
/* disconnect ac97 codec */
|
||||||
static int snd_ac97_dev_unregister(struct snd_device *device)
|
static int snd_ac97_dev_disconnect(struct snd_device *device)
|
||||||
{
|
{
|
||||||
struct snd_ac97 *ac97 = device->device_data;
|
struct snd_ac97 *ac97 = device->device_data;
|
||||||
if (ac97->dev.bus)
|
if (ac97->dev.bus)
|
||||||
device_unregister(&ac97->dev);
|
device_unregister(&ac97->dev);
|
||||||
return snd_ac97_free(ac97);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build_ops to do nothing */
|
/* build_ops to do nothing */
|
||||||
static struct snd_ac97_build_ops null_build_ops;
|
static struct snd_ac97_build_ops null_build_ops;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
static void do_update_power(void *data)
|
||||||
|
{
|
||||||
|
update_power_regs(data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_ac97_mixer - create an Codec97 component
|
* snd_ac97_mixer - create an Codec97 component
|
||||||
* @bus: the AC97 bus which codec is attached to
|
* @bus: the AC97 bus which codec is attached to
|
||||||
|
@ -1860,7 +1965,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
|
||||||
static struct snd_device_ops ops = {
|
static struct snd_device_ops ops = {
|
||||||
.dev_free = snd_ac97_dev_free,
|
.dev_free = snd_ac97_dev_free,
|
||||||
.dev_register = snd_ac97_dev_register,
|
.dev_register = snd_ac97_dev_register,
|
||||||
.dev_unregister = snd_ac97_dev_unregister,
|
.dev_disconnect = snd_ac97_dev_disconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
snd_assert(rac97 != NULL, return -EINVAL);
|
snd_assert(rac97 != NULL, return -EINVAL);
|
||||||
|
@ -1883,6 +1988,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
|
||||||
bus->codec[ac97->num] = ac97;
|
bus->codec[ac97->num] = ac97;
|
||||||
mutex_init(&ac97->reg_mutex);
|
mutex_init(&ac97->reg_mutex);
|
||||||
mutex_init(&ac97->page_mutex);
|
mutex_init(&ac97->page_mutex);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
ac97->power_workq = create_workqueue("ac97");
|
||||||
|
INIT_WORK(&ac97->power_work, do_update_power, ac97);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
if (ac97->pci) {
|
if (ac97->pci) {
|
||||||
|
@ -2117,15 +2226,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* make sure the proper powerdown bits are cleared */
|
if (ac97_is_audio(ac97))
|
||||||
if (ac97->scaps && ac97_is_audio(ac97)) {
|
update_power_regs(ac97);
|
||||||
reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
|
|
||||||
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
|
||||||
reg &= ~AC97_EA_PRJ;
|
|
||||||
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
|
||||||
reg &= ~(AC97_EA_PRI | AC97_EA_PRK);
|
|
||||||
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg);
|
|
||||||
}
|
|
||||||
snd_ac97_proc_init(ac97);
|
snd_ac97_proc_init(ac97);
|
||||||
if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {
|
if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) {
|
||||||
snd_ac97_free(ac97);
|
snd_ac97_free(ac97);
|
||||||
|
@ -2153,22 +2255,155 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
|
||||||
snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
|
snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */
|
/* surround, CLFE, mic powerdown */
|
||||||
power |= 0x4000; /* Headphone amplifier powerdown */
|
power = ac97->regs[AC97_EXTENDED_STATUS];
|
||||||
power |= 0x0300; /* ADC & DAC powerdown */
|
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
||||||
|
power |= AC97_EA_PRJ;
|
||||||
|
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
||||||
|
power |= AC97_EA_PRI | AC97_EA_PRK;
|
||||||
|
power |= AC97_EA_PRL;
|
||||||
|
snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power);
|
||||||
|
|
||||||
|
/* powerdown external amplifier */
|
||||||
|
if (ac97->scaps & AC97_SCAP_INV_EAPD)
|
||||||
|
power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD;
|
||||||
|
else if (! (ac97->scaps & AC97_SCAP_EAPD_LED))
|
||||||
|
power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD;
|
||||||
|
power |= AC97_PD_PR6; /* Headphone amplifier powerdown */
|
||||||
|
power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */
|
||||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||||
udelay(100);
|
udelay(100);
|
||||||
power |= 0x0400; /* Analog Mixer powerdown (Vref on) */
|
power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
|
||||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
if (power_save) {
|
||||||
udelay(100);
|
udelay(100);
|
||||||
#if 0
|
/* AC-link powerdown, internal Clk disable */
|
||||||
/* FIXME: this causes click noises on some boards at resume */
|
/* FIXME: this may cause click noises on some boards */
|
||||||
power |= 0x3800; /* AC-link powerdown, internal Clk disable */
|
power |= AC97_PD_PR4 | AC97_PD_PR5;
|
||||||
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
snd_ac97_write(ac97, AC97_POWERDOWN, power);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ac97_power_reg {
|
||||||
|
unsigned short reg;
|
||||||
|
unsigned short power_reg;
|
||||||
|
unsigned short mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE };
|
||||||
|
|
||||||
|
static struct ac97_power_reg power_regs[PWIDX_SIZE] = {
|
||||||
|
[PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0},
|
||||||
|
[PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1},
|
||||||
|
[PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS,
|
||||||
|
AC97_EA_PRI | AC97_EA_PRK},
|
||||||
|
[PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS,
|
||||||
|
AC97_EA_PRJ},
|
||||||
|
[PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS,
|
||||||
|
AC97_EA_PRL},
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
/**
|
||||||
|
* snd_ac97_update_power - update the powerdown register
|
||||||
|
* @ac97: the codec instance
|
||||||
|
* @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE
|
||||||
|
* @powerup: non-zero when power up the part
|
||||||
|
*
|
||||||
|
* Update the AC97 powerdown register bits of the given part.
|
||||||
|
*/
|
||||||
|
int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (! ac97)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (reg) {
|
||||||
|
/* SPDIF requires DAC power, too */
|
||||||
|
if (reg == AC97_SPDIF)
|
||||||
|
reg = AC97_PCM_FRONT_DAC_RATE;
|
||||||
|
for (i = 0; i < PWIDX_SIZE; i++) {
|
||||||
|
if (power_regs[i].reg == reg) {
|
||||||
|
if (powerup)
|
||||||
|
ac97->power_up |= (1 << i);
|
||||||
|
else
|
||||||
|
ac97->power_up &= ~(1 << i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! power_save)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (! powerup && ac97->power_workq)
|
||||||
|
/* adjust power-down bits after two seconds delay
|
||||||
|
* (for avoiding loud click noises for many (OSS) apps
|
||||||
|
* that open/close frequently)
|
||||||
|
*/
|
||||||
|
queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
|
||||||
|
else
|
||||||
|
update_power_regs(ac97);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(snd_ac97_update_power);
|
||||||
|
#endif /* CONFIG_SND_AC97_POWER_SAVE */
|
||||||
|
|
||||||
|
static void update_power_regs(struct snd_ac97 *ac97)
|
||||||
|
{
|
||||||
|
unsigned int power_up, bits;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
if (power_save)
|
||||||
|
power_up = ac97->power_up;
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
|
power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
|
||||||
|
power_up |= (1 << PWIDX_MIC);
|
||||||
|
if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
|
||||||
|
power_up |= (1 << PWIDX_SURR);
|
||||||
|
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
|
||||||
|
power_up |= (1 << PWIDX_CLFE);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (power_up) {
|
||||||
|
if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
|
||||||
|
/* needs power-up analog mix and vref */
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR3, 0);
|
||||||
|
msleep(1);
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR2, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < PWIDX_SIZE; i++) {
|
||||||
|
if (power_up & (1 << i))
|
||||||
|
bits = 0;
|
||||||
|
else
|
||||||
|
bits = power_regs[i].mask;
|
||||||
|
snd_ac97_update_bits(ac97, power_regs[i].power_reg,
|
||||||
|
power_regs[i].mask, bits);
|
||||||
|
}
|
||||||
|
if (! power_up) {
|
||||||
|
if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) {
|
||||||
|
/* power down analog mix and vref */
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR2, AC97_PD_PR2);
|
||||||
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN,
|
||||||
|
AC97_PD_PR3, AC97_PD_PR3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
/**
|
/**
|
||||||
* snd_ac97_suspend - General suspend function for AC97 codec
|
* snd_ac97_suspend - General suspend function for AC97 codec
|
||||||
|
@ -2484,6 +2719,7 @@ static int tune_mute_led(struct snd_ac97 *ac97)
|
||||||
msw->put = master_mute_sw_put;
|
msw->put = master_mute_sw_put;
|
||||||
snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
|
snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
|
||||||
snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
|
snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
|
||||||
|
ac97->scaps |= AC97_SCAP_EAPD_LED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include "ac97_patch.h"
|
#include "ac97_patch.h"
|
||||||
#include "ac97_id.h"
|
#include "ac97_id.h"
|
||||||
|
@ -51,6 +52,20 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* replace with a new TLV */
|
||||||
|
static void reset_tlv(struct snd_ac97 *ac97, const char *name,
|
||||||
|
unsigned int *tlv)
|
||||||
|
{
|
||||||
|
struct snd_ctl_elem_id sid;
|
||||||
|
struct snd_kcontrol *kctl;
|
||||||
|
memset(&sid, 0, sizeof(sid));
|
||||||
|
strcpy(sid.name, name);
|
||||||
|
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||||
|
kctl = snd_ctl_find_id(ac97->bus->card, &sid);
|
||||||
|
if (kctl && kctl->tlv.p)
|
||||||
|
kctl->tlv.p = tlv;
|
||||||
|
}
|
||||||
|
|
||||||
/* set to the page, update bits and restore the page */
|
/* set to the page, update bits and restore the page */
|
||||||
static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page)
|
static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page)
|
||||||
{
|
{
|
||||||
|
@ -466,7 +481,7 @@ int patch_wolfson05(struct snd_ac97 * ac97)
|
||||||
ac97->build_ops = &patch_wolfson_wm9705_ops;
|
ac97->build_ops = &patch_wolfson_wm9705_ops;
|
||||||
#ifdef CONFIG_TOUCHSCREEN_WM9705
|
#ifdef CONFIG_TOUCHSCREEN_WM9705
|
||||||
/* WM9705 touchscreen uses AUX and VIDEO for touch */
|
/* WM9705 touchscreen uses AUX and VIDEO for touch */
|
||||||
ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
|
ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1380,6 +1395,17 @@ static void ad1888_resume(struct snd_ac97 *ac97)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const struct snd_ac97_res_table ad1819_restbl[] = {
|
||||||
|
{ AC97_PHONE, 0x9f1f },
|
||||||
|
{ AC97_MIC, 0x9f1f },
|
||||||
|
{ AC97_LINE, 0x9f1f },
|
||||||
|
{ AC97_CD, 0x9f1f },
|
||||||
|
{ AC97_VIDEO, 0x9f1f },
|
||||||
|
{ AC97_AUX, 0x9f1f },
|
||||||
|
{ AC97_PCM, 0x9f1f },
|
||||||
|
{ } /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
int patch_ad1819(struct snd_ac97 * ac97)
|
int patch_ad1819(struct snd_ac97 * ac97)
|
||||||
{
|
{
|
||||||
unsigned short scfg;
|
unsigned short scfg;
|
||||||
|
@ -1387,6 +1413,7 @@ int patch_ad1819(struct snd_ac97 * ac97)
|
||||||
// patch for Analog Devices
|
// patch for Analog Devices
|
||||||
scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
|
scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
|
||||||
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */
|
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */
|
||||||
|
ac97->res_table = ad1819_restbl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1522,12 +1549,16 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = {
|
||||||
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
|
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
|
||||||
|
|
||||||
static int patch_ad1885_specific(struct snd_ac97 * ac97)
|
static int patch_ad1885_specific(struct snd_ac97 * ac97)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)
|
if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
reset_tlv(ac97, "Headphone Playback Volume",
|
||||||
|
db_scale_6bit_6db_max);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,12 +1582,27 @@ int patch_ad1885(struct snd_ac97 * ac97)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int patch_ad1886_specific(struct snd_ac97 * ac97)
|
||||||
|
{
|
||||||
|
reset_tlv(ac97, "Headphone Playback Volume",
|
||||||
|
db_scale_6bit_6db_max);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct snd_ac97_build_ops patch_ad1886_build_ops = {
|
||||||
|
.build_specific = &patch_ad1886_specific,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.resume = ad18xx_resume
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
int patch_ad1886(struct snd_ac97 * ac97)
|
int patch_ad1886(struct snd_ac97 * ac97)
|
||||||
{
|
{
|
||||||
patch_ad1881(ac97);
|
patch_ad1881(ac97);
|
||||||
/* Presario700 workaround */
|
/* Presario700 workaround */
|
||||||
/* for Jack Sense/SPDIF Register misetting causing */
|
/* for Jack Sense/SPDIF Register misetting causing */
|
||||||
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
|
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
|
||||||
|
ac97->build_ops = &patch_ad1886_build_ops;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2015,6 +2061,8 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = {
|
||||||
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
|
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
|
||||||
|
|
||||||
static int patch_alc650_specific(struct snd_ac97 * ac97)
|
static int patch_alc650_specific(struct snd_ac97 * ac97)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -2025,6 +2073,9 @@ static int patch_alc650_specific(struct snd_ac97 * ac97)
|
||||||
if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0)
|
if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
if (ac97->id != AC97_ID_ALC650F)
|
||||||
|
reset_tlv(ac97, "Master Playback Volume",
|
||||||
|
db_scale_5bit_3db_max);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2208,7 +2259,8 @@ int patch_alc655(struct snd_ac97 * ac97)
|
||||||
val &= ~(1 << 1); /* Pin 47 is spdif input pin */
|
val &= ~(1 << 1); /* Pin 47 is spdif input pin */
|
||||||
else { /* ALC655 */
|
else { /* ALC655 */
|
||||||
if (ac97->subsystem_vendor == 0x1462 &&
|
if (ac97->subsystem_vendor == 0x1462 &&
|
||||||
ac97->subsystem_device == 0x0131) /* MSI S270 laptop */
|
(ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
|
||||||
|
ac97->subsystem_device == 0x0161)) /* LG K1 Express */
|
||||||
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
|
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
|
||||||
else
|
else
|
||||||
val |= (1 << 1); /* Pin 47 is spdif input pin */
|
val |= (1 << 1); /* Pin 47 is spdif input pin */
|
||||||
|
@ -2759,6 +2811,10 @@ int patch_vt1616(struct snd_ac97 * ac97)
|
||||||
*/
|
*/
|
||||||
int patch_vt1617a(struct snd_ac97 * ac97)
|
int patch_vt1617a(struct snd_ac97 * ac97)
|
||||||
{
|
{
|
||||||
|
/* bring analog power consumption to normal, like WinXP driver
|
||||||
|
* for EPIA SP
|
||||||
|
*/
|
||||||
|
snd_ac97_write_cache(ac97, 0x5c, 0x20);
|
||||||
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
|
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
|
||||||
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
|
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2872,3 +2928,41 @@ int patch_lm4550(struct snd_ac97 *ac97)
|
||||||
ac97->res_table = lm4550_restbl;
|
ac97->res_table = lm4550_restbl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf)
|
||||||
|
*/
|
||||||
|
static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = {
|
||||||
|
/* enable/disable headphone driver which allows direct connection to
|
||||||
|
stereo headphone without the use of external DC blocking
|
||||||
|
capacitors */
|
||||||
|
AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0),
|
||||||
|
/* Filter used to compensate the DC offset is added in the ADC to remove idle
|
||||||
|
tones from the audio band. */
|
||||||
|
AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0),
|
||||||
|
/* Control smart-low-power mode feature. Allows automatic power down
|
||||||
|
of unused blocks in the ADC analog front end and the PLL. */
|
||||||
|
AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int patch_ucb1400_specific(struct snd_ac97 * ac97)
|
||||||
|
{
|
||||||
|
int idx, err;
|
||||||
|
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++)
|
||||||
|
if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0)
|
||||||
|
return err;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct snd_ac97_build_ops patch_ucb1400_ops = {
|
||||||
|
.build_specific = patch_ucb1400_specific,
|
||||||
|
};
|
||||||
|
|
||||||
|
int patch_ucb1400(struct snd_ac97 * ac97)
|
||||||
|
{
|
||||||
|
ac97->build_ops = &patch_ucb1400_ops;
|
||||||
|
/* enable headphone driver and smart low power mode by default */
|
||||||
|
snd_ac97_write(ac97, 0x6a, 0x0050);
|
||||||
|
snd_ac97_write(ac97, 0x6c, 0x0030);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -58,5 +58,6 @@ int patch_cm9780(struct snd_ac97 * ac97);
|
||||||
int patch_vt1616(struct snd_ac97 * ac97);
|
int patch_vt1616(struct snd_ac97 * ac97);
|
||||||
int patch_vt1617a(struct snd_ac97 * ac97);
|
int patch_vt1617a(struct snd_ac97 * ac97);
|
||||||
int patch_it2646(struct snd_ac97 * ac97);
|
int patch_it2646(struct snd_ac97 * ac97);
|
||||||
|
int patch_ucb1400(struct snd_ac97 * ac97);
|
||||||
int mpatch_si3036(struct snd_ac97 * ac97);
|
int mpatch_si3036(struct snd_ac97 * ac97);
|
||||||
int patch_lm4550(struct snd_ac97 * ac97);
|
int patch_lm4550(struct snd_ac97 * ac97);
|
||||||
|
|
|
@ -269,6 +269,7 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snd_ac97_update_power(ac97, reg, 1);
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case AC97_PCM_MIC_ADC_RATE:
|
case AC97_PCM_MIC_ADC_RATE:
|
||||||
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */
|
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */
|
||||||
|
@ -606,6 +607,7 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pcm->cur_dbl = r;
|
||||||
spin_unlock_irq(&pcm->bus->bus_lock);
|
spin_unlock_irq(&pcm->bus->bus_lock);
|
||||||
for (i = 3; i < 12; i++) {
|
for (i = 3; i < 12; i++) {
|
||||||
if (!(slots & (1 << i)))
|
if (!(slots & (1 << i)))
|
||||||
|
@ -651,6 +653,21 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
|
||||||
unsigned short slots = pcm->aslots;
|
unsigned short slots = pcm->aslots;
|
||||||
int i, cidx;
|
int i, cidx;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
int r = pcm->cur_dbl;
|
||||||
|
for (i = 3; i < 12; i++) {
|
||||||
|
if (!(slots & (1 << i)))
|
||||||
|
continue;
|
||||||
|
for (cidx = 0; cidx < 4; cidx++) {
|
||||||
|
if (pcm->r[r].rslots[cidx] & (1 << i)) {
|
||||||
|
int reg = get_slot_reg(pcm, cidx, i, r);
|
||||||
|
snd_ac97_update_power(pcm->r[r].codec[cidx],
|
||||||
|
reg, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bus = pcm->bus;
|
bus = pcm->bus;
|
||||||
spin_lock_irq(&pcm->bus->bus_lock);
|
spin_lock_irq(&pcm->bus->bus_lock);
|
||||||
for (i = 3; i < 12; i++) {
|
for (i = 3; i < 12; i++) {
|
||||||
|
@ -660,6 +677,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
|
||||||
bus->used_slots[pcm->stream][cidx] &= ~(1 << i);
|
bus->used_slots[pcm->stream][cidx] &= ~(1 << i);
|
||||||
}
|
}
|
||||||
pcm->aslots = 0;
|
pcm->aslots = 0;
|
||||||
|
pcm->cur_dbl = 0;
|
||||||
spin_unlock_irq(&pcm->bus->bus_lock);
|
spin_unlock_irq(&pcm->bus->bus_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,15 +457,11 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97)
|
||||||
|
|
||||||
void snd_ac97_proc_done(struct snd_ac97 * ac97)
|
void snd_ac97_proc_done(struct snd_ac97 * ac97)
|
||||||
{
|
{
|
||||||
if (ac97->proc_regs) {
|
snd_info_free_entry(ac97->proc_regs);
|
||||||
snd_info_unregister(ac97->proc_regs);
|
|
||||||
ac97->proc_regs = NULL;
|
ac97->proc_regs = NULL;
|
||||||
}
|
snd_info_free_entry(ac97->proc);
|
||||||
if (ac97->proc) {
|
|
||||||
snd_info_unregister(ac97->proc);
|
|
||||||
ac97->proc = NULL;
|
ac97->proc = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus)
|
void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus)
|
||||||
{
|
{
|
||||||
|
@ -485,8 +481,6 @@ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus)
|
||||||
|
|
||||||
void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus)
|
void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus)
|
||||||
{
|
{
|
||||||
if (bus->proc) {
|
snd_info_free_entry(bus->proc);
|
||||||
snd_info_unregister(bus->proc);
|
|
||||||
bus->proc = NULL;
|
bus->proc = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/ak4531_codec.h>
|
#include <sound/ak4531_codec.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
|
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
|
||||||
MODULE_DESCRIPTION("Universal routines for AK4531 codec");
|
MODULE_DESCRIPTION("Universal routines for AK4531 codec");
|
||||||
|
@ -63,6 +64,14 @@ static void snd_ak4531_dump(struct snd_ak4531 *ak4531)
|
||||||
.info = snd_ak4531_info_single, \
|
.info = snd_ak4531_info_single, \
|
||||||
.get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \
|
.get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \
|
||||||
.private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) }
|
.private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) }
|
||||||
|
#define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
|
.info = snd_ak4531_info_single, \
|
||||||
|
.get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \
|
||||||
|
.private_value = reg | (shift << 16) | (mask << 24) | (invert << 22), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
|
|
||||||
static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
@ -122,6 +131,14 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||||
.info = snd_ak4531_info_double, \
|
.info = snd_ak4531_info_double, \
|
||||||
.get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \
|
.get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \
|
||||||
.private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) }
|
.private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) }
|
||||||
|
#define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
|
.info = snd_ak4531_info_double, \
|
||||||
|
.get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \
|
||||||
|
.private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
|
|
||||||
static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
@ -250,50 +267,62 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_ak4531_controls[] = {
|
static struct snd_kcontrol_new snd_ak4531_controls[] = {
|
||||||
|
|
||||||
AK4531_DOUBLE("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1),
|
AK4531_DOUBLE_TLV("Master Playback Switch", 0,
|
||||||
|
AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1,
|
||||||
|
db_scale_master),
|
||||||
AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1),
|
AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1),
|
||||||
|
|
||||||
AK4531_SINGLE("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1),
|
AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1,
|
||||||
|
db_scale_mono),
|
||||||
AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1),
|
AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1),
|
||||||
|
|
||||||
AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1),
|
AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1),
|
||||||
AK4531_DOUBLE("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1),
|
AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1,
|
||||||
|
db_scale_input),
|
||||||
AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0),
|
AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0),
|
||||||
AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0),
|
AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0),
|
||||||
|
|
||||||
AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1),
|
AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1),
|
||||||
AK4531_DOUBLE("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1),
|
AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1,
|
||||||
|
db_scale_input),
|
||||||
AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0),
|
AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0),
|
||||||
AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5),
|
AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5),
|
||||||
|
|
||||||
AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1),
|
AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1),
|
||||||
AK4531_DOUBLE("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1),
|
AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1,
|
||||||
|
db_scale_input),
|
||||||
AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0),
|
AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0),
|
||||||
AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1),
|
AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1),
|
||||||
|
|
||||||
AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1),
|
AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1),
|
||||||
AK4531_DOUBLE("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1),
|
AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1,
|
||||||
|
db_scale_input),
|
||||||
AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0),
|
AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0),
|
||||||
AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3),
|
AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3),
|
||||||
|
|
||||||
AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1),
|
AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1),
|
||||||
AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1),
|
AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1,
|
||||||
|
db_scale_input),
|
||||||
AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0),
|
AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0),
|
||||||
AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3),
|
AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3),
|
||||||
|
|
||||||
AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1),
|
AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1),
|
||||||
AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1),
|
AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input),
|
||||||
AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0),
|
AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0),
|
||||||
AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0),
|
AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0),
|
||||||
|
|
||||||
AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1),
|
AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1),
|
||||||
AK4531_SINGLE("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1),
|
AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input),
|
||||||
AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0),
|
AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0),
|
||||||
AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0),
|
AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0),
|
||||||
|
|
||||||
AK4531_SINGLE("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1),
|
AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input),
|
||||||
AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1),
|
AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1),
|
||||||
AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0),
|
AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0),
|
||||||
AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0),
|
AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0),
|
||||||
|
|
|
@ -70,9 +70,13 @@
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include "ca0106.h"
|
#include "ca0106.h"
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
|
||||||
|
static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
|
||||||
|
|
||||||
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
|
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo)
|
struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
@ -469,18 +473,24 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
#define CA_VOLUME(xname,chid,reg) \
|
#define CA_VOLUME(xname,chid,reg) \
|
||||||
{ \
|
{ \
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
.info = snd_ca0106_volume_info, \
|
.info = snd_ca0106_volume_info, \
|
||||||
.get = snd_ca0106_volume_get, \
|
.get = snd_ca0106_volume_get, \
|
||||||
.put = snd_ca0106_volume_put, \
|
.put = snd_ca0106_volume_put, \
|
||||||
|
.tlv = { .p = snd_ca0106_db_scale1 }, \
|
||||||
.private_value = ((chid) << 8) | (reg) \
|
.private_value = ((chid) << 8) | (reg) \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define I2C_VOLUME(xname,chid) \
|
#define I2C_VOLUME(xname,chid) \
|
||||||
{ \
|
{ \
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
.info = snd_ca0106_i2c_volume_info, \
|
.info = snd_ca0106_i2c_volume_info, \
|
||||||
.get = snd_ca0106_i2c_volume_get, \
|
.get = snd_ca0106_i2c_volume_get, \
|
||||||
.put = snd_ca0106_i2c_volume_put, \
|
.put = snd_ca0106_i2c_volume_put, \
|
||||||
|
.tlv = { .p = snd_ca0106_db_scale2 }, \
|
||||||
.private_value = chid \
|
.private_value = chid \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/rawmidi.h>
|
#include <sound/rawmidi.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/opl3.h>
|
#include <sound/opl3.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
|
||||||
|
@ -1054,6 +1055,8 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_cs4281_fm_vol =
|
static struct snd_kcontrol_new snd_cs4281_fm_vol =
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1062,6 +1065,7 @@ static struct snd_kcontrol_new snd_cs4281_fm_vol =
|
||||||
.get = snd_cs4281_get_volume,
|
.get = snd_cs4281_get_volume,
|
||||||
.put = snd_cs4281_put_volume,
|
.put = snd_cs4281_put_volume,
|
||||||
.private_value = ((BA0_FMLVC << 16) | BA0_FMRVC),
|
.private_value = ((BA0_FMLVC << 16) | BA0_FMRVC),
|
||||||
|
.tlv = { .p = db_scale_dsp },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_cs4281_pcm_vol =
|
static struct snd_kcontrol_new snd_cs4281_pcm_vol =
|
||||||
|
@ -1072,6 +1076,7 @@ static struct snd_kcontrol_new snd_cs4281_pcm_vol =
|
||||||
.get = snd_cs4281_get_volume,
|
.get = snd_cs4281_get_volume,
|
||||||
.put = snd_cs4281_put_volume,
|
.put = snd_cs4281_put_volume,
|
||||||
.private_value = ((BA0_PPLVC << 16) | BA0_PPRVC),
|
.private_value = ((BA0_PPLVC << 16) | BA0_PPRVC),
|
||||||
|
.tlv = { .p = db_scale_dsp },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
|
static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
|
||||||
|
|
|
@ -868,35 +868,23 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
|
||||||
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
|
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (ins->proc_sym_info_entry) {
|
snd_info_free_entry(ins->proc_sym_info_entry);
|
||||||
snd_info_unregister(ins->proc_sym_info_entry);
|
|
||||||
ins->proc_sym_info_entry = NULL;
|
ins->proc_sym_info_entry = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->proc_modules_info_entry) {
|
snd_info_free_entry(ins->proc_modules_info_entry);
|
||||||
snd_info_unregister(ins->proc_modules_info_entry);
|
|
||||||
ins->proc_modules_info_entry = NULL;
|
ins->proc_modules_info_entry = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->proc_parameter_dump_info_entry) {
|
snd_info_free_entry(ins->proc_parameter_dump_info_entry);
|
||||||
snd_info_unregister(ins->proc_parameter_dump_info_entry);
|
|
||||||
ins->proc_parameter_dump_info_entry = NULL;
|
ins->proc_parameter_dump_info_entry = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->proc_sample_dump_info_entry) {
|
snd_info_free_entry(ins->proc_sample_dump_info_entry);
|
||||||
snd_info_unregister(ins->proc_sample_dump_info_entry);
|
|
||||||
ins->proc_sample_dump_info_entry = NULL;
|
ins->proc_sample_dump_info_entry = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->proc_scb_info_entry) {
|
snd_info_free_entry(ins->proc_scb_info_entry);
|
||||||
snd_info_unregister(ins->proc_scb_info_entry);
|
|
||||||
ins->proc_scb_info_entry = NULL;
|
ins->proc_scb_info_entry = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->proc_task_info_entry) {
|
snd_info_free_entry(ins->proc_task_info_entry);
|
||||||
snd_info_unregister(ins->proc_task_info_entry);
|
|
||||||
ins->proc_task_info_entry = NULL;
|
ins->proc_task_info_entry = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&chip->spos_mutex);
|
mutex_lock(&chip->spos_mutex);
|
||||||
for (i = 0; i < ins->nscb; ++i) {
|
for (i = 0; i < ins->nscb; ++i) {
|
||||||
|
@ -905,10 +893,8 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
|
||||||
}
|
}
|
||||||
mutex_unlock(&chip->spos_mutex);
|
mutex_unlock(&chip->spos_mutex);
|
||||||
|
|
||||||
if (ins->proc_dsp_dir) {
|
snd_info_free_entry(ins->proc_dsp_dir);
|
||||||
snd_info_unregister (ins->proc_dsp_dir);
|
|
||||||
ins->proc_dsp_dir = NULL;
|
ins->proc_dsp_dir = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
|
||||||
|
|
||||||
snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
|
snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
|
||||||
|
|
||||||
snd_info_unregister(scb->proc_info);
|
snd_info_free_entry(scb->proc_info);
|
||||||
scb->proc_info = NULL;
|
scb->proc_info = NULL;
|
||||||
|
|
||||||
snd_assert (scb_info != NULL, return);
|
snd_assert (scb_info != NULL, return);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o
|
snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o
|
||||||
|
|
||||||
ifdef CONFIG_PM
|
ifeq ($(CONFIG_PM),y)
|
||||||
snd-cs5535audio-objs += cs5535audio_pm.o
|
snd-cs5535audio-objs += cs5535audio_pm.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ static int snd_emu10k1_suspend(struct pci_dev *pci, pm_message_t state)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_emu10k1_resume(struct pci_dev *pci)
|
static int snd_emu10k1_resume(struct pci_dev *pci)
|
||||||
{
|
{
|
||||||
struct snd_card *card = pci_get_drvdata(pci);
|
struct snd_card *card = pci_get_drvdata(pci);
|
||||||
struct snd_emu10k1 *emu = card->private_data;
|
struct snd_emu10k1 *emu = card->private_data;
|
||||||
|
|
|
@ -927,6 +927,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
|
||||||
.ca0151_chip = 1,
|
.ca0151_chip = 1,
|
||||||
.spk71 = 1,
|
.spk71 = 1,
|
||||||
.spdif_bug = 1,
|
.spdif_bug = 1,
|
||||||
|
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
|
||||||
.ac97_chip = 1} ,
|
.ac97_chip = 1} ,
|
||||||
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
|
||||||
.driver = "Audigy2", .name = "Audigy 2 EX [1005]",
|
.driver = "Audigy2", .name = "Audigy 2 EX [1005]",
|
||||||
|
|
|
@ -1626,12 +1626,7 @@ static struct pci_driver driver = {
|
||||||
// initialization of the module
|
// initialization of the module
|
||||||
static int __init alsa_card_emu10k1x_init(void)
|
static int __init alsa_card_emu10k1x_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
return pci_register_driver(&driver);
|
||||||
|
|
||||||
if ((err = pci_register_driver(&driver)) > 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up the module
|
// clean up the module
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/emu10k1.h>
|
#include <sound/emu10k1.h>
|
||||||
|
|
||||||
#if 0 /* for testing purposes - digital out -> capture */
|
#if 0 /* for testing purposes - digital out -> capture */
|
||||||
|
@ -266,6 +267,7 @@ static const u32 treble_table[41][5] = {
|
||||||
{ 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
|
{ 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
|
||||||
static const u32 db_table[101] = {
|
static const u32 db_table[101] = {
|
||||||
0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
|
0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
|
||||||
0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
|
0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
|
||||||
|
@ -290,6 +292,9 @@ static const u32 db_table[101] = {
|
||||||
0x7fffffff,
|
0x7fffffff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* EMU10k1/EMU10k2 DSP control db gain */
|
||||||
|
static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
|
||||||
|
|
||||||
static const u32 onoff_table[2] = {
|
static const u32 onoff_table[2] = {
|
||||||
0x00000000, 0x00000001
|
0x00000000, 0x00000001
|
||||||
};
|
};
|
||||||
|
@ -755,6 +760,11 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
|
||||||
knew.device = gctl->id.device;
|
knew.device = gctl->id.device;
|
||||||
knew.subdevice = gctl->id.subdevice;
|
knew.subdevice = gctl->id.subdevice;
|
||||||
knew.info = snd_emu10k1_gpr_ctl_info;
|
knew.info = snd_emu10k1_gpr_ctl_info;
|
||||||
|
if (gctl->tlv.p) {
|
||||||
|
knew.tlv.p = gctl->tlv.p;
|
||||||
|
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
|
||||||
|
}
|
||||||
knew.get = snd_emu10k1_gpr_ctl_get;
|
knew.get = snd_emu10k1_gpr_ctl_get;
|
||||||
knew.put = snd_emu10k1_gpr_ctl_put;
|
knew.put = snd_emu10k1_gpr_ctl_put;
|
||||||
memset(nctl, 0, sizeof(*nctl));
|
memset(nctl, 0, sizeof(*nctl));
|
||||||
|
@ -1013,6 +1023,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
|
||||||
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
|
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
|
||||||
ctl->min = 0;
|
ctl->min = 0;
|
||||||
ctl->max = 100;
|
ctl->max = 100;
|
||||||
|
ctl->tlv.p = snd_emu10k1_db_scale1;
|
||||||
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
|
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,6 +1038,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
|
||||||
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
|
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
|
||||||
ctl->min = 0;
|
ctl->min = 0;
|
||||||
ctl->max = 100;
|
ctl->max = 100;
|
||||||
|
ctl->tlv.p = snd_emu10k1_db_scale1;
|
||||||
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
|
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/emu10k1.h>
|
#include <sound/emu10k1.h>
|
||||||
#include "p16v.h"
|
#include "p16v.h"
|
||||||
|
|
||||||
|
@ -784,12 +785,16 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol,
|
||||||
}
|
}
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
|
||||||
|
|
||||||
#define P16V_VOL(xname,xreg,xhl) { \
|
#define P16V_VOL(xname,xreg,xhl) { \
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
.info = snd_p16v_volume_info, \
|
.info = snd_p16v_volume_info, \
|
||||||
.get = snd_p16v_volume_get, \
|
.get = snd_p16v_volume_get, \
|
||||||
.put = snd_p16v_volume_put, \
|
.put = snd_p16v_volume_put, \
|
||||||
|
.tlv = { .p = snd_p16v_db_scale1 }, \
|
||||||
.private_value = ((xreg) | ((xhl) << 8)) \
|
.private_value = ((xreg) | ((xhl) << 8)) \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include <sound/opl3.h>
|
#include <sound/opl3.h>
|
||||||
#include <sound/mpu401.h>
|
#include <sound/mpu401.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
@ -1164,6 +1165,14 @@ static int snd_es1938_reg_read(struct es1938 *chip, unsigned char reg)
|
||||||
return snd_es1938_read(chip, reg);
|
return snd_es1938_read(chip, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ES1938_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
|
.info = snd_es1938_info_single, \
|
||||||
|
.get = snd_es1938_get_single, .put = snd_es1938_put_single, \
|
||||||
|
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
|
||||||
|
.tlv = { .p = xtlv } }
|
||||||
#define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \
|
#define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||||
.info = snd_es1938_info_single, \
|
.info = snd_es1938_info_single, \
|
||||||
|
@ -1217,6 +1226,14 @@ static int snd_es1938_put_single(struct snd_kcontrol *kcontrol,
|
||||||
return snd_es1938_reg_bits(chip, reg, mask, val) != val;
|
return snd_es1938_reg_bits(chip, reg, mask, val) != val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ES1938_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\
|
||||||
|
.name = xname, .index = xindex, \
|
||||||
|
.info = snd_es1938_info_double, \
|
||||||
|
.get = snd_es1938_get_double, .put = snd_es1938_put_double, \
|
||||||
|
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
|
||||||
|
.tlv = { .p = xtlv } }
|
||||||
#define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
#define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||||
.info = snd_es1938_info_double, \
|
.info = snd_es1938_info_double, \
|
||||||
|
@ -1297,8 +1314,41 @@ static int snd_es1938_put_double(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int db_scale_master[] = {
|
||||||
|
TLV_DB_RANGE_HEAD(2),
|
||||||
|
0, 54, TLV_DB_SCALE_ITEM(-3600, 50, 1),
|
||||||
|
54, 63, TLV_DB_SCALE_ITEM(-900, 100, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int db_scale_audio1[] = {
|
||||||
|
TLV_DB_RANGE_HEAD(2),
|
||||||
|
0, 8, TLV_DB_SCALE_ITEM(-3300, 300, 1),
|
||||||
|
8, 15, TLV_DB_SCALE_ITEM(-900, 150, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int db_scale_audio2[] = {
|
||||||
|
TLV_DB_RANGE_HEAD(2),
|
||||||
|
0, 8, TLV_DB_SCALE_ITEM(-3450, 300, 1),
|
||||||
|
8, 15, TLV_DB_SCALE_ITEM(-1050, 150, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int db_scale_mic[] = {
|
||||||
|
TLV_DB_RANGE_HEAD(2),
|
||||||
|
0, 8, TLV_DB_SCALE_ITEM(-2400, 300, 1),
|
||||||
|
8, 15, TLV_DB_SCALE_ITEM(0, 150, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int db_scale_line[] = {
|
||||||
|
TLV_DB_RANGE_HEAD(2),
|
||||||
|
0, 8, TLV_DB_SCALE_ITEM(-3150, 300, 1),
|
||||||
|
8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_es1938_controls[] = {
|
static struct snd_kcontrol_new snd_es1938_controls[] = {
|
||||||
ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),
|
ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0,
|
||||||
|
db_scale_master),
|
||||||
ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
|
ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1309,19 +1359,27 @@ ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READ |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Hardware Master Playback Switch",
|
.name = "Hardware Master Playback Switch",
|
||||||
.access = SNDRV_CTL_ELEM_ACCESS_READ,
|
|
||||||
.info = snd_es1938_info_hw_switch,
|
.info = snd_es1938_info_hw_switch,
|
||||||
.get = snd_es1938_get_hw_switch,
|
.get = snd_es1938_get_hw_switch,
|
||||||
|
.tlv = { .p = db_scale_master },
|
||||||
},
|
},
|
||||||
ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0),
|
ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0),
|
||||||
ES1938_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0,
|
||||||
|
db_scale_line),
|
||||||
ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
|
ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
|
||||||
ES1938_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
|
db_scale_mic),
|
||||||
ES1938_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),
|
db_scale_line),
|
||||||
ES1938_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0,
|
||||||
|
db_scale_mic),
|
||||||
|
ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0,
|
||||||
|
db_scale_line),
|
||||||
|
ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0,
|
||||||
|
db_scale_capture),
|
||||||
ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0),
|
ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0),
|
||||||
ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
|
ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
|
||||||
ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
|
ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
|
||||||
|
@ -1332,16 +1390,26 @@ ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
|
||||||
.get = snd_es1938_get_mux,
|
.get = snd_es1938_get_mux,
|
||||||
.put = snd_es1938_put_mux,
|
.put = snd_es1938_put_mux,
|
||||||
},
|
},
|
||||||
ES1938_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),
|
db_scale_line),
|
||||||
ES1938_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),
|
db_scale_audio2),
|
||||||
ES1938_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0),
|
db_scale_mic),
|
||||||
ES1938_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0),
|
db_scale_line),
|
||||||
ES1938_DOUBLE("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0),
|
ES1938_DOUBLE_TLV("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0,
|
||||||
ES1938_DOUBLE("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0),
|
db_scale_mic),
|
||||||
|
ES1938_DOUBLE_TLV("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0,
|
||||||
|
db_scale_line),
|
||||||
|
ES1938_DOUBLE_TLV("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0,
|
||||||
|
db_scale_line),
|
||||||
|
ES1938_DOUBLE_TLV("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0,
|
||||||
|
db_scale_line),
|
||||||
|
ES1938_DOUBLE_TLV("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0,
|
||||||
|
db_scale_audio2),
|
||||||
|
ES1938_DOUBLE_TLV("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0,
|
||||||
|
db_scale_audio1),
|
||||||
ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0),
|
ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0),
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
|
|
@ -1905,7 +1905,7 @@ static void es1968_update_hw_volume(unsigned long private_data)
|
||||||
/* Figure out which volume control button was pushed,
|
/* Figure out which volume control button was pushed,
|
||||||
based on differences from the default register
|
based on differences from the default register
|
||||||
values. */
|
values. */
|
||||||
x = inb(chip->io_port + 0x1c);
|
x = inb(chip->io_port + 0x1c) & 0xee;
|
||||||
/* Reset the volume control registers. */
|
/* Reset the volume control registers. */
|
||||||
outb(0x88, chip->io_port + 0x1c);
|
outb(0x88, chip->io_port + 0x1c);
|
||||||
outb(0x88, chip->io_port + 0x1d);
|
outb(0x88, chip->io_port + 0x1d);
|
||||||
|
@ -1921,7 +1921,8 @@ static void es1968_update_hw_volume(unsigned long private_data)
|
||||||
/* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
|
/* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
|
||||||
spin_lock_irqsave(&chip->ac97_lock, flags);
|
spin_lock_irqsave(&chip->ac97_lock, flags);
|
||||||
val = chip->ac97->regs[AC97_MASTER];
|
val = chip->ac97->regs[AC97_MASTER];
|
||||||
if (x & 1) {
|
switch (x) {
|
||||||
|
case 0x88:
|
||||||
/* mute */
|
/* mute */
|
||||||
val ^= 0x8000;
|
val ^= 0x8000;
|
||||||
chip->ac97->regs[AC97_MASTER] = val;
|
chip->ac97->regs[AC97_MASTER] = val;
|
||||||
|
@ -1929,26 +1930,31 @@ static void es1968_update_hw_volume(unsigned long private_data)
|
||||||
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
|
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
|
||||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||||
&chip->master_switch->id);
|
&chip->master_switch->id);
|
||||||
} else {
|
break;
|
||||||
val &= 0x7fff;
|
case 0xaa:
|
||||||
if (((x>>1) & 7) > 4) {
|
|
||||||
/* volume up */
|
/* volume up */
|
||||||
if ((val & 0xff) > 0)
|
if ((val & 0x7f) > 0)
|
||||||
val--;
|
val--;
|
||||||
if ((val & 0xff00) > 0)
|
if ((val & 0x7f00) > 0)
|
||||||
val -= 0x0100;
|
val -= 0x0100;
|
||||||
} else {
|
|
||||||
/* volume down */
|
|
||||||
if ((val & 0xff) < 0x1f)
|
|
||||||
val++;
|
|
||||||
if ((val & 0xff00) < 0x1f00)
|
|
||||||
val += 0x0100;
|
|
||||||
}
|
|
||||||
chip->ac97->regs[AC97_MASTER] = val;
|
chip->ac97->regs[AC97_MASTER] = val;
|
||||||
outw(val, chip->io_port + ESM_AC97_DATA);
|
outw(val, chip->io_port + ESM_AC97_DATA);
|
||||||
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
|
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
|
||||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||||
&chip->master_volume->id);
|
&chip->master_volume->id);
|
||||||
|
break;
|
||||||
|
case 0x66:
|
||||||
|
/* volume down */
|
||||||
|
if ((val & 0x7f) < 0x1f)
|
||||||
|
val++;
|
||||||
|
if ((val & 0x7f00) < 0x1f00)
|
||||||
|
val += 0x0100;
|
||||||
|
chip->ac97->regs[AC97_MASTER] = val;
|
||||||
|
outw(val, chip->io_port + ESM_AC97_DATA);
|
||||||
|
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
|
||||||
|
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||||
|
&chip->master_volume->id);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&chip->ac97_lock, flags);
|
spin_unlock_irqrestore(&chip->ac97_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* The driver for the ForteMedia FM801 based soundcards
|
* The driver for the ForteMedia FM801 based soundcards
|
||||||
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
|
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
|
||||||
*
|
*
|
||||||
|
* Support FM only card by Andy Shevchenko <andy@smile.org.ua>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include <sound/mpu401.h>
|
#include <sound/mpu401.h>
|
||||||
#include <sound/opl3.h>
|
#include <sound/opl3.h>
|
||||||
|
@ -54,6 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
|
||||||
* 1 = MediaForte 256-PCS
|
* 1 = MediaForte 256-PCS
|
||||||
* 2 = MediaForte 256-PCPR
|
* 2 = MediaForte 256-PCPR
|
||||||
* 3 = MediaForte 64-PCR
|
* 3 = MediaForte 64-PCR
|
||||||
|
* 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card
|
||||||
* High 16-bits are video (radio) device number + 1
|
* High 16-bits are video (radio) device number + 1
|
||||||
*/
|
*/
|
||||||
static int tea575x_tuner[SNDRV_CARDS];
|
static int tea575x_tuner[SNDRV_CARDS];
|
||||||
|
@ -158,6 +161,7 @@ struct fm801 {
|
||||||
unsigned int multichannel: 1, /* multichannel support */
|
unsigned int multichannel: 1, /* multichannel support */
|
||||||
secondary: 1; /* secondary codec */
|
secondary: 1; /* secondary codec */
|
||||||
unsigned char secondary_addr; /* address of the secondary codec */
|
unsigned char secondary_addr; /* address of the secondary codec */
|
||||||
|
unsigned int tea575x_tuner; /* tuner flags */
|
||||||
|
|
||||||
unsigned short ply_ctrl; /* playback control */
|
unsigned short ply_ctrl; /* playback control */
|
||||||
unsigned short cap_ctrl; /* capture control */
|
unsigned short cap_ctrl; /* capture control */
|
||||||
|
@ -318,10 +322,8 @@ static unsigned int channels[] = {
|
||||||
2, 4, 6
|
2, 4, 6
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CHANNELS sizeof(channels) / sizeof(channels[0])
|
|
||||||
|
|
||||||
static struct snd_pcm_hw_constraint_list hw_constraints_channels = {
|
static struct snd_pcm_hw_constraint_list hw_constraints_channels = {
|
||||||
.count = CHANNELS,
|
.count = ARRAY_SIZE(channels),
|
||||||
.list = channels,
|
.list = channels,
|
||||||
.mask = 0,
|
.mask = 0,
|
||||||
};
|
};
|
||||||
|
@ -1052,6 +1054,13 @@ static int snd_fm801_put_single(struct snd_kcontrol *kcontrol,
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \
|
||||||
.get = snd_fm801_get_double, .put = snd_fm801_put_double, \
|
.get = snd_fm801_get_double, .put = snd_fm801_put_double, \
|
||||||
.private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) }
|
.private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) }
|
||||||
|
#define FM801_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
|
.name = xname, .info = snd_fm801_info_double, \
|
||||||
|
.get = snd_fm801_get_double, .put = snd_fm801_put_double, \
|
||||||
|
.private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \
|
||||||
|
.tlv = { .p = (xtlv) } }
|
||||||
|
|
||||||
static int snd_fm801_info_double(struct snd_kcontrol *kcontrol,
|
static int snd_fm801_info_double(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo)
|
struct snd_ctl_elem_info *uinfo)
|
||||||
|
@ -1148,14 +1157,19 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol,
|
||||||
return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);
|
return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
|
||||||
|
|
||||||
#define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)
|
#define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = {
|
static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = {
|
||||||
FM801_DOUBLE("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1),
|
FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1,
|
||||||
|
db_scale_dsp),
|
||||||
FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1),
|
FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1),
|
||||||
FM801_DOUBLE("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1),
|
FM801_DOUBLE_TLV("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1,
|
||||||
|
db_scale_dsp),
|
||||||
FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1),
|
FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1),
|
||||||
FM801_DOUBLE("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1),
|
FM801_DOUBLE_TLV("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1,
|
||||||
|
db_scale_dsp),
|
||||||
FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
|
FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1253,6 +1267,9 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||||
int id;
|
int id;
|
||||||
unsigned short cmdw;
|
unsigned short cmdw;
|
||||||
|
|
||||||
|
if (chip->tea575x_tuner & 0x0010)
|
||||||
|
goto __ac97_ok;
|
||||||
|
|
||||||
/* codec cold reset + AC'97 warm reset */
|
/* codec cold reset + AC'97 warm reset */
|
||||||
outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL));
|
outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL));
|
||||||
inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
|
inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
|
||||||
|
@ -1290,6 +1307,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||||
wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750));
|
wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__ac97_ok:
|
||||||
|
|
||||||
/* init volume */
|
/* init volume */
|
||||||
outw(0x0808, FM801_REG(chip, PCM_VOL));
|
outw(0x0808, FM801_REG(chip, PCM_VOL));
|
||||||
outw(0x9f1f, FM801_REG(chip, FM_VOL));
|
outw(0x9f1f, FM801_REG(chip, FM_VOL));
|
||||||
|
@ -1298,9 +1317,12 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||||
/* I2S control - I2S mode */
|
/* I2S control - I2S mode */
|
||||||
outw(0x0003, FM801_REG(chip, I2S_MODE));
|
outw(0x0003, FM801_REG(chip, I2S_MODE));
|
||||||
|
|
||||||
/* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */
|
/* interrupt setup */
|
||||||
cmdw = inw(FM801_REG(chip, IRQ_MASK));
|
cmdw = inw(FM801_REG(chip, IRQ_MASK));
|
||||||
cmdw &= ~0x0083;
|
if (chip->irq < 0)
|
||||||
|
cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */
|
||||||
|
else
|
||||||
|
cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */
|
||||||
outw(cmdw, FM801_REG(chip, IRQ_MASK));
|
outw(cmdw, FM801_REG(chip, IRQ_MASK));
|
||||||
|
|
||||||
/* interrupt clear */
|
/* interrupt clear */
|
||||||
|
@ -1365,12 +1387,14 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||||
chip->card = card;
|
chip->card = card;
|
||||||
chip->pci = pci;
|
chip->pci = pci;
|
||||||
chip->irq = -1;
|
chip->irq = -1;
|
||||||
|
chip->tea575x_tuner = tea575x_tuner;
|
||||||
if ((err = pci_request_regions(pci, "FM801")) < 0) {
|
if ((err = pci_request_regions(pci, "FM801")) < 0) {
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
pci_disable_device(pci);
|
pci_disable_device(pci);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
chip->port = pci_resource_start(pci, 0);
|
chip->port = pci_resource_start(pci, 0);
|
||||||
|
if ((tea575x_tuner & 0x0010) == 0) {
|
||||||
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
||||||
"FM801", chip)) {
|
"FM801", chip)) {
|
||||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
|
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
|
||||||
|
@ -1379,6 +1403,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||||
}
|
}
|
||||||
chip->irq = pci->irq;
|
chip->irq = pci->irq;
|
||||||
pci_set_master(pci);
|
pci_set_master(pci);
|
||||||
|
}
|
||||||
|
|
||||||
pci_read_config_byte(pci, PCI_REVISION_ID, &rev);
|
pci_read_config_byte(pci, PCI_REVISION_ID, &rev);
|
||||||
if (rev >= 0xb1) /* FM801-AU */
|
if (rev >= 0xb1) /* FM801-AU */
|
||||||
|
@ -1394,12 +1419,12 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||||
snd_card_set_dev(card, &pci->dev);
|
snd_card_set_dev(card, &pci->dev);
|
||||||
|
|
||||||
#ifdef TEA575X_RADIO
|
#ifdef TEA575X_RADIO
|
||||||
if (tea575x_tuner > 0 && (tea575x_tuner & 0xffff) < 4) {
|
if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
|
||||||
chip->tea.dev_nr = tea575x_tuner >> 16;
|
chip->tea.dev_nr = tea575x_tuner >> 16;
|
||||||
chip->tea.card = card;
|
chip->tea.card = card;
|
||||||
chip->tea.freq_fixup = 10700;
|
chip->tea.freq_fixup = 10700;
|
||||||
chip->tea.private_data = chip;
|
chip->tea.private_data = chip;
|
||||||
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0xffff) - 1];
|
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1];
|
||||||
snd_tea575x_init(&chip->tea);
|
snd_tea575x_init(&chip->tea);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1439,6 +1464,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
|
||||||
sprintf(card->longname, "%s at 0x%lx, irq %i",
|
sprintf(card->longname, "%s at 0x%lx, irq %i",
|
||||||
card->shortname, chip->port, chip->irq);
|
card->shortname, chip->port, chip->irq);
|
||||||
|
|
||||||
|
if (tea575x_tuner[dev] & 0x0010)
|
||||||
|
goto __fm801_tuner_only;
|
||||||
|
|
||||||
if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
|
if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
|
||||||
snd_card_free(card);
|
snd_card_free(card);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1465,6 +1493,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__fm801_tuner_only:
|
||||||
if ((err = snd_card_register(card)) < 0) {
|
if ((err = snd_card_register(card)) < 0) {
|
||||||
snd_card_free(card);
|
snd_card_free(card);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include "hda_codec.h"
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
|
|
||||||
|
@ -50,8 +51,10 @@ struct hda_vendor_id {
|
||||||
/* codec vendor labels */
|
/* codec vendor labels */
|
||||||
static struct hda_vendor_id hda_vendor_ids[] = {
|
static struct hda_vendor_id hda_vendor_ids[] = {
|
||||||
{ 0x10ec, "Realtek" },
|
{ 0x10ec, "Realtek" },
|
||||||
|
{ 0x1057, "Motorola" },
|
||||||
{ 0x11d4, "Analog Devices" },
|
{ 0x11d4, "Analog Devices" },
|
||||||
{ 0x13f6, "C-Media" },
|
{ 0x13f6, "C-Media" },
|
||||||
|
{ 0x14f1, "Conexant" },
|
||||||
{ 0x434d, "C-Media" },
|
{ 0x434d, "C-Media" },
|
||||||
{ 0x8384, "SigmaTel" },
|
{ 0x8384, "SigmaTel" },
|
||||||
{} /* terminator */
|
{} /* terminator */
|
||||||
|
@ -841,6 +844,31 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
||||||
|
unsigned int size, unsigned int __user *_tlv)
|
||||||
|
{
|
||||||
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
hda_nid_t nid = get_amp_nid(kcontrol);
|
||||||
|
int dir = get_amp_direction(kcontrol);
|
||||||
|
u32 caps, val1, val2;
|
||||||
|
|
||||||
|
if (size < 4 * sizeof(unsigned int))
|
||||||
|
return -ENOMEM;
|
||||||
|
caps = query_amp_caps(codec, nid, dir);
|
||||||
|
val2 = (((caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT) + 1) * 25;
|
||||||
|
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
|
||||||
|
val1 = ((int)val1) * ((int)val2);
|
||||||
|
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
|
||||||
|
return -EFAULT;
|
||||||
|
if (put_user(2 * sizeof(unsigned int), _tlv + 1))
|
||||||
|
return -EFAULT;
|
||||||
|
if (put_user(val1, _tlv + 2))
|
||||||
|
return -EFAULT;
|
||||||
|
if (put_user(val2, _tlv + 3))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* switch */
|
/* switch */
|
||||||
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
@ -1477,10 +1505,10 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||||
formats |= SNDRV_PCM_FMTBIT_S32_LE;
|
formats |= SNDRV_PCM_FMTBIT_S32_LE;
|
||||||
if (val & AC_SUPPCM_BITS_32)
|
if (val & AC_SUPPCM_BITS_32)
|
||||||
bps = 32;
|
bps = 32;
|
||||||
else if (val & AC_SUPPCM_BITS_20)
|
|
||||||
bps = 20;
|
|
||||||
else if (val & AC_SUPPCM_BITS_24)
|
else if (val & AC_SUPPCM_BITS_24)
|
||||||
bps = 24;
|
bps = 24;
|
||||||
|
else if (val & AC_SUPPCM_BITS_20)
|
||||||
|
bps = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */
|
else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */
|
||||||
|
@ -1916,7 +1944,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o
|
||||||
|
|
||||||
/* front */
|
/* front */
|
||||||
snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
|
snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
|
||||||
if (mout->hp_nid)
|
if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT])
|
||||||
/* headphone out will just decode front left/right (stereo) */
|
/* headphone out will just decode front left/right (stereo) */
|
||||||
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
|
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
|
||||||
/* extra outputs copied from front */
|
/* extra outputs copied from front */
|
||||||
|
@ -1984,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
|
||||||
* in the order of front, rear, CLFE, side, ...
|
* in the order of front, rear, CLFE, side, ...
|
||||||
*
|
*
|
||||||
* If more extra outputs (speaker and headphone) are found, the pins are
|
* If more extra outputs (speaker and headphone) are found, the pins are
|
||||||
* assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack
|
* assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
|
||||||
* is detected, one of speaker of HP pins is assigned as the primary
|
* is detected, one of speaker of HP pins is assigned as the primary
|
||||||
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
|
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
|
||||||
* if any analog output exists.
|
* if any analog output exists.
|
||||||
|
@ -2046,14 +2074,26 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
cfg->speaker_outs++;
|
cfg->speaker_outs++;
|
||||||
break;
|
break;
|
||||||
case AC_JACK_HP_OUT:
|
case AC_JACK_HP_OUT:
|
||||||
cfg->hp_pin = nid;
|
if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
|
||||||
|
continue;
|
||||||
|
cfg->hp_pins[cfg->hp_outs] = nid;
|
||||||
|
cfg->hp_outs++;
|
||||||
break;
|
break;
|
||||||
case AC_JACK_MIC_IN:
|
case AC_JACK_MIC_IN: {
|
||||||
if (loc == AC_JACK_LOC_FRONT)
|
int preferred, alt;
|
||||||
cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid;
|
if (loc == AC_JACK_LOC_FRONT) {
|
||||||
else
|
preferred = AUTO_PIN_FRONT_MIC;
|
||||||
cfg->input_pins[AUTO_PIN_MIC] = nid;
|
alt = AUTO_PIN_MIC;
|
||||||
|
} else {
|
||||||
|
preferred = AUTO_PIN_MIC;
|
||||||
|
alt = AUTO_PIN_FRONT_MIC;
|
||||||
|
}
|
||||||
|
if (!cfg->input_pins[preferred])
|
||||||
|
cfg->input_pins[preferred] = nid;
|
||||||
|
else if (!cfg->input_pins[alt])
|
||||||
|
cfg->input_pins[alt] = nid;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case AC_JACK_LINE_IN:
|
case AC_JACK_LINE_IN:
|
||||||
if (loc == AC_JACK_LOC_FRONT)
|
if (loc == AC_JACK_LOC_FRONT)
|
||||||
cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
|
cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
|
||||||
|
@ -2119,8 +2159,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
cfg->speaker_outs, cfg->speaker_pins[0],
|
cfg->speaker_outs, cfg->speaker_pins[0],
|
||||||
cfg->speaker_pins[1], cfg->speaker_pins[2],
|
cfg->speaker_pins[1], cfg->speaker_pins[2],
|
||||||
cfg->speaker_pins[3], cfg->speaker_pins[4]);
|
cfg->speaker_pins[3], cfg->speaker_pins[4]);
|
||||||
snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n",
|
snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
||||||
cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin);
|
cfg->hp_outs, cfg->hp_pins[0],
|
||||||
|
cfg->hp_pins[1], cfg->hp_pins[2],
|
||||||
|
cfg->hp_pins[3], cfg->hp_pins[4]);
|
||||||
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
|
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
|
||||||
" cd=0x%x, aux=0x%x\n",
|
" cd=0x%x, aux=0x%x\n",
|
||||||
cfg->input_pins[AUTO_PIN_MIC],
|
cfg->input_pins[AUTO_PIN_MIC],
|
||||||
|
@ -2141,10 +2183,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
sizeof(cfg->speaker_pins));
|
sizeof(cfg->speaker_pins));
|
||||||
cfg->speaker_outs = 0;
|
cfg->speaker_outs = 0;
|
||||||
memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
|
memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
|
||||||
} else if (cfg->hp_pin) {
|
} else if (cfg->hp_outs) {
|
||||||
cfg->line_outs = 1;
|
cfg->line_outs = cfg->hp_outs;
|
||||||
cfg->line_out_pins[0] = cfg->hp_pin;
|
memcpy(cfg->line_out_pins, cfg->hp_pins,
|
||||||
cfg->hp_pin = 0;
|
sizeof(cfg->hp_pins));
|
||||||
|
cfg->hp_outs = 0;
|
||||||
|
memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,18 @@ struct hda_gnode {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* patch-specific record */
|
/* patch-specific record */
|
||||||
|
|
||||||
|
#define MAX_PCM_VOLS 2
|
||||||
|
struct pcm_vol {
|
||||||
|
struct hda_gnode *node; /* Node for PCM volume */
|
||||||
|
unsigned int index; /* connection of PCM volume */
|
||||||
|
};
|
||||||
|
|
||||||
struct hda_gspec {
|
struct hda_gspec {
|
||||||
struct hda_gnode *dac_node[2]; /* DAC node */
|
struct hda_gnode *dac_node[2]; /* DAC node */
|
||||||
struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */
|
struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */
|
||||||
struct hda_gnode *pcm_vol_node[2]; /* Node for PCM volume */
|
struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */
|
||||||
unsigned int pcm_vol_index[2]; /* connection of PCM volume */
|
unsigned int pcm_vol_nodes; /* number of PCM volumes */
|
||||||
|
|
||||||
struct hda_gnode *adc_node; /* ADC node */
|
struct hda_gnode *adc_node; /* ADC node */
|
||||||
struct hda_gnode *cap_vol_node; /* Node for capture volume */
|
struct hda_gnode *cap_vol_node; /* Node for capture volume */
|
||||||
|
@ -285,9 +292,11 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec,
|
||||||
return node == spec->dac_node[dac_idx];
|
return node == spec->dac_node[dac_idx];
|
||||||
}
|
}
|
||||||
spec->dac_node[dac_idx] = node;
|
spec->dac_node[dac_idx] = node;
|
||||||
if (node->wid_caps & AC_WCAP_OUT_AMP) {
|
if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
|
||||||
spec->pcm_vol_node[dac_idx] = node;
|
spec->pcm_vol_nodes < MAX_PCM_VOLS) {
|
||||||
spec->pcm_vol_index[dac_idx] = 0;
|
spec->pcm_vol[spec->pcm_vol_nodes].node = node;
|
||||||
|
spec->pcm_vol[spec->pcm_vol_nodes].index = 0;
|
||||||
|
spec->pcm_vol_nodes++;
|
||||||
}
|
}
|
||||||
return 1; /* found */
|
return 1; /* found */
|
||||||
}
|
}
|
||||||
|
@ -307,13 +316,16 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec,
|
||||||
select_input_connection(codec, node, i);
|
select_input_connection(codec, node, i);
|
||||||
unmute_input(codec, node, i);
|
unmute_input(codec, node, i);
|
||||||
unmute_output(codec, node);
|
unmute_output(codec, node);
|
||||||
if (! spec->pcm_vol_node[dac_idx]) {
|
if (spec->dac_node[dac_idx] &&
|
||||||
if (node->wid_caps & AC_WCAP_IN_AMP) {
|
spec->pcm_vol_nodes < MAX_PCM_VOLS &&
|
||||||
spec->pcm_vol_node[dac_idx] = node;
|
!(spec->dac_node[dac_idx]->wid_caps &
|
||||||
spec->pcm_vol_index[dac_idx] = i;
|
AC_WCAP_OUT_AMP)) {
|
||||||
} else if (node->wid_caps & AC_WCAP_OUT_AMP) {
|
if ((node->wid_caps & AC_WCAP_IN_AMP) ||
|
||||||
spec->pcm_vol_node[dac_idx] = node;
|
(node->wid_caps & AC_WCAP_OUT_AMP)) {
|
||||||
spec->pcm_vol_index[dac_idx] = 0;
|
int n = spec->pcm_vol_nodes;
|
||||||
|
spec->pcm_vol[n].node = node;
|
||||||
|
spec->pcm_vol[n].index = i;
|
||||||
|
spec->pcm_vol_nodes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -370,7 +382,9 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec,
|
||||||
/* set PIN-Out enable */
|
/* set PIN-Out enable */
|
||||||
snd_hda_codec_write(codec, node->nid, 0,
|
snd_hda_codec_write(codec, node->nid, 0,
|
||||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||||
AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
|
AC_PINCTL_OUT_EN |
|
||||||
|
((node->pin_caps & AC_PINCAP_HP_DRV) ?
|
||||||
|
AC_PINCTL_HP_EN : 0));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,14 +475,19 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
|
||||||
return "Front Line";
|
return "Front Line";
|
||||||
return "Line";
|
return "Line";
|
||||||
case AC_JACK_CD:
|
case AC_JACK_CD:
|
||||||
|
#if 0
|
||||||
if (pinctl)
|
if (pinctl)
|
||||||
*pinctl |= AC_PINCTL_VREF_GRD;
|
*pinctl |= AC_PINCTL_VREF_GRD;
|
||||||
|
#endif
|
||||||
return "CD";
|
return "CD";
|
||||||
case AC_JACK_AUX:
|
case AC_JACK_AUX:
|
||||||
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
|
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
|
||||||
return "Front Aux";
|
return "Front Aux";
|
||||||
return "Aux";
|
return "Aux";
|
||||||
case AC_JACK_MIC_IN:
|
case AC_JACK_MIC_IN:
|
||||||
|
if (node->pin_caps &
|
||||||
|
(AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))
|
||||||
|
*pinctl |= AC_PINCTL_VREF_80;
|
||||||
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
|
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
|
||||||
return "Front Mic";
|
return "Front Mic";
|
||||||
return "Mic";
|
return "Mic";
|
||||||
|
@ -556,6 +575,29 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
||||||
return 1; /* found */
|
return 1; /* found */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* add a capture source element */
|
||||||
|
static void add_cap_src(struct hda_gspec *spec, int idx)
|
||||||
|
{
|
||||||
|
struct hda_input_mux_item *csrc;
|
||||||
|
char *buf;
|
||||||
|
int num, ocap;
|
||||||
|
|
||||||
|
num = spec->input_mux.num_items;
|
||||||
|
csrc = &spec->input_mux.items[num];
|
||||||
|
buf = spec->cap_labels[num];
|
||||||
|
for (ocap = 0; ocap < num; ocap++) {
|
||||||
|
if (! strcmp(buf, spec->cap_labels[ocap])) {
|
||||||
|
/* same label already exists,
|
||||||
|
* put the index number to be unique
|
||||||
|
*/
|
||||||
|
sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
csrc->index = idx;
|
||||||
|
spec->input_mux.num_items++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse input
|
* parse input
|
||||||
*/
|
*/
|
||||||
|
@ -576,28 +618,26 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
|
||||||
* if it reaches to a proper input PIN, add the path as the
|
* if it reaches to a proper input PIN, add the path as the
|
||||||
* input path.
|
* input path.
|
||||||
*/
|
*/
|
||||||
|
/* first, check the direct connections to PIN widgets */
|
||||||
for (i = 0; i < adc_node->nconns; i++) {
|
for (i = 0; i < adc_node->nconns; i++) {
|
||||||
node = hda_get_node(spec, adc_node->conn_list[i]);
|
node = hda_get_node(spec, adc_node->conn_list[i]);
|
||||||
if (! node)
|
if (node && node->type == AC_WID_PIN) {
|
||||||
continue;
|
|
||||||
err = parse_adc_sub_nodes(codec, spec, node);
|
err = parse_adc_sub_nodes(codec, spec, node);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
else if (err > 0) {
|
else if (err > 0)
|
||||||
struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items];
|
add_cap_src(spec, i);
|
||||||
char *buf = spec->cap_labels[spec->input_mux.num_items];
|
|
||||||
int ocap;
|
|
||||||
for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) {
|
|
||||||
if (! strcmp(buf, spec->cap_labels[ocap])) {
|
|
||||||
/* same label already exists,
|
|
||||||
* put the index number to be unique
|
|
||||||
*/
|
|
||||||
sprintf(buf, "%s %d", spec->cap_labels[ocap],
|
|
||||||
spec->input_mux.num_items);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
csrc->index = i;
|
/* ... then check the rests, more complicated connections */
|
||||||
spec->input_mux.num_items++;
|
for (i = 0; i < adc_node->nconns; i++) {
|
||||||
|
node = hda_get_node(spec, adc_node->conn_list[i]);
|
||||||
|
if (node && node->type != AC_WID_PIN) {
|
||||||
|
err = parse_adc_sub_nodes(codec, spec, node);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
else if (err > 0)
|
||||||
|
add_cap_src(spec, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,9 +687,6 @@ static int parse_input(struct hda_codec *codec)
|
||||||
/*
|
/*
|
||||||
* create mixer controls if possible
|
* create mixer controls if possible
|
||||||
*/
|
*/
|
||||||
#define DIR_OUT 0x1
|
|
||||||
#define DIR_IN 0x2
|
|
||||||
|
|
||||||
static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
|
static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
|
||||||
unsigned int index, const char *type, const char *dir_sfx)
|
unsigned int index, const char *type, const char *dir_sfx)
|
||||||
{
|
{
|
||||||
|
@ -722,18 +759,37 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con
|
||||||
/*
|
/*
|
||||||
* build output mixer controls
|
* build output mixer controls
|
||||||
*/
|
*/
|
||||||
|
static int create_output_mixers(struct hda_codec *codec, const char **names)
|
||||||
|
{
|
||||||
|
struct hda_gspec *spec = codec->spec;
|
||||||
|
int i, err;
|
||||||
|
|
||||||
|
for (i = 0; i < spec->pcm_vol_nodes; i++) {
|
||||||
|
err = create_mixer(codec, spec->pcm_vol[i].node,
|
||||||
|
spec->pcm_vol[i].index,
|
||||||
|
names[i], "Playback");
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int build_output_controls(struct hda_codec *codec)
|
static int build_output_controls(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct hda_gspec *spec = codec->spec;
|
struct hda_gspec *spec = codec->spec;
|
||||||
static const char *types[2] = { "Master", "Headphone" };
|
static const char *types_speaker[] = { "Speaker", "Headphone" };
|
||||||
int i, err;
|
static const char *types_line[] = { "Front", "Headphone" };
|
||||||
|
|
||||||
for (i = 0; i < 2 && spec->pcm_vol_node[i]; i++) {
|
switch (spec->pcm_vol_nodes) {
|
||||||
err = create_mixer(codec, spec->pcm_vol_node[i],
|
case 1:
|
||||||
spec->pcm_vol_index[i],
|
return create_mixer(codec, spec->pcm_vol[0].node,
|
||||||
types[i], "Playback");
|
spec->pcm_vol[0].index,
|
||||||
if (err < 0)
|
"Master", "Playback");
|
||||||
return err;
|
case 2:
|
||||||
|
if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER)
|
||||||
|
return create_output_mixers(codec, types_speaker);
|
||||||
|
else
|
||||||
|
return create_output_mixers(codec, types_line);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -743,16 +799,7 @@ static int build_input_controls(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct hda_gspec *spec = codec->spec;
|
struct hda_gspec *spec = codec->spec;
|
||||||
struct hda_gnode *adc_node = spec->adc_node;
|
struct hda_gnode *adc_node = spec->adc_node;
|
||||||
int err;
|
int i, err;
|
||||||
|
|
||||||
if (! adc_node)
|
|
||||||
return 0; /* not found */
|
|
||||||
|
|
||||||
/* create capture volume and switch controls if the ADC has an amp */
|
|
||||||
err = create_mixer(codec, adc_node, 0, NULL, "Capture");
|
|
||||||
|
|
||||||
/* create input MUX if multiple sources are available */
|
|
||||||
if (spec->input_mux.num_items > 1) {
|
|
||||||
static struct snd_kcontrol_new cap_sel = {
|
static struct snd_kcontrol_new cap_sel = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
.name = "Capture Source",
|
.name = "Capture Source",
|
||||||
|
@ -760,11 +807,49 @@ static int build_input_controls(struct hda_codec *codec)
|
||||||
.get = capture_source_get,
|
.get = capture_source_get,
|
||||||
.put = capture_source_put,
|
.put = capture_source_put,
|
||||||
};
|
};
|
||||||
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0)
|
|
||||||
return err;
|
if (! adc_node || ! spec->input_mux.num_items)
|
||||||
|
return 0; /* not found */
|
||||||
|
|
||||||
spec->cur_cap_src = 0;
|
spec->cur_cap_src = 0;
|
||||||
select_input_connection(codec, adc_node, spec->input_mux.items[0].index);
|
select_input_connection(codec, adc_node,
|
||||||
|
spec->input_mux.items[0].index);
|
||||||
|
|
||||||
|
/* create capture volume and switch controls if the ADC has an amp */
|
||||||
|
/* do we have only a single item? */
|
||||||
|
if (spec->input_mux.num_items == 1) {
|
||||||
|
err = create_mixer(codec, adc_node,
|
||||||
|
spec->input_mux.items[0].index,
|
||||||
|
NULL, "Capture");
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create input MUX if multiple sources are available */
|
||||||
|
if ((err = snd_ctl_add(codec->bus->card,
|
||||||
|
snd_ctl_new1(&cap_sel, codec))) < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* no volume control? */
|
||||||
|
if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) ||
|
||||||
|
! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < spec->input_mux.num_items; i++) {
|
||||||
|
struct snd_kcontrol_new knew;
|
||||||
|
char name[32];
|
||||||
|
sprintf(name, "%s Capture Volume",
|
||||||
|
spec->input_mux.items[i].label);
|
||||||
|
knew = (struct snd_kcontrol_new)
|
||||||
|
HDA_CODEC_VOLUME(name, adc_node->nid,
|
||||||
|
spec->input_mux.items[i].index,
|
||||||
|
HDA_INPUT);
|
||||||
|
if ((err = snd_ctl_add(codec->bus->card,
|
||||||
|
snd_ctl_new1(&knew, codec))) < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ static char *model;
|
||||||
static int position_fix;
|
static int position_fix;
|
||||||
static int probe_mask = -1;
|
static int probe_mask = -1;
|
||||||
static int single_cmd;
|
static int single_cmd;
|
||||||
|
static int disable_msi;
|
||||||
|
|
||||||
module_param(index, int, 0444);
|
module_param(index, int, 0444);
|
||||||
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
||||||
|
@ -68,6 +69,8 @@ module_param(probe_mask, int, 0444);
|
||||||
MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
|
MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
|
||||||
module_param(single_cmd, bool, 0444);
|
module_param(single_cmd, bool, 0444);
|
||||||
MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
|
MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
|
||||||
|
module_param(disable_msi, int, 0);
|
||||||
|
MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
|
||||||
|
|
||||||
|
|
||||||
/* just for backward compatibility */
|
/* just for backward compatibility */
|
||||||
|
@ -252,7 +255,7 @@ enum {
|
||||||
struct azx_dev {
|
struct azx_dev {
|
||||||
u32 *bdl; /* virtual address of the BDL */
|
u32 *bdl; /* virtual address of the BDL */
|
||||||
dma_addr_t bdl_addr; /* physical address of the BDL */
|
dma_addr_t bdl_addr; /* physical address of the BDL */
|
||||||
volatile u32 *posbuf; /* position buffer pointer */
|
u32 *posbuf; /* position buffer pointer */
|
||||||
|
|
||||||
unsigned int bufsize; /* size of the play buffer in bytes */
|
unsigned int bufsize; /* size of the play buffer in bytes */
|
||||||
unsigned int fragsize; /* size of each period in bytes */
|
unsigned int fragsize; /* size of each period in bytes */
|
||||||
|
@ -332,6 +335,7 @@ struct azx {
|
||||||
int position_fix;
|
int position_fix;
|
||||||
unsigned int initialized :1;
|
unsigned int initialized :1;
|
||||||
unsigned int single_cmd :1;
|
unsigned int single_cmd :1;
|
||||||
|
unsigned int polling_mode :1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* driver types */
|
/* driver types */
|
||||||
|
@ -516,12 +520,29 @@ static void azx_update_rirb(struct azx *chip)
|
||||||
static unsigned int azx_rirb_get_response(struct hda_codec *codec)
|
static unsigned int azx_rirb_get_response(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct azx *chip = codec->bus->private_data;
|
struct azx *chip = codec->bus->private_data;
|
||||||
int timeout = 50;
|
unsigned long timeout;
|
||||||
|
|
||||||
while (chip->rirb.cmds) {
|
again:
|
||||||
if (! --timeout) {
|
timeout = jiffies + msecs_to_jiffies(1000);
|
||||||
snd_printk(KERN_ERR
|
do {
|
||||||
"hda_intel: azx_get_response timeout, "
|
if (chip->polling_mode) {
|
||||||
|
spin_lock_irq(&chip->reg_lock);
|
||||||
|
azx_update_rirb(chip);
|
||||||
|
spin_unlock_irq(&chip->reg_lock);
|
||||||
|
}
|
||||||
|
if (! chip->rirb.cmds)
|
||||||
|
return chip->rirb.res; /* the last value */
|
||||||
|
schedule_timeout_interruptible(1);
|
||||||
|
} while (time_after_eq(timeout, jiffies));
|
||||||
|
|
||||||
|
if (!chip->polling_mode) {
|
||||||
|
snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
|
||||||
|
"switching to polling mode...\n");
|
||||||
|
chip->polling_mode = 1;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
|
||||||
"switching to single_cmd mode...\n");
|
"switching to single_cmd mode...\n");
|
||||||
chip->rirb.rp = azx_readb(chip, RIRBWP);
|
chip->rirb.rp = azx_readb(chip, RIRBWP);
|
||||||
chip->rirb.cmds = 0;
|
chip->rirb.cmds = 0;
|
||||||
|
@ -530,10 +551,6 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
|
||||||
azx_free_cmd_io(chip);
|
azx_free_cmd_io(chip);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
msleep(1);
|
|
||||||
}
|
|
||||||
return chip->rirb.res; /* the last value */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the single immediate command instead of CORB/RIRB for simplicity
|
* Use the single immediate command instead of CORB/RIRB for simplicity
|
||||||
|
@ -645,7 +662,7 @@ static int azx_reset(struct azx *chip)
|
||||||
while (!azx_readb(chip, GCTL) && --count)
|
while (!azx_readb(chip, GCTL) && --count)
|
||||||
msleep(1);
|
msleep(1);
|
||||||
|
|
||||||
/* Brent Chartrand said to wait >= 540us for codecs to intialize */
|
/* Brent Chartrand said to wait >= 540us for codecs to initialize */
|
||||||
msleep(1);
|
msleep(1);
|
||||||
|
|
||||||
/* check to see if controller is ready */
|
/* check to see if controller is ready */
|
||||||
|
@ -999,8 +1016,9 @@ static struct snd_pcm_hardware azx_pcm_hw = {
|
||||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||||
SNDRV_PCM_INFO_MMAP_VALID |
|
SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
SNDRV_PCM_INFO_PAUSE /*|*/
|
/* No full-resume yet implemented */
|
||||||
/*SNDRV_PCM_INFO_RESUME*/),
|
/* SNDRV_PCM_INFO_RESUME |*/
|
||||||
|
SNDRV_PCM_INFO_PAUSE),
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.rates = SNDRV_PCM_RATE_48000,
|
.rates = SNDRV_PCM_RATE_48000,
|
||||||
.rate_min = 48000,
|
.rate_min = 48000,
|
||||||
|
@ -1178,7 +1196,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||||
if (chip->position_fix == POS_FIX_POSBUF ||
|
if (chip->position_fix == POS_FIX_POSBUF ||
|
||||||
chip->position_fix == POS_FIX_AUTO) {
|
chip->position_fix == POS_FIX_AUTO) {
|
||||||
/* use the position buffer */
|
/* use the position buffer */
|
||||||
pos = *azx_dev->posbuf;
|
pos = le32_to_cpu(*azx_dev->posbuf);
|
||||||
if (chip->position_fix == POS_FIX_AUTO &&
|
if (chip->position_fix == POS_FIX_AUTO &&
|
||||||
azx_dev->period_intr == 1 && ! pos) {
|
azx_dev->period_intr == 1 && ! pos) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
|
@ -1222,7 +1240,12 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
|
||||||
struct snd_pcm *pcm;
|
struct snd_pcm *pcm;
|
||||||
struct azx_pcm *apcm;
|
struct azx_pcm *apcm;
|
||||||
|
|
||||||
snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL);
|
/* if no substreams are defined for both playback and capture,
|
||||||
|
* it's just a placeholder. ignore it.
|
||||||
|
*/
|
||||||
|
if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
|
||||||
|
return 0;
|
||||||
|
|
||||||
snd_assert(cpcm->name, return -EINVAL);
|
snd_assert(cpcm->name, return -EINVAL);
|
||||||
|
|
||||||
err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
|
err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
|
||||||
|
@ -1248,6 +1271,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
|
||||||
snd_dma_pci_data(chip->pci),
|
snd_dma_pci_data(chip->pci),
|
||||||
1024 * 64, 1024 * 128);
|
1024 * 64, 1024 * 128);
|
||||||
chip->pcm[pcm_dev] = pcm;
|
chip->pcm[pcm_dev] = pcm;
|
||||||
|
if (chip->pcm_devs < pcm_dev + 1)
|
||||||
chip->pcm_devs = pcm_dev + 1;
|
chip->pcm_devs = pcm_dev + 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1326,7 +1350,7 @@ static int __devinit azx_init_stream(struct azx *chip)
|
||||||
struct azx_dev *azx_dev = &chip->azx_dev[i];
|
struct azx_dev *azx_dev = &chip->azx_dev[i];
|
||||||
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
|
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
|
||||||
azx_dev->bdl_addr = chip->bdl.addr + off;
|
azx_dev->bdl_addr = chip->bdl.addr + off;
|
||||||
azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
|
azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
|
||||||
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
||||||
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
|
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
|
||||||
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
|
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
|
||||||
|
@ -1355,6 +1379,10 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
|
||||||
snd_pcm_suspend_all(chip->pcm[i]);
|
snd_pcm_suspend_all(chip->pcm[i]);
|
||||||
snd_hda_suspend(chip->bus, state);
|
snd_hda_suspend(chip->bus, state);
|
||||||
azx_free_cmd_io(chip);
|
azx_free_cmd_io(chip);
|
||||||
|
if (chip->irq >= 0)
|
||||||
|
free_irq(chip->irq, chip);
|
||||||
|
if (!disable_msi)
|
||||||
|
pci_disable_msi(chip->pci);
|
||||||
pci_disable_device(pci);
|
pci_disable_device(pci);
|
||||||
pci_save_state(pci);
|
pci_save_state(pci);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1367,6 +1395,12 @@ static int azx_resume(struct pci_dev *pci)
|
||||||
|
|
||||||
pci_restore_state(pci);
|
pci_restore_state(pci);
|
||||||
pci_enable_device(pci);
|
pci_enable_device(pci);
|
||||||
|
if (!disable_msi)
|
||||||
|
pci_enable_msi(pci);
|
||||||
|
/* FIXME: need proper error handling */
|
||||||
|
request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
||||||
|
"HDA Intel", chip);
|
||||||
|
chip->irq = pci->irq;
|
||||||
pci_set_master(pci);
|
pci_set_master(pci);
|
||||||
azx_init_chip(chip);
|
azx_init_chip(chip);
|
||||||
snd_hda_resume(chip->bus);
|
snd_hda_resume(chip->bus);
|
||||||
|
@ -1398,12 +1432,14 @@ static int azx_free(struct azx *chip)
|
||||||
azx_writel(chip, DPLBASE, 0);
|
azx_writel(chip, DPLBASE, 0);
|
||||||
azx_writel(chip, DPUBASE, 0);
|
azx_writel(chip, DPUBASE, 0);
|
||||||
|
|
||||||
/* wait a little for interrupts to finish */
|
synchronize_irq(chip->irq);
|
||||||
msleep(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->irq >= 0)
|
if (chip->irq >= 0) {
|
||||||
free_irq(chip->irq, (void*)chip);
|
free_irq(chip->irq, (void*)chip);
|
||||||
|
if (!disable_msi)
|
||||||
|
pci_disable_msi(chip->pci);
|
||||||
|
}
|
||||||
if (chip->remap_addr)
|
if (chip->remap_addr)
|
||||||
iounmap(chip->remap_addr);
|
iounmap(chip->remap_addr);
|
||||||
|
|
||||||
|
@ -1434,19 +1470,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
|
||||||
struct azx **rchip)
|
struct azx **rchip)
|
||||||
{
|
{
|
||||||
struct azx *chip;
|
struct azx *chip;
|
||||||
int err = 0;
|
int err;
|
||||||
static struct snd_device_ops ops = {
|
static struct snd_device_ops ops = {
|
||||||
.dev_free = azx_dev_free,
|
.dev_free = azx_dev_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
*rchip = NULL;
|
*rchip = NULL;
|
||||||
|
|
||||||
if ((err = pci_enable_device(pci)) < 0)
|
err = pci_enable_device(pci);
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||||
|
if (!chip) {
|
||||||
if (NULL == chip) {
|
|
||||||
snd_printk(KERN_ERR SFX "cannot allocate chip\n");
|
snd_printk(KERN_ERR SFX "cannot allocate chip\n");
|
||||||
pci_disable_device(pci);
|
pci_disable_device(pci);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1472,7 +1508,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
|
err = pci_request_regions(pci, "ICH HD audio");
|
||||||
|
if (err < 0) {
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
pci_disable_device(pci);
|
pci_disable_device(pci);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1486,6 +1523,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!disable_msi)
|
||||||
|
pci_enable_msi(pci);
|
||||||
|
|
||||||
if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
||||||
"HDA Intel", (void*)chip)) {
|
"HDA Intel", (void*)chip)) {
|
||||||
snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
|
snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
|
||||||
|
@ -1577,16 +1617,16 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
|
||||||
{
|
{
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
struct azx *chip;
|
struct azx *chip;
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
card = snd_card_new(index, id, THIS_MODULE, 0);
|
card = snd_card_new(index, id, THIS_MODULE, 0);
|
||||||
if (NULL == card) {
|
if (!card) {
|
||||||
snd_printk(KERN_ERR SFX "Error creating card!\n");
|
snd_printk(KERN_ERR SFX "Error creating card!\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = azx_create(card, pci, pci_id->driver_data,
|
err = azx_create(card, pci, pci_id->driver_data, &chip);
|
||||||
&chip)) < 0) {
|
if (err < 0) {
|
||||||
snd_card_free(card);
|
snd_card_free(card);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,13 @@
|
||||||
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
||||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
|
||||||
.info = snd_hda_mixer_amp_volume_info, \
|
.info = snd_hda_mixer_amp_volume_info, \
|
||||||
.get = snd_hda_mixer_amp_volume_get, \
|
.get = snd_hda_mixer_amp_volume_get, \
|
||||||
.put = snd_hda_mixer_amp_volume_put, \
|
.put = snd_hda_mixer_amp_volume_put, \
|
||||||
|
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
|
||||||
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
|
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
|
||||||
/* stereo volume with index */
|
/* stereo volume with index */
|
||||||
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
|
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
|
||||||
|
@ -63,6 +67,7 @@
|
||||||
int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
|
int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
|
||||||
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
||||||
int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
||||||
|
int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv);
|
||||||
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
|
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
|
||||||
int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
||||||
int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
|
||||||
|
@ -224,7 +229,8 @@ struct auto_pin_cfg {
|
||||||
hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
|
hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
|
||||||
int speaker_outs;
|
int speaker_outs;
|
||||||
hda_nid_t speaker_pins[5];
|
hda_nid_t speaker_pins[5];
|
||||||
hda_nid_t hp_pin;
|
int hp_outs;
|
||||||
|
hda_nid_t hp_pins[5];
|
||||||
hda_nid_t input_pins[AUTO_PIN_LAST];
|
hda_nid_t input_pins[AUTO_PIN_LAST];
|
||||||
hda_nid_t dig_out_pin;
|
hda_nid_t dig_out_pin;
|
||||||
hda_nid_t dig_in_pin;
|
hda_nid_t dig_in_pin;
|
||||||
|
|
|
@ -52,10 +52,9 @@ static void print_amp_caps(struct snd_info_buffer *buffer,
|
||||||
struct hda_codec *codec, hda_nid_t nid, int dir)
|
struct hda_codec *codec, hda_nid_t nid, int dir)
|
||||||
{
|
{
|
||||||
unsigned int caps;
|
unsigned int caps;
|
||||||
if (dir == HDA_OUTPUT)
|
caps = snd_hda_param_read(codec, nid,
|
||||||
caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP);
|
dir == HDA_OUTPUT ?
|
||||||
else
|
AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
|
||||||
caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP);
|
|
||||||
if (caps == -1 || caps == 0) {
|
if (caps == -1 || caps == 0) {
|
||||||
snd_iprintf(buffer, "N/A\n");
|
snd_iprintf(buffer, "N/A\n");
|
||||||
return;
|
return;
|
||||||
|
@ -74,10 +73,7 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (dir == HDA_OUTPUT)
|
dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
|
||||||
dir = AC_AMP_GET_OUTPUT;
|
|
||||||
else
|
|
||||||
dir = AC_AMP_GET_INPUT;
|
|
||||||
for (i = 0; i < indices; i++) {
|
for (i = 0; i < indices; i++) {
|
||||||
snd_iprintf(buffer, " [");
|
snd_iprintf(buffer, " [");
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
|
|
|
@ -488,9 +488,13 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
.name = "PCM Playback Volume",
|
.name = "PCM Playback Volume",
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
|
||||||
.info = ad1986a_pcm_amp_vol_info,
|
.info = ad1986a_pcm_amp_vol_info,
|
||||||
.get = ad1986a_pcm_amp_vol_get,
|
.get = ad1986a_pcm_amp_vol_get,
|
||||||
.put = ad1986a_pcm_amp_vol_put,
|
.put = ad1986a_pcm_amp_vol_put,
|
||||||
|
.tlv = { .c = snd_hda_mixer_amp_tlv },
|
||||||
.private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
|
.private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -637,6 +641,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
|
||||||
.info = snd_hda_mixer_amp_volume_info,
|
.info = snd_hda_mixer_amp_volume_info,
|
||||||
.get = snd_hda_mixer_amp_volume_get,
|
.get = snd_hda_mixer_amp_volume_get,
|
||||||
.put = ad1986a_laptop_master_vol_put,
|
.put = ad1986a_laptop_master_vol_put,
|
||||||
|
.tlv = { .c = snd_hda_mixer_amp_tlv },
|
||||||
.private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
|
.private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -791,6 +796,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
|
||||||
.config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
|
.config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
|
||||||
.config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
|
.config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
|
||||||
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb,
|
||||||
|
.config = AD1986A_3STACK }, /* ASUS M2NPV-VM */
|
||||||
{ .modelname = "laptop", .config = AD1986A_LAPTOP },
|
{ .modelname = "laptop", .config = AD1986A_LAPTOP },
|
||||||
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
|
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
|
||||||
.config = AD1986A_LAPTOP }, /* FSC V2060 */
|
.config = AD1986A_LAPTOP }, /* FSC V2060 */
|
||||||
|
@ -803,6 +810,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
|
||||||
.config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
|
.config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
|
||||||
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
|
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
|
||||||
.config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
|
.config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
|
||||||
|
{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc026,
|
||||||
|
.config = AD1986A_LAPTOP_EAPD }, /* Samsung X10-T2300 Culesa */
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
|
||||||
.config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */
|
.config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
|
||||||
|
@ -1626,10 +1635,12 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct ad198x_spec *spec = codec->spec;
|
struct ad198x_spec *spec = codec->spec;
|
||||||
if (spec->need_dac_fix)
|
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
|
||||||
|
spec->num_channel_mode,
|
||||||
|
&spec->multiout.max_channels);
|
||||||
|
if (! err && spec->need_dac_fix)
|
||||||
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
|
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
|
||||||
return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
|
return err;
|
||||||
spec->num_channel_mode, &spec->multiout.max_channels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 6-stack mode */
|
/* 6-stack mode */
|
||||||
|
@ -2460,7 +2471,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
|
||||||
pin = spec->autocfg.speaker_pins[0];
|
pin = spec->autocfg.speaker_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
|
ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
|
||||||
}
|
}
|
||||||
|
@ -2512,7 +2523,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
|
||||||
(err = ad1988_auto_create_extra_out(codec,
|
(err = ad1988_auto_create_extra_out(codec,
|
||||||
spec->autocfg.speaker_pins[0],
|
spec->autocfg.speaker_pins[0],
|
||||||
"Speaker")) < 0 ||
|
"Speaker")) < 0 ||
|
||||||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin,
|
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
|
||||||
"Headphone")) < 0 ||
|
"Headphone")) < 0 ||
|
||||||
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -79,6 +79,7 @@ enum {
|
||||||
ALC262_BASIC,
|
ALC262_BASIC,
|
||||||
ALC262_FUJITSU,
|
ALC262_FUJITSU,
|
||||||
ALC262_HP_BPC,
|
ALC262_HP_BPC,
|
||||||
|
ALC262_BENQ_ED8,
|
||||||
ALC262_AUTO,
|
ALC262_AUTO,
|
||||||
ALC262_MODEL_LAST /* last tag */
|
ALC262_MODEL_LAST /* last tag */
|
||||||
};
|
};
|
||||||
|
@ -89,6 +90,7 @@ enum {
|
||||||
ALC660_3ST,
|
ALC660_3ST,
|
||||||
ALC861_3ST_DIG,
|
ALC861_3ST_DIG,
|
||||||
ALC861_6ST_DIG,
|
ALC861_6ST_DIG,
|
||||||
|
ALC861_UNIWILL_M31,
|
||||||
ALC861_AUTO,
|
ALC861_AUTO,
|
||||||
ALC861_MODEL_LAST,
|
ALC861_MODEL_LAST,
|
||||||
};
|
};
|
||||||
|
@ -97,6 +99,7 @@ enum {
|
||||||
enum {
|
enum {
|
||||||
ALC882_3ST_DIG,
|
ALC882_3ST_DIG,
|
||||||
ALC882_6ST_DIG,
|
ALC882_6ST_DIG,
|
||||||
|
ALC882_ARIMA,
|
||||||
ALC882_AUTO,
|
ALC882_AUTO,
|
||||||
ALC882_MODEL_LAST,
|
ALC882_MODEL_LAST,
|
||||||
};
|
};
|
||||||
|
@ -108,6 +111,7 @@ enum {
|
||||||
ALC883_3ST_6ch,
|
ALC883_3ST_6ch,
|
||||||
ALC883_6ST_DIG,
|
ALC883_6ST_DIG,
|
||||||
ALC888_DEMO_BOARD,
|
ALC888_DEMO_BOARD,
|
||||||
|
ALC883_ACER,
|
||||||
ALC883_AUTO,
|
ALC883_AUTO,
|
||||||
ALC883_MODEL_LAST,
|
ALC883_MODEL_LAST,
|
||||||
};
|
};
|
||||||
|
@ -153,6 +157,7 @@ struct alc_spec {
|
||||||
/* channel model */
|
/* channel model */
|
||||||
const struct hda_channel_mode *channel_mode;
|
const struct hda_channel_mode *channel_mode;
|
||||||
int num_channel_mode;
|
int num_channel_mode;
|
||||||
|
int need_dac_fix;
|
||||||
|
|
||||||
/* PCM information */
|
/* PCM information */
|
||||||
struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
|
struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
|
||||||
|
@ -190,6 +195,7 @@ struct alc_config_preset {
|
||||||
hda_nid_t dig_in_nid;
|
hda_nid_t dig_in_nid;
|
||||||
unsigned int num_channel_mode;
|
unsigned int num_channel_mode;
|
||||||
const struct hda_channel_mode *channel_mode;
|
const struct hda_channel_mode *channel_mode;
|
||||||
|
int need_dac_fix;
|
||||||
unsigned int num_mux_defs;
|
unsigned int num_mux_defs;
|
||||||
const struct hda_input_mux *input_mux;
|
const struct hda_input_mux *input_mux;
|
||||||
void (*unsol_event)(struct hda_codec *, unsigned int);
|
void (*unsol_event)(struct hda_codec *, unsigned int);
|
||||||
|
@ -262,9 +268,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
|
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
|
||||||
spec->num_channel_mode,
|
spec->num_channel_mode,
|
||||||
&spec->multiout.max_channels);
|
&spec->multiout.max_channels);
|
||||||
|
if (! err && spec->need_dac_fix)
|
||||||
|
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -544,6 +553,7 @@ static void setup_preset(struct alc_spec *spec,
|
||||||
|
|
||||||
spec->channel_mode = preset->channel_mode;
|
spec->channel_mode = preset->channel_mode;
|
||||||
spec->num_channel_mode = preset->num_channel_mode;
|
spec->num_channel_mode = preset->num_channel_mode;
|
||||||
|
spec->need_dac_fix = preset->need_dac_fix;
|
||||||
|
|
||||||
spec->multiout.max_channels = spec->channel_mode[0].channels;
|
spec->multiout.max_channels = spec->channel_mode[0].channels;
|
||||||
|
|
||||||
|
@ -1348,6 +1358,10 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
|
static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
|
||||||
|
/* change to EAPD mode */
|
||||||
|
{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
|
||||||
|
{0x20, AC_VERB_SET_PROC_COEF, 0x3060},
|
||||||
|
|
||||||
/* Headphone output */
|
/* Headphone output */
|
||||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||||
/* Front output*/
|
/* Front output*/
|
||||||
|
@ -1782,25 +1796,9 @@ static int alc_build_pcms(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the use of more than one ADC is requested for the current
|
/* SPDIF for stream index #1 */
|
||||||
* model, configure a second analog capture-only PCM.
|
|
||||||
*/
|
|
||||||
if (spec->num_adc_nids > 1) {
|
|
||||||
codec->num_pcms++;
|
|
||||||
info++;
|
|
||||||
info->name = spec->stream_name_analog;
|
|
||||||
/* No playback stream for second PCM */
|
|
||||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
|
|
||||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
|
|
||||||
if (spec->stream_analog_capture) {
|
|
||||||
snd_assert(spec->adc_nids, return -EINVAL);
|
|
||||||
info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
|
|
||||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
|
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
|
||||||
codec->num_pcms++;
|
codec->num_pcms = 2;
|
||||||
info++;
|
info++;
|
||||||
info->name = spec->stream_name_digital;
|
info->name = spec->stream_name_digital;
|
||||||
if (spec->multiout.dig_out_nid &&
|
if (spec->multiout.dig_out_nid &&
|
||||||
|
@ -1815,6 +1813,24 @@ static int alc_build_pcms(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the use of more than one ADC is requested for the current
|
||||||
|
* model, configure a second analog capture-only PCM.
|
||||||
|
*/
|
||||||
|
/* Additional Analaog capture for index #2 */
|
||||||
|
if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
|
||||||
|
spec->adc_nids) {
|
||||||
|
codec->num_pcms = 3;
|
||||||
|
info++;
|
||||||
|
info->name = spec->stream_name_analog;
|
||||||
|
/* No playback stream for second PCM */
|
||||||
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
|
||||||
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
|
||||||
|
if (spec->stream_analog_capture) {
|
||||||
|
info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
|
||||||
|
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2130,7 +2146,10 @@ static struct hda_board_config alc880_cfg_tbl[] = {
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
|
||||||
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST },
|
||||||
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
|
||||||
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
|
||||||
|
@ -2145,6 +2164,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
|
||||||
{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
|
||||||
{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
|
{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
|
||||||
/* TCL S700 */
|
/* TCL S700 */
|
||||||
|
{ .modelname = "tcl", .config = ALC880_TCL_S700 },
|
||||||
{ .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
|
{ .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
|
||||||
|
|
||||||
/* Back 3 jack, front 2 jack (Internal add Aux-In) */
|
/* Back 3 jack, front 2 jack (Internal add Aux-In) */
|
||||||
|
@ -2156,8 +2176,13 @@ static struct hda_board_config alc880_cfg_tbl[] = {
|
||||||
{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
|
{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
|
||||||
{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
|
{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
|
||||||
/* Clevo m520G NB */
|
|
||||||
{ .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO },
|
/* Clevo laptops */
|
||||||
|
{ .modelname = "clevo", .config = ALC880_CLEVO },
|
||||||
|
{ .pci_subvendor = 0x1558, .pci_subdevice = 0x0520,
|
||||||
|
.config = ALC880_CLEVO }, /* Clevo m520G NB */
|
||||||
|
{ .pci_subvendor = 0x1558, .pci_subdevice = 0x0660,
|
||||||
|
.config = ALC880_CLEVO }, /* Clevo m665n */
|
||||||
|
|
||||||
/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
|
/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
|
||||||
|
@ -2222,12 +2247,16 @@ static struct hda_board_config alc880_cfg_tbl[] = {
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
|
||||||
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
|
||||||
|
{ .modelname = "asus-w1v", .config = ALC880_ASUS_W1V },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
|
||||||
|
{ .modelname = "asus-dig", .config = ALC880_ASUS_DIG },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
|
||||||
|
{ .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 },
|
||||||
{ .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
|
{ .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
|
||||||
|
|
||||||
{ .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
|
{ .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
|
||||||
|
@ -2243,6 +2272,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
|
||||||
|
|
||||||
{ .modelname = "lg-lw", .config = ALC880_LG_LW },
|
{ .modelname = "lg-lw", .config = ALC880_LG_LW },
|
||||||
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
|
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
|
||||||
|
{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW },
|
||||||
|
|
||||||
#ifdef CONFIG_SND_DEBUG
|
#ifdef CONFIG_SND_DEBUG
|
||||||
{ .modelname = "test", .config = ALC880_TEST },
|
{ .modelname = "test", .config = ALC880_TEST },
|
||||||
|
@ -2263,6 +2293,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dac_nids = alc880_dac_nids,
|
.dac_nids = alc880_dac_nids,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
|
||||||
.channel_mode = alc880_threestack_modes,
|
.channel_mode = alc880_threestack_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_3ST_DIG] = {
|
[ALC880_3ST_DIG] = {
|
||||||
|
@ -2273,6 +2304,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
|
||||||
.channel_mode = alc880_threestack_modes,
|
.channel_mode = alc880_threestack_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_TCL_S700] = {
|
[ALC880_TCL_S700] = {
|
||||||
|
@ -2365,6 +2397,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dac_nids = alc880_asus_dac_nids,
|
.dac_nids = alc880_asus_dac_nids,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
||||||
.channel_mode = alc880_asus_modes,
|
.channel_mode = alc880_asus_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_ASUS_DIG] = {
|
[ALC880_ASUS_DIG] = {
|
||||||
|
@ -2376,6 +2409,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
||||||
.channel_mode = alc880_asus_modes,
|
.channel_mode = alc880_asus_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_ASUS_DIG2] = {
|
[ALC880_ASUS_DIG2] = {
|
||||||
|
@ -2387,6 +2421,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
||||||
.channel_mode = alc880_asus_modes,
|
.channel_mode = alc880_asus_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_ASUS_W1V] = {
|
[ALC880_ASUS_W1V] = {
|
||||||
|
@ -2398,6 +2433,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
||||||
.channel_mode = alc880_asus_modes,
|
.channel_mode = alc880_asus_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_UNIWILL_DIG] = {
|
[ALC880_UNIWILL_DIG] = {
|
||||||
|
@ -2408,6 +2444,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
|
||||||
.channel_mode = alc880_asus_modes,
|
.channel_mode = alc880_asus_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_CLEVO] = {
|
[ALC880_CLEVO] = {
|
||||||
|
@ -2419,6 +2456,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.hp_nid = 0x03,
|
.hp_nid = 0x03,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
|
||||||
.channel_mode = alc880_threestack_modes,
|
.channel_mode = alc880_threestack_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_capture_source,
|
.input_mux = &alc880_capture_source,
|
||||||
},
|
},
|
||||||
[ALC880_LG] = {
|
[ALC880_LG] = {
|
||||||
|
@ -2430,6 +2468,7 @@ static struct alc_config_preset alc880_presets[] = {
|
||||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
|
.num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
|
||||||
.channel_mode = alc880_lg_ch_modes,
|
.channel_mode = alc880_lg_ch_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc880_lg_capture_source,
|
.input_mux = &alc880_lg_capture_source,
|
||||||
.unsol_event = alc880_lg_unsol_event,
|
.unsol_event = alc880_lg_unsol_event,
|
||||||
.init_hook = alc880_lg_automute,
|
.init_hook = alc880_lg_automute,
|
||||||
|
@ -2714,7 +2753,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec)
|
||||||
pin = spec->autocfg.speaker_pins[0];
|
pin = spec->autocfg.speaker_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
|
alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
|
||||||
}
|
}
|
||||||
|
@ -2755,7 +2794,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
|
||||||
(err = alc880_auto_create_extra_out(spec,
|
(err = alc880_auto_create_extra_out(spec,
|
||||||
spec->autocfg.speaker_pins[0],
|
spec->autocfg.speaker_pins[0],
|
||||||
"Speaker")) < 0 ||
|
"Speaker")) < 0 ||
|
||||||
(err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin,
|
(err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
|
||||||
"Headphone")) < 0 ||
|
"Headphone")) < 0 ||
|
||||||
(err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
(err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -3697,7 +3736,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
nid = cfg->hp_pin;
|
nid = cfg->hp_pins[0];
|
||||||
if (nid) {
|
if (nid) {
|
||||||
err = alc260_add_playback_controls(spec, nid, "Headphone");
|
err = alc260_add_playback_controls(spec, nid, "Headphone");
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -3767,7 +3806,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
|
||||||
if (nid)
|
if (nid)
|
||||||
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
||||||
|
|
||||||
nid = spec->autocfg.hp_pin;
|
nid = spec->autocfg.hp_pins[0];
|
||||||
if (nid)
|
if (nid)
|
||||||
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
|
||||||
}
|
}
|
||||||
|
@ -3900,7 +3939,8 @@ static struct hda_board_config alc260_cfg_tbl[] = {
|
||||||
{ .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
|
{ .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
|
||||||
.config = ALC260_BASIC }, /* CTL Travel Master U553W */
|
.config = ALC260_BASIC }, /* CTL Travel Master U553W */
|
||||||
{ .modelname = "hp", .config = ALC260_HP },
|
{ .modelname = "hp", .config = ALC260_HP },
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
|
{ .modelname = "hp-3013", .config = ALC260_HP_3013 },
|
||||||
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 },
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
|
||||||
|
@ -4266,6 +4306,13 @@ static struct hda_verb alc882_init_verbs[] = {
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct hda_verb alc882_eapd_verbs[] = {
|
||||||
|
/* change to EAPD mode */
|
||||||
|
{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
|
||||||
|
{0x20, AC_VERB_SET_PROC_COEF, 0x3060},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic initialization of ADC, input mixers and output mixers
|
* generic initialization of ADC, input mixers and output mixers
|
||||||
*/
|
*/
|
||||||
|
@ -4397,6 +4444,9 @@ static struct hda_board_config alc882_cfg_tbl[] = {
|
||||||
.config = ALC882_6ST_DIG }, /* Foxconn */
|
.config = ALC882_6ST_DIG }, /* Foxconn */
|
||||||
{ .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
|
{ .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
|
||||||
.config = ALC882_6ST_DIG }, /* ECS to Intel*/
|
.config = ALC882_6ST_DIG }, /* ECS to Intel*/
|
||||||
|
{ .modelname = "arima", .config = ALC882_ARIMA },
|
||||||
|
{ .pci_subvendor = 0x161f, .pci_subdevice = 0x2054,
|
||||||
|
.config = ALC882_ARIMA }, /* Arima W820Di1 */
|
||||||
{ .modelname = "auto", .config = ALC882_AUTO },
|
{ .modelname = "auto", .config = ALC882_AUTO },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
@ -4411,6 +4461,7 @@ static struct alc_config_preset alc882_presets[] = {
|
||||||
.dig_in_nid = ALC882_DIGIN_NID,
|
.dig_in_nid = ALC882_DIGIN_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
|
.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
|
||||||
.channel_mode = alc882_ch_modes,
|
.channel_mode = alc882_ch_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc882_capture_source,
|
.input_mux = &alc882_capture_source,
|
||||||
},
|
},
|
||||||
[ALC882_6ST_DIG] = {
|
[ALC882_6ST_DIG] = {
|
||||||
|
@ -4424,6 +4475,15 @@ static struct alc_config_preset alc882_presets[] = {
|
||||||
.channel_mode = alc882_sixstack_modes,
|
.channel_mode = alc882_sixstack_modes,
|
||||||
.input_mux = &alc882_capture_source,
|
.input_mux = &alc882_capture_source,
|
||||||
},
|
},
|
||||||
|
[ALC882_ARIMA] = {
|
||||||
|
.mixers = { alc882_base_mixer, alc882_chmode_mixer },
|
||||||
|
.init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
|
||||||
|
.num_dacs = ARRAY_SIZE(alc882_dac_nids),
|
||||||
|
.dac_nids = alc882_dac_nids,
|
||||||
|
.num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
|
||||||
|
.channel_mode = alc882_sixstack_modes,
|
||||||
|
.input_mux = &alc882_capture_source,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4466,7 +4526,7 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
hda_nid_t pin;
|
hda_nid_t pin;
|
||||||
|
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */
|
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */
|
||||||
}
|
}
|
||||||
|
@ -4999,16 +5059,23 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
|
||||||
*/
|
*/
|
||||||
static struct hda_board_config alc883_cfg_tbl[] = {
|
static struct hda_board_config alc883_cfg_tbl[] = {
|
||||||
{ .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
|
{ .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
|
||||||
|
{ .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG },
|
||||||
|
{ .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
|
||||||
|
.config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
|
||||||
|
{ .modelname = "3stack-6ch", .config = ALC883_3ST_6ch },
|
||||||
|
{ .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
|
||||||
|
.config = ALC883_3ST_6ch },
|
||||||
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd601,
|
||||||
|
.config = ALC883_3ST_6ch }, /* D102GGC */
|
||||||
{ .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
|
{ .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
|
||||||
{ .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
|
|
||||||
{ .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
|
{ .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
|
||||||
.config = ALC883_6ST_DIG }, /* MSI */
|
.config = ALC883_6ST_DIG }, /* MSI */
|
||||||
{ .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
|
{ .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
|
||||||
.config = ALC883_6ST_DIG }, /* Foxconn */
|
.config = ALC883_6ST_DIG }, /* Foxconn */
|
||||||
{ .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
|
{ .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
|
||||||
.config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
|
{ .modelname = "acer", .config = ALC883_ACER },
|
||||||
{ .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
|
{ .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/,
|
||||||
.config = ALC883_3ST_6ch },
|
.config = ALC883_ACER },
|
||||||
{ .modelname = "auto", .config = ALC883_AUTO },
|
{ .modelname = "auto", .config = ALC883_AUTO },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
@ -5038,6 +5105,7 @@ static struct alc_config_preset alc883_presets[] = {
|
||||||
.dig_in_nid = ALC883_DIGIN_NID,
|
.dig_in_nid = ALC883_DIGIN_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
|
.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
|
||||||
.channel_mode = alc883_3ST_6ch_modes,
|
.channel_mode = alc883_3ST_6ch_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc883_capture_source,
|
.input_mux = &alc883_capture_source,
|
||||||
},
|
},
|
||||||
[ALC883_3ST_6ch] = {
|
[ALC883_3ST_6ch] = {
|
||||||
|
@ -5049,6 +5117,7 @@ static struct alc_config_preset alc883_presets[] = {
|
||||||
.adc_nids = alc883_adc_nids,
|
.adc_nids = alc883_adc_nids,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
|
.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
|
||||||
.channel_mode = alc883_3ST_6ch_modes,
|
.channel_mode = alc883_3ST_6ch_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.input_mux = &alc883_capture_source,
|
.input_mux = &alc883_capture_source,
|
||||||
},
|
},
|
||||||
[ALC883_6ST_DIG] = {
|
[ALC883_6ST_DIG] = {
|
||||||
|
@ -5077,6 +5146,23 @@ static struct alc_config_preset alc883_presets[] = {
|
||||||
.channel_mode = alc883_sixstack_modes,
|
.channel_mode = alc883_sixstack_modes,
|
||||||
.input_mux = &alc883_capture_source,
|
.input_mux = &alc883_capture_source,
|
||||||
},
|
},
|
||||||
|
[ALC883_ACER] = {
|
||||||
|
.mixers = { alc883_base_mixer,
|
||||||
|
alc883_chmode_mixer },
|
||||||
|
/* On TravelMate laptops, GPIO 0 enables the internal speaker
|
||||||
|
* and the headphone jack. Turn this on and rely on the
|
||||||
|
* standard mute methods whenever the user wants to turn
|
||||||
|
* these outputs off.
|
||||||
|
*/
|
||||||
|
.init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
|
||||||
|
.num_dacs = ARRAY_SIZE(alc883_dac_nids),
|
||||||
|
.dac_nids = alc883_dac_nids,
|
||||||
|
.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
|
||||||
|
.adc_nids = alc883_adc_nids,
|
||||||
|
.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
|
||||||
|
.channel_mode = alc883_3ST_2ch_modes,
|
||||||
|
.input_mux = &alc883_capture_source,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -5121,7 +5207,7 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec)
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
hda_nid_t pin;
|
hda_nid_t pin;
|
||||||
|
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
/* use dac 0 */
|
/* use dac 0 */
|
||||||
alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
|
alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
|
||||||
|
@ -5217,8 +5303,10 @@ static int patch_alc883(struct hda_codec *codec)
|
||||||
spec->stream_digital_playback = &alc883_pcm_digital_playback;
|
spec->stream_digital_playback = &alc883_pcm_digital_playback;
|
||||||
spec->stream_digital_capture = &alc883_pcm_digital_capture;
|
spec->stream_digital_capture = &alc883_pcm_digital_capture;
|
||||||
|
|
||||||
|
if (! spec->adc_nids && spec->input_mux) {
|
||||||
spec->adc_nids = alc883_adc_nids;
|
spec->adc_nids = alc883_adc_nids;
|
||||||
spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
|
spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
|
||||||
|
}
|
||||||
|
|
||||||
codec->patch_ops = alc_patch_ops;
|
codec->patch_ops = alc_patch_ops;
|
||||||
if (board_config == ALC883_AUTO)
|
if (board_config == ALC883_AUTO)
|
||||||
|
@ -5481,6 +5569,7 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
|
||||||
.info = snd_hda_mixer_amp_volume_info,
|
.info = snd_hda_mixer_amp_volume_info,
|
||||||
.get = snd_hda_mixer_amp_volume_get,
|
.get = snd_hda_mixer_amp_volume_get,
|
||||||
.put = alc262_fujitsu_master_vol_put,
|
.put = alc262_fujitsu_master_vol_put,
|
||||||
|
.tlv = { .c = snd_hda_mixer_amp_tlv },
|
||||||
.private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
|
.private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -5499,6 +5588,13 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
|
||||||
{ } /* end */
|
{ } /* end */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* additional init verbs for Benq laptops */
|
||||||
|
static struct hda_verb alc262_EAPD_verbs[] = {
|
||||||
|
{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
|
||||||
|
{0x20, AC_VERB_SET_PROC_COEF, 0x3070},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
/* add playback controls from the parsed DAC table */
|
/* add playback controls from the parsed DAC table */
|
||||||
static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
|
static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
|
||||||
{
|
{
|
||||||
|
@ -5534,7 +5630,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nid = cfg->hp_pin;
|
nid = cfg->hp_pins[0];
|
||||||
if (nid) {
|
if (nid) {
|
||||||
/* spec->multiout.hp_nid = 2; */
|
/* spec->multiout.hp_nid = 2; */
|
||||||
if (nid == 0x16) {
|
if (nid == 0x16) {
|
||||||
|
@ -5769,6 +5865,7 @@ static struct hda_board_config alc262_cfg_tbl[] = {
|
||||||
{ .modelname = "fujitsu", .config = ALC262_FUJITSU },
|
{ .modelname = "fujitsu", .config = ALC262_FUJITSU },
|
||||||
{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
|
{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
|
||||||
.config = ALC262_FUJITSU },
|
.config = ALC262_FUJITSU },
|
||||||
|
{ .modelname = "hp-bpc", .config = ALC262_HP_BPC },
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x208c,
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x208c,
|
||||||
.config = ALC262_HP_BPC }, /* xw4400 */
|
.config = ALC262_HP_BPC }, /* xw4400 */
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
|
||||||
|
@ -5777,6 +5874,9 @@ static struct hda_board_config alc262_cfg_tbl[] = {
|
||||||
.config = ALC262_HP_BPC }, /* xw8400 */
|
.config = ALC262_HP_BPC }, /* xw8400 */
|
||||||
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
|
{ .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
|
||||||
.config = ALC262_HP_BPC }, /* xw9400 */
|
.config = ALC262_HP_BPC }, /* xw9400 */
|
||||||
|
{ .modelname = "benq", .config = ALC262_BENQ_ED8 },
|
||||||
|
{ .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560,
|
||||||
|
.config = ALC262_BENQ_ED8 },
|
||||||
{ .modelname = "auto", .config = ALC262_AUTO },
|
{ .modelname = "auto", .config = ALC262_AUTO },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
@ -5814,6 +5914,16 @@ static struct alc_config_preset alc262_presets[] = {
|
||||||
.channel_mode = alc262_modes,
|
.channel_mode = alc262_modes,
|
||||||
.input_mux = &alc262_HP_capture_source,
|
.input_mux = &alc262_HP_capture_source,
|
||||||
},
|
},
|
||||||
|
[ALC262_BENQ_ED8] = {
|
||||||
|
.mixers = { alc262_base_mixer },
|
||||||
|
.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
|
||||||
|
.num_dacs = ARRAY_SIZE(alc262_dac_nids),
|
||||||
|
.dac_nids = alc262_dac_nids,
|
||||||
|
.hp_nid = 0x03,
|
||||||
|
.num_channel_mode = ARRAY_SIZE(alc262_modes),
|
||||||
|
.channel_mode = alc262_modes,
|
||||||
|
.input_mux = &alc262_capture_source,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int patch_alc262(struct hda_codec *codec)
|
static int patch_alc262(struct hda_codec *codec)
|
||||||
|
@ -5942,6 +6052,23 @@ static struct hda_channel_mode alc861_threestack_modes[2] = {
|
||||||
{ 2, alc861_threestack_ch2_init },
|
{ 2, alc861_threestack_ch2_init },
|
||||||
{ 6, alc861_threestack_ch6_init },
|
{ 6, alc861_threestack_ch6_init },
|
||||||
};
|
};
|
||||||
|
/* Set mic1 as input and unmute the mixer */
|
||||||
|
static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
|
||||||
|
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||||
|
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
|
||||||
|
{ } /* end */
|
||||||
|
};
|
||||||
|
/* Set mic1 as output and mute mixer */
|
||||||
|
static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
|
||||||
|
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||||
|
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
|
||||||
|
{ } /* end */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
|
||||||
|
{ 2, alc861_uniwill_m31_ch2_init },
|
||||||
|
{ 4, alc861_uniwill_m31_ch4_init },
|
||||||
|
};
|
||||||
|
|
||||||
/* patch-ALC861 */
|
/* patch-ALC861 */
|
||||||
|
|
||||||
|
@ -6020,6 +6147,47 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
|
||||||
},
|
},
|
||||||
{ } /* end */
|
{ } /* end */
|
||||||
};
|
};
|
||||||
|
static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
|
||||||
|
/* output mixer control */
|
||||||
|
HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
|
||||||
|
HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
|
||||||
|
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
|
||||||
|
HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
|
||||||
|
/*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
|
||||||
|
|
||||||
|
/* Input mixer control */
|
||||||
|
/* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||||
|
HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
|
||||||
|
HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
|
||||||
|
HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
|
||||||
|
HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
|
||||||
|
HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
|
||||||
|
HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
|
||||||
|
HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
|
||||||
|
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
|
||||||
|
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
|
||||||
|
|
||||||
|
/* Capture mixer control */
|
||||||
|
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
|
||||||
|
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
|
||||||
|
{
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.name = "Capture Source",
|
||||||
|
.count = 1,
|
||||||
|
.info = alc_mux_enum_info,
|
||||||
|
.get = alc_mux_enum_get,
|
||||||
|
.put = alc_mux_enum_put,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.name = "Channel Mode",
|
||||||
|
.info = alc_ch_mode_info,
|
||||||
|
.get = alc_ch_mode_get,
|
||||||
|
.put = alc_ch_mode_put,
|
||||||
|
.private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
|
||||||
|
},
|
||||||
|
{ } /* end */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic initialization of ADC, input mixers and output mixers
|
* generic initialization of ADC, input mixers and output mixers
|
||||||
|
@ -6148,6 +6316,67 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
|
||||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
|
||||||
|
/*
|
||||||
|
* Unmute ADC0 and set the default input to mic-in
|
||||||
|
*/
|
||||||
|
/* port-A for surround (rear panel) */
|
||||||
|
{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
|
||||||
|
/* port-B for mic-in (rear panel) with vref */
|
||||||
|
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||||
|
/* port-C for line-in (rear panel) */
|
||||||
|
{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
|
||||||
|
/* port-D for Front */
|
||||||
|
{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||||
|
{ 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||||
|
/* port-E for HP out (front panel) */
|
||||||
|
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80
|
||||||
|
/* route front PCM to HP */
|
||||||
|
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
|
||||||
|
/* port-F for mic-in (front panel) with vref */
|
||||||
|
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||||
|
/* port-G for CLFE (rear panel) */
|
||||||
|
{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
|
||||||
|
/* port-H for side (rear panel) */
|
||||||
|
{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
|
||||||
|
/* CD-in */
|
||||||
|
{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
|
||||||
|
/* route front mic to ADC1*/
|
||||||
|
{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||||
|
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
/* Unmute DAC0~3 & spdif out*/
|
||||||
|
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||||
|
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||||
|
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||||
|
{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||||
|
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||||
|
|
||||||
|
/* Unmute Mixer 14 (mic) 1c (Line in)*/
|
||||||
|
{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
|
||||||
|
/* Unmute Stereo Mixer 15 */
|
||||||
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||||
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step
|
||||||
|
|
||||||
|
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||||
|
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||||
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front)
|
||||||
|
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic initialization of ADC, input mixers and output mixers
|
* generic initialization of ADC, input mixers and output mixers
|
||||||
*/
|
*/
|
||||||
|
@ -6401,7 +6630,7 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
hda_nid_t pin;
|
hda_nid_t pin;
|
||||||
|
|
||||||
pin = spec->autocfg.hp_pin;
|
pin = spec->autocfg.hp_pins[0];
|
||||||
if (pin) /* connect to front */
|
if (pin) /* connect to front */
|
||||||
alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]);
|
alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]);
|
||||||
}
|
}
|
||||||
|
@ -6436,7 +6665,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
|
||||||
|
|
||||||
if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
|
if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
|
||||||
(err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
(err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
|
||||||
(err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 ||
|
(err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0])) < 0 ||
|
||||||
(err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
(err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -6477,10 +6706,14 @@ static struct hda_board_config alc861_cfg_tbl[] = {
|
||||||
{ .modelname = "3stack", .config = ALC861_3ST },
|
{ .modelname = "3stack", .config = ALC861_3ST },
|
||||||
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
|
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
|
||||||
.config = ALC861_3ST },
|
.config = ALC861_3ST },
|
||||||
|
{ .modelname = "3stack-660", .config = ALC660_3ST },
|
||||||
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
|
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
|
||||||
.config = ALC660_3ST },
|
.config = ALC660_3ST },
|
||||||
{ .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
|
{ .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
|
||||||
{ .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
|
{ .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
|
||||||
|
{ .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31},
|
||||||
|
{ .pci_subvendor = 0x1584, .pci_subdevice = 0x9072,
|
||||||
|
.config = ALC861_UNIWILL_M31 },
|
||||||
{ .modelname = "auto", .config = ALC861_AUTO },
|
{ .modelname = "auto", .config = ALC861_AUTO },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
@ -6493,6 +6726,7 @@ static struct alc_config_preset alc861_presets[] = {
|
||||||
.dac_nids = alc861_dac_nids,
|
.dac_nids = alc861_dac_nids,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
||||||
.channel_mode = alc861_threestack_modes,
|
.channel_mode = alc861_threestack_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||||
.adc_nids = alc861_adc_nids,
|
.adc_nids = alc861_adc_nids,
|
||||||
.input_mux = &alc861_capture_source,
|
.input_mux = &alc861_capture_source,
|
||||||
|
@ -6505,6 +6739,7 @@ static struct alc_config_preset alc861_presets[] = {
|
||||||
.dig_out_nid = ALC861_DIGOUT_NID,
|
.dig_out_nid = ALC861_DIGOUT_NID,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
||||||
.channel_mode = alc861_threestack_modes,
|
.channel_mode = alc861_threestack_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||||
.adc_nids = alc861_adc_nids,
|
.adc_nids = alc861_adc_nids,
|
||||||
.input_mux = &alc861_capture_source,
|
.input_mux = &alc861_capture_source,
|
||||||
|
@ -6528,10 +6763,25 @@ static struct alc_config_preset alc861_presets[] = {
|
||||||
.dac_nids = alc660_dac_nids,
|
.dac_nids = alc660_dac_nids,
|
||||||
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
||||||
.channel_mode = alc861_threestack_modes,
|
.channel_mode = alc861_threestack_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||||
.adc_nids = alc861_adc_nids,
|
.adc_nids = alc861_adc_nids,
|
||||||
.input_mux = &alc861_capture_source,
|
.input_mux = &alc861_capture_source,
|
||||||
},
|
},
|
||||||
|
[ALC861_UNIWILL_M31] = {
|
||||||
|
.mixers = { alc861_uniwill_m31_mixer },
|
||||||
|
.init_verbs = { alc861_uniwill_m31_init_verbs },
|
||||||
|
.num_dacs = ARRAY_SIZE(alc861_dac_nids),
|
||||||
|
.dac_nids = alc861_dac_nids,
|
||||||
|
.dig_out_nid = ALC861_DIGOUT_NID,
|
||||||
|
.num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
|
||||||
|
.channel_mode = alc861_uniwill_m31_modes,
|
||||||
|
.need_dac_fix = 1,
|
||||||
|
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||||
|
.adc_nids = alc861_adc_nids,
|
||||||
|
.input_mux = &alc861_capture_source,
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,7 @@ struct hda_codec_preset snd_hda_preset_si3054[] = {
|
||||||
{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
|
{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
|
||||||
{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
|
{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
|
||||||
{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
|
{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
|
||||||
|
{ .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -60,6 +60,7 @@
|
||||||
#include "ice1712.h"
|
#include "ice1712.h"
|
||||||
#include "envy24ht.h"
|
#include "envy24ht.h"
|
||||||
#include "aureon.h"
|
#include "aureon.h"
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
/* WM8770 registers */
|
/* WM8770 registers */
|
||||||
#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
|
#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
|
||||||
|
@ -660,6 +661,12 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Logarithmic volume values for WM8770
|
* Logarithmic volume values for WM8770
|
||||||
* Computed as 20 * Log10(255 / x)
|
* Computed as 20 * Log10(255 / x)
|
||||||
|
@ -1409,10 +1416,13 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Master Playback Volume",
|
.name = "Master Playback Volume",
|
||||||
.info = wm_master_vol_info,
|
.info = wm_master_vol_info,
|
||||||
.get = wm_master_vol_get,
|
.get = wm_master_vol_get,
|
||||||
.put = wm_master_vol_put
|
.put = wm_master_vol_put,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1424,11 +1434,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Front Playback Volume",
|
.name = "Front Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (2 << 8) | 0
|
.private_value = (2 << 8) | 0,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1440,11 +1453,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Rear Playback Volume",
|
.name = "Rear Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (2 << 8) | 2
|
.private_value = (2 << 8) | 2,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1456,11 +1472,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Center Playback Volume",
|
.name = "Center Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (1 << 8) | 4
|
.private_value = (1 << 8) | 4,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1472,11 +1491,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "LFE Playback Volume",
|
.name = "LFE Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (1 << 8) | 5
|
.private_value = (1 << 8) | 5,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1488,11 +1510,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Side Playback Volume",
|
.name = "Side Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (2 << 8) | 6
|
.private_value = (2 << 8) | 6,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1506,10 +1531,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "PCM Playback Volume",
|
.name = "PCM Playback Volume",
|
||||||
.info = wm_pcm_vol_info,
|
.info = wm_pcm_vol_info,
|
||||||
.get = wm_pcm_vol_get,
|
.get = wm_pcm_vol_get,
|
||||||
.put = wm_pcm_vol_put
|
.put = wm_pcm_vol_put,
|
||||||
|
.tlv = { .p = db_scale_wm_pcm }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1520,10 +1548,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Capture Volume",
|
.name = "Capture Volume",
|
||||||
.info = wm_adc_vol_info,
|
.info = wm_adc_vol_info,
|
||||||
.get = wm_adc_vol_get,
|
.get = wm_adc_vol_get,
|
||||||
.put = wm_adc_vol_put
|
.put = wm_adc_vol_put,
|
||||||
|
.tlv = { .p = db_scale_wm_adc }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1567,11 +1598,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "AC97 Playback Volume",
|
.name = "AC97 Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_MASTER|AUREON_AC97_STEREO
|
.private_value = AC97_MASTER|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_master }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1583,11 +1617,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "CD Playback Volume",
|
.name = "CD Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_CD|AUREON_AC97_STEREO
|
.private_value = AC97_CD|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1599,11 +1636,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Aux Playback Volume",
|
.name = "Aux Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_AUX|AUREON_AC97_STEREO
|
.private_value = AC97_AUX|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1615,11 +1655,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Line Playback Volume",
|
.name = "Line Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_LINE|AUREON_AC97_STEREO
|
.private_value = AC97_LINE|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1631,11 +1674,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Mic Playback Volume",
|
.name = "Mic Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_MIC
|
.private_value = AC97_MIC,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1657,11 +1703,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "AC97 Playback Volume",
|
.name = "AC97 Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_MASTER|AUREON_AC97_STEREO
|
.private_value = AC97_MASTER|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_master }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1673,11 +1722,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "CD Playback Volume",
|
.name = "CD Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_AUX|AUREON_AC97_STEREO
|
.private_value = AC97_AUX|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1685,15 +1737,18 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
|
||||||
.info = aureon_ac97_mute_info,
|
.info = aureon_ac97_mute_info,
|
||||||
.get = aureon_ac97_mute_get,
|
.get = aureon_ac97_mute_get,
|
||||||
.put = aureon_ac97_mute_put,
|
.put = aureon_ac97_mute_put,
|
||||||
.private_value = AC97_CD,
|
.private_value = AC97_CD
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Phono Playback Volume",
|
.name = "Phono Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_CD|AUREON_AC97_STEREO
|
.private_value = AC97_CD|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1705,11 +1760,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Line Playback Volume",
|
.name = "Line Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_LINE|AUREON_AC97_STEREO
|
.private_value = AC97_LINE|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1721,11 +1779,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Mic Playback Volume",
|
.name = "Mic Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_MIC
|
.private_value = AC97_MIC,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -1744,11 +1805,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Aux Playback Volume",
|
.name = "Aux Playback Volume",
|
||||||
.info = aureon_ac97_vol_info,
|
.info = aureon_ac97_vol_info,
|
||||||
.get = aureon_ac97_vol_get,
|
.get = aureon_ac97_vol_get,
|
||||||
.put = aureon_ac97_vol_put,
|
.put = aureon_ac97_vol_put,
|
||||||
.private_value = AC97_VIDEO|AUREON_AC97_STEREO
|
.private_value = AC97_VIDEO|AUREON_AC97_STEREO,
|
||||||
|
.tlv = { .p = db_scale_ac97_gain }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include <sound/cs8427.h>
|
#include <sound/cs8427.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
|
|
||||||
|
@ -1377,6 +1378,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
|
static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
|
||||||
{
|
{
|
||||||
|
@ -1390,12 +1392,15 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Multi Playback Volume",
|
.name = "Multi Playback Volume",
|
||||||
.info = snd_ice1712_pro_mixer_volume_info,
|
.info = snd_ice1712_pro_mixer_volume_info,
|
||||||
.get = snd_ice1712_pro_mixer_volume_get,
|
.get = snd_ice1712_pro_mixer_volume_get,
|
||||||
.put = snd_ice1712_pro_mixer_volume_put,
|
.put = snd_ice1712_pro_mixer_volume_put,
|
||||||
.private_value = 0,
|
.private_value = 0,
|
||||||
.count = 10,
|
.count = 10,
|
||||||
|
.tlv = { .p = db_scale_playback }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1420,11 +1425,14 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
|
static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "H/W Multi Capture Volume",
|
.name = "H/W Multi Capture Volume",
|
||||||
.info = snd_ice1712_pro_mixer_volume_info,
|
.info = snd_ice1712_pro_mixer_volume_info,
|
||||||
.get = snd_ice1712_pro_mixer_volume_get,
|
.get = snd_ice1712_pro_mixer_volume_get,
|
||||||
.put = snd_ice1712_pro_mixer_volume_put,
|
.put = snd_ice1712_pro_mixer_volume_put,
|
||||||
.private_value = 10,
|
.private_value = 10,
|
||||||
|
.tlv = { .p = db_scale_playback }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
|
static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
|
||||||
|
@ -1857,7 +1865,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
|
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
|
||||||
static unsigned int xrate[13] = {
|
static unsigned int xrate[13] = {
|
||||||
8000, 9600, 11025, 12000, 1600, 22050, 24000,
|
8000, 9600, 11025, 12000, 16000, 22050, 24000,
|
||||||
32000, 44100, 48000, 64000, 88200, 96000
|
32000, 44100, 48000, 64000, 88200, 96000
|
||||||
};
|
};
|
||||||
unsigned char oval;
|
unsigned char oval;
|
||||||
|
@ -1924,7 +1932,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont
|
||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
static unsigned int xrate[13] = {
|
static unsigned int xrate[13] = {
|
||||||
8000, 9600, 11025, 12000, 1600, 22050, 24000,
|
8000, 9600, 11025, 12000, 16000, 22050, 24000,
|
||||||
32000, 44100, 48000, 64000, 88200, 96000
|
32000, 44100, 48000, 64000, 88200, 96000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1941,7 +1949,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
static unsigned int xrate[13] = {
|
static unsigned int xrate[13] = {
|
||||||
8000, 9600, 11025, 12000, 1600, 22050, 24000,
|
8000, 9600, 11025, 12000, 16000, 22050, 24000,
|
||||||
32000, 44100, 48000, 64000, 88200, 96000
|
32000, 44100, 48000, 64000, 88200, 96000
|
||||||
};
|
};
|
||||||
unsigned char oval;
|
unsigned char oval;
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "ice1712.h"
|
#include "ice1712.h"
|
||||||
#include "envy24ht.h"
|
#include "envy24ht.h"
|
||||||
#include "phase.h"
|
#include "phase.h"
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
/* WM8770 registers */
|
/* WM8770 registers */
|
||||||
#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
|
#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
|
||||||
|
@ -696,6 +697,9 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
|
||||||
|
|
||||||
static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -706,10 +710,13 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Master Playback Volume",
|
.name = "Master Playback Volume",
|
||||||
.info = wm_master_vol_info,
|
.info = wm_master_vol_info,
|
||||||
.get = wm_master_vol_get,
|
.get = wm_master_vol_get,
|
||||||
.put = wm_master_vol_put
|
.put = wm_master_vol_put,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -721,11 +728,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Front Playback Volume",
|
.name = "Front Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (2 << 8) | 0
|
.private_value = (2 << 8) | 0,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -737,11 +747,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Rear Playback Volume",
|
.name = "Rear Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (2 << 8) | 2
|
.private_value = (2 << 8) | 2,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -753,11 +766,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Center Playback Volume",
|
.name = "Center Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (1 << 8) | 4
|
.private_value = (1 << 8) | 4,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -769,11 +785,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "LFE Playback Volume",
|
.name = "LFE Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (1 << 8) | 5
|
.private_value = (1 << 8) | 5,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -785,11 +804,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Side Playback Volume",
|
.name = "Side Playback Volume",
|
||||||
.info = wm_vol_info,
|
.info = wm_vol_info,
|
||||||
.get = wm_vol_get,
|
.get = wm_vol_get,
|
||||||
.put = wm_vol_put,
|
.put = wm_vol_put,
|
||||||
.private_value = (2 << 8) | 6
|
.private_value = (2 << 8) | 6,
|
||||||
|
.tlv = { .p = db_scale_wm_dac }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -803,10 +825,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "PCM Playback Volume",
|
.name = "PCM Playback Volume",
|
||||||
.info = wm_pcm_vol_info,
|
.info = wm_pcm_vol_info,
|
||||||
.get = wm_pcm_vol_get,
|
.get = wm_pcm_vol_get,
|
||||||
.put = wm_pcm_vol_put
|
.put = wm_pcm_vol_put,
|
||||||
|
.tlv = { .p = db_scale_wm_pcm }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include "ice1712.h"
|
#include "ice1712.h"
|
||||||
#include "envy24ht.h"
|
#include "envy24ht.h"
|
||||||
|
@ -564,6 +565,8 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mixers
|
* mixers
|
||||||
*/
|
*/
|
||||||
|
@ -571,17 +574,23 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
|
||||||
static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
|
static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "PCM Playback Volume",
|
.name = "PCM Playback Volume",
|
||||||
.info = wm_dac_vol_info,
|
.info = wm_dac_vol_info,
|
||||||
.get = wm_dac_vol_get,
|
.get = wm_dac_vol_get,
|
||||||
.put = wm_dac_vol_put,
|
.put = wm_dac_vol_put,
|
||||||
|
.tlv = { .p = db_scale_volume },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Capture Volume",
|
.name = "Capture Volume",
|
||||||
.info = wm_adc_vol_info,
|
.info = wm_adc_vol_info,
|
||||||
.get = wm_adc_vol_get,
|
.get = wm_adc_vol_get,
|
||||||
.put = wm_adc_vol_put,
|
.put = wm_adc_vol_put,
|
||||||
|
.tlv = { .p = db_scale_volume },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "envy24ht.h"
|
#include "envy24ht.h"
|
||||||
#include "prodigy192.h"
|
#include "prodigy192.h"
|
||||||
#include "stac946x.h"
|
#include "stac946x.h"
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val)
|
static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val)
|
||||||
{
|
{
|
||||||
|
@ -356,6 +357,9 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mixers
|
* mixers
|
||||||
*/
|
*/
|
||||||
|
@ -368,14 +372,18 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = {
|
||||||
.get = stac9460_dac_mute_get,
|
.get = stac9460_dac_mute_get,
|
||||||
.put = stac9460_dac_mute_put,
|
.put = stac9460_dac_mute_put,
|
||||||
.private_value = 1,
|
.private_value = 1,
|
||||||
|
.tlv = { .p = db_scale_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Master Playback Volume",
|
.name = "Master Playback Volume",
|
||||||
.info = stac9460_dac_vol_info,
|
.info = stac9460_dac_vol_info,
|
||||||
.get = stac9460_dac_vol_get,
|
.get = stac9460_dac_vol_get,
|
||||||
.put = stac9460_dac_vol_put,
|
.put = stac9460_dac_vol_put,
|
||||||
.private_value = 1,
|
.private_value = 1,
|
||||||
|
.tlv = { .p = db_scale_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -387,11 +395,14 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "DAC Volume",
|
.name = "DAC Volume",
|
||||||
.count = 6,
|
.count = 6,
|
||||||
.info = stac9460_dac_vol_info,
|
.info = stac9460_dac_vol_info,
|
||||||
.get = stac9460_dac_vol_get,
|
.get = stac9460_dac_vol_get,
|
||||||
.put = stac9460_dac_vol_put,
|
.put = stac9460_dac_vol_put,
|
||||||
|
.tlv = { .p = db_scale_dac }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -404,11 +415,14 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "ADC Volume",
|
.name = "ADC Volume",
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.info = stac9460_adc_vol_info,
|
.info = stac9460_adc_vol_info,
|
||||||
.get = stac9460_adc_vol_get,
|
.get = stac9460_adc_vol_get,
|
||||||
.put = stac9460_adc_vol_put,
|
.put = stac9460_adc_vol_put,
|
||||||
|
.tlv = { .p = db_scale_adc }
|
||||||
},
|
},
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
|
|
|
@ -87,16 +87,33 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
|
||||||
* initialize the chips on M-Audio Revolution cards
|
* initialize the chips on M-Audio Revolution cards
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned int revo71_num_stereo_front[] = {2};
|
#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
|
||||||
static char *revo71_channel_names_front[] = {"PCM Playback Volume"};
|
|
||||||
|
|
||||||
static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2};
|
static struct snd_akm4xxx_dac_channel revo71_front[] = {
|
||||||
static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume",
|
AK_DAC("PCM Playback Volume", 2)
|
||||||
"PCM Side Playback Volume", "PCM Rear Playback Volume"};
|
};
|
||||||
|
|
||||||
static unsigned int revo51_num_stereo[] = {2, 1, 1, 2};
|
static struct snd_akm4xxx_dac_channel revo71_surround[] = {
|
||||||
static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume",
|
AK_DAC("PCM Center Playback Volume", 1),
|
||||||
"PCM LFE Playback Volume", "PCM Rear Playback Volume"};
|
AK_DAC("PCM LFE Playback Volume", 1),
|
||||||
|
AK_DAC("PCM Side Playback Volume", 2),
|
||||||
|
AK_DAC("PCM Rear Playback Volume", 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_akm4xxx_dac_channel revo51_dac[] = {
|
||||||
|
AK_DAC("PCM Playback Volume", 2),
|
||||||
|
AK_DAC("PCM Center Playback Volume", 1),
|
||||||
|
AK_DAC("PCM LFE Playback Volume", 1),
|
||||||
|
AK_DAC("PCM Rear Playback Volume", 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_akm4xxx_adc_channel revo51_adc[] = {
|
||||||
|
{
|
||||||
|
.name = "PCM Capture Volume",
|
||||||
|
.switch_name = "PCM Capture Switch",
|
||||||
|
.num_channels = 2
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static struct snd_akm4xxx akm_revo_front __devinitdata = {
|
static struct snd_akm4xxx akm_revo_front __devinitdata = {
|
||||||
.type = SND_AK4381,
|
.type = SND_AK4381,
|
||||||
|
@ -104,8 +121,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = {
|
||||||
.ops = {
|
.ops = {
|
||||||
.set_rate_val = revo_set_rate_val
|
.set_rate_val = revo_set_rate_val
|
||||||
},
|
},
|
||||||
.num_stereo = revo71_num_stereo_front,
|
.dac_info = revo71_front,
|
||||||
.channel_names = revo71_channel_names_front
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
|
static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
|
||||||
|
@ -127,8 +143,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = {
|
||||||
.ops = {
|
.ops = {
|
||||||
.set_rate_val = revo_set_rate_val
|
.set_rate_val = revo_set_rate_val
|
||||||
},
|
},
|
||||||
.num_stereo = revo71_num_stereo_surround,
|
.dac_info = revo71_surround,
|
||||||
.channel_names = revo71_channel_names_surround
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
|
static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
|
||||||
|
@ -149,8 +164,7 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = {
|
||||||
.ops = {
|
.ops = {
|
||||||
.set_rate_val = revo_set_rate_val
|
.set_rate_val = revo_set_rate_val
|
||||||
},
|
},
|
||||||
.num_stereo = revo51_num_stereo,
|
.dac_info = revo51_dac,
|
||||||
.channel_names = revo51_channel_names
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
|
static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
|
||||||
|
@ -159,7 +173,25 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
|
||||||
.data_mask = VT1724_REVO_CDOUT,
|
.data_mask = VT1724_REVO_CDOUT,
|
||||||
.clk_mask = VT1724_REVO_CCLK,
|
.clk_mask = VT1724_REVO_CCLK,
|
||||||
.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
||||||
.cs_addr = 0,
|
.cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
||||||
|
.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
||||||
|
.add_flags = VT1724_REVO_CCLK, /* high at init */
|
||||||
|
.mask_flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_akm4xxx akm_revo51_adc __devinitdata = {
|
||||||
|
.type = SND_AK5365,
|
||||||
|
.num_adcs = 2,
|
||||||
|
.adc_info = revo51_adc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
|
||||||
|
.caddr = 2,
|
||||||
|
.cif = 0,
|
||||||
|
.data_mask = VT1724_REVO_CDOUT,
|
||||||
|
.clk_mask = VT1724_REVO_CCLK,
|
||||||
|
.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
||||||
|
.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
|
||||||
.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
|
||||||
.add_flags = VT1724_REVO_CCLK, /* high at init */
|
.add_flags = VT1724_REVO_CCLK, /* high at init */
|
||||||
.mask_flags = 0,
|
.mask_flags = 0,
|
||||||
|
@ -202,9 +234,13 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
|
||||||
snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
|
snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
|
||||||
break;
|
break;
|
||||||
case VT1724_SUBDEVICE_REVOLUTION51:
|
case VT1724_SUBDEVICE_REVOLUTION51:
|
||||||
ice->akm_codecs = 1;
|
ice->akm_codecs = 2;
|
||||||
if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
|
if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc,
|
||||||
|
&akm_revo51_adc_priv, ice);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
/* unmute all codecs - needed! */
|
/* unmute all codecs - needed! */
|
||||||
snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
|
snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -42,7 +42,7 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
|
||||||
#define VT1724_REVO_CCLK 0x02
|
#define VT1724_REVO_CCLK 0x02
|
||||||
#define VT1724_REVO_CDIN 0x04 /* not used */
|
#define VT1724_REVO_CDIN 0x04 /* not used */
|
||||||
#define VT1724_REVO_CDOUT 0x08
|
#define VT1724_REVO_CDOUT 0x08
|
||||||
#define VT1724_REVO_CS0 0x10 /* not used */
|
#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */
|
||||||
#define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */
|
#define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */
|
||||||
#define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */
|
#define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */
|
||||||
#define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */
|
#define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */
|
||||||
|
|
|
@ -2251,6 +2251,16 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
|
||||||
/* ACLink on, 2 channels */
|
/* ACLink on, 2 channels */
|
||||||
cnt = igetdword(chip, ICHREG(GLOB_CNT));
|
cnt = igetdword(chip, ICHREG(GLOB_CNT));
|
||||||
cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
|
cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
|
||||||
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
||||||
|
/* do cold reset - the full ac97 powerdown may leave the controller
|
||||||
|
* in a warm state but actually it cannot communicate with the codec.
|
||||||
|
*/
|
||||||
|
iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD);
|
||||||
|
cnt = igetdword(chip, ICHREG(GLOB_CNT));
|
||||||
|
udelay(10);
|
||||||
|
iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
|
||||||
|
msleep(1);
|
||||||
|
#else
|
||||||
/* finish cold or do warm reset */
|
/* finish cold or do warm reset */
|
||||||
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
|
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
|
||||||
iputdword(chip, ICHREG(GLOB_CNT), cnt);
|
iputdword(chip, ICHREG(GLOB_CNT), cnt);
|
||||||
|
@ -2265,6 +2275,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
__ok:
|
__ok:
|
||||||
|
#endif
|
||||||
if (probing) {
|
if (probing) {
|
||||||
/* wait for any codec ready status.
|
/* wait for any codec ready status.
|
||||||
* Once it becomes ready it should remain ready
|
* Once it becomes ready it should remain ready
|
||||||
|
@ -2485,7 +2496,7 @@ static int intel8x0_resume(struct pci_dev *pci)
|
||||||
card->shortname, chip);
|
card->shortname, chip);
|
||||||
chip->irq = pci->irq;
|
chip->irq = pci->irq;
|
||||||
synchronize_irq(chip->irq);
|
synchronize_irq(chip->irq);
|
||||||
snd_intel8x0_chip_init(chip, 1);
|
snd_intel8x0_chip_init(chip, 0);
|
||||||
|
|
||||||
/* re-initialize mixer stuff */
|
/* re-initialize mixer stuff */
|
||||||
if (chip->device_type == DEVICE_INTEL_ICH4) {
|
if (chip->device_type == DEVICE_INTEL_ICH4) {
|
||||||
|
@ -2615,6 +2626,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
|
||||||
/* not 48000Hz, tuning the clock.. */
|
/* not 48000Hz, tuning the clock.. */
|
||||||
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
|
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
|
||||||
printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
|
printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
|
||||||
|
snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
|
|
@ -1045,6 +1045,8 @@ static int intel8x0m_suspend(struct pci_dev *pci, pm_message_t state)
|
||||||
for (i = 0; i < chip->pcm_devs; i++)
|
for (i = 0; i < chip->pcm_devs; i++)
|
||||||
snd_pcm_suspend_all(chip->pcm[i]);
|
snd_pcm_suspend_all(chip->pcm[i]);
|
||||||
snd_ac97_suspend(chip->ac97);
|
snd_ac97_suspend(chip->ac97);
|
||||||
|
if (chip->irq >= 0)
|
||||||
|
free_irq(chip->irq, chip);
|
||||||
pci_disable_device(pci);
|
pci_disable_device(pci);
|
||||||
pci_save_state(pci);
|
pci_save_state(pci);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1058,6 +1060,9 @@ static int intel8x0m_resume(struct pci_dev *pci)
|
||||||
pci_restore_state(pci);
|
pci_restore_state(pci);
|
||||||
pci_enable_device(pci);
|
pci_enable_device(pci);
|
||||||
pci_set_master(pci);
|
pci_set_master(pci);
|
||||||
|
request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
||||||
|
card->shortname, chip);
|
||||||
|
chip->irq = pci->irq;
|
||||||
snd_intel8x0_chip_init(chip, 0);
|
snd_intel8x0_chip_init(chip, 0);
|
||||||
snd_ac97_resume(chip->ac97);
|
snd_ac97_resume(chip->ac97);
|
||||||
|
|
||||||
|
|
|
@ -1109,13 +1109,13 @@ static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry,
|
||||||
offset = offset & ~3; /* 4 bytes aligned */
|
offset = offset & ~3; /* 4 bytes aligned */
|
||||||
|
|
||||||
switch(orig) {
|
switch(orig) {
|
||||||
case 0: /* SEEK_SET */
|
case SEEK_SET:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
break;
|
break;
|
||||||
case 1: /* SEEK_CUR */
|
case SEEK_CUR:
|
||||||
file->f_pos += offset;
|
file->f_pos += offset;
|
||||||
break;
|
break;
|
||||||
case 2: /* SEEK_END, offset is negative */
|
case SEEK_END: /* offset is negative */
|
||||||
file->f_pos = MIXART_BA0_SIZE + offset;
|
file->f_pos = MIXART_BA0_SIZE + offset;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1135,13 +1135,13 @@ static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry,
|
||||||
offset = offset & ~3; /* 4 bytes aligned */
|
offset = offset & ~3; /* 4 bytes aligned */
|
||||||
|
|
||||||
switch(orig) {
|
switch(orig) {
|
||||||
case 0: /* SEEK_SET */
|
case SEEK_SET:
|
||||||
file->f_pos = offset;
|
file->f_pos = offset;
|
||||||
break;
|
break;
|
||||||
case 1: /* SEEK_CUR */
|
case SEEK_CUR:
|
||||||
file->f_pos += offset;
|
file->f_pos += offset;
|
||||||
break;
|
break;
|
||||||
case 2: /* SEEK_END, offset is negative */
|
case SEEK_END: /* offset is negative */
|
||||||
file->f_pos = MIXART_BA1_SIZE + offset;
|
file->f_pos = MIXART_BA1_SIZE + offset;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "mixart_core.h"
|
#include "mixart_core.h"
|
||||||
#include "mixart_hwdep.h"
|
#include "mixart_hwdep.h"
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include "mixart_mixer.h"
|
#include "mixart_mixer.h"
|
||||||
|
|
||||||
static u32 mixart_analog_level[256] = {
|
static u32 mixart_analog_level[256] = {
|
||||||
|
@ -388,12 +389,17 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new mixart_control_analog_level = {
|
static struct snd_kcontrol_new mixart_control_analog_level = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
/* name will be filled later */
|
/* name will be filled later */
|
||||||
.info = mixart_analog_vol_info,
|
.info = mixart_analog_vol_info,
|
||||||
.get = mixart_analog_vol_get,
|
.get = mixart_analog_vol_get,
|
||||||
.put = mixart_analog_vol_put,
|
.put = mixart_analog_vol_put,
|
||||||
|
.tlv = { .p = db_scale_analog },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* shared */
|
/* shared */
|
||||||
|
@ -866,14 +872,19 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_mixart_pcm_vol =
|
static struct snd_kcontrol_new snd_mixart_pcm_vol =
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
/* name will be filled later */
|
/* name will be filled later */
|
||||||
/* count will be filled later */
|
/* count will be filled later */
|
||||||
.info = mixart_digital_vol_info, /* shared */
|
.info = mixart_digital_vol_info, /* shared */
|
||||||
.get = mixart_pcm_vol_get,
|
.get = mixart_pcm_vol_get,
|
||||||
.put = mixart_pcm_vol_put,
|
.put = mixart_pcm_vol_put,
|
||||||
|
.tlv = { .p = db_scale_digital },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -984,10 +995,13 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||||
|
|
||||||
static struct snd_kcontrol_new mixart_control_monitor_vol = {
|
static struct snd_kcontrol_new mixart_control_monitor_vol = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Monitoring Volume",
|
.name = "Monitoring Volume",
|
||||||
.info = mixart_digital_vol_info, /* shared */
|
.info = mixart_digital_vol_info, /* shared */
|
||||||
.get = mixart_monitor_vol_get,
|
.get = mixart_monitor_vol_get,
|
||||||
.put = mixart_monitor_vol_put,
|
.put = mixart_monitor_vol_put,
|
||||||
|
.tlv = { .p = db_scale_digital },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "pcxhr_hwdep.h"
|
#include "pcxhr_hwdep.h"
|
||||||
#include "pcxhr_core.h"
|
#include "pcxhr_core.h"
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
#include "pcxhr_mixer.h"
|
#include "pcxhr_mixer.h"
|
||||||
|
|
||||||
|
@ -43,6 +44,9 @@
|
||||||
#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */
|
#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */
|
||||||
#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
|
#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
|
||||||
|
|
||||||
static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
|
static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
|
||||||
{
|
{
|
||||||
int err, vol;
|
int err, vol;
|
||||||
|
@ -130,10 +134,13 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol,
|
||||||
|
|
||||||
static struct snd_kcontrol_new pcxhr_control_analog_level = {
|
static struct snd_kcontrol_new pcxhr_control_analog_level = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
/* name will be filled later */
|
/* name will be filled later */
|
||||||
.info = pcxhr_analog_vol_info,
|
.info = pcxhr_analog_vol_info,
|
||||||
.get = pcxhr_analog_vol_get,
|
.get = pcxhr_analog_vol_get,
|
||||||
.put = pcxhr_analog_vol_put,
|
.put = pcxhr_analog_vol_put,
|
||||||
|
/* tlv will be filled later */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* shared */
|
/* shared */
|
||||||
|
@ -188,6 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = {
|
||||||
#define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */
|
#define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */
|
||||||
#define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */
|
#define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
|
||||||
|
|
||||||
#define MORE_THAN_ONE_STREAM_LEVEL 0x000001
|
#define MORE_THAN_ONE_STREAM_LEVEL 0x000001
|
||||||
#define VALID_STREAM_PAN_LEVEL_MASK 0x800000
|
#define VALID_STREAM_PAN_LEVEL_MASK 0x800000
|
||||||
|
@ -343,11 +351,14 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol,
|
||||||
static struct snd_kcontrol_new snd_pcxhr_pcm_vol =
|
static struct snd_kcontrol_new snd_pcxhr_pcm_vol =
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
/* name will be filled later */
|
/* name will be filled later */
|
||||||
/* count will be filled later */
|
/* count will be filled later */
|
||||||
.info = pcxhr_digital_vol_info, /* shared */
|
.info = pcxhr_digital_vol_info, /* shared */
|
||||||
.get = pcxhr_pcm_vol_get,
|
.get = pcxhr_pcm_vol_get,
|
||||||
.put = pcxhr_pcm_vol_put,
|
.put = pcxhr_pcm_vol_put,
|
||||||
|
.tlv = { .p = db_scale_digital },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -433,10 +444,13 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol,
|
||||||
|
|
||||||
static struct snd_kcontrol_new pcxhr_control_monitor_vol = {
|
static struct snd_kcontrol_new pcxhr_control_monitor_vol = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Monitoring Volume",
|
.name = "Monitoring Volume",
|
||||||
.info = pcxhr_digital_vol_info, /* shared */
|
.info = pcxhr_digital_vol_info, /* shared */
|
||||||
.get = pcxhr_monitor_vol_get,
|
.get = pcxhr_monitor_vol_get,
|
||||||
.put = pcxhr_monitor_vol_put,
|
.put = pcxhr_monitor_vol_put,
|
||||||
|
.tlv = { .p = db_scale_digital },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -928,6 +942,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr)
|
||||||
temp = pcxhr_control_analog_level;
|
temp = pcxhr_control_analog_level;
|
||||||
temp.name = "Master Playback Volume";
|
temp.name = "Master Playback Volume";
|
||||||
temp.private_value = 0; /* playback */
|
temp.private_value = 0; /* playback */
|
||||||
|
temp.tlv.p = db_scale_analog_playback;
|
||||||
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
|
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
|
||||||
return err;
|
return err;
|
||||||
/* output mute controls */
|
/* output mute controls */
|
||||||
|
@ -963,6 +978,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr)
|
||||||
temp = pcxhr_control_analog_level;
|
temp = pcxhr_control_analog_level;
|
||||||
temp.name = "Master Capture Volume";
|
temp.name = "Master Capture Volume";
|
||||||
temp.private_value = 1; /* capture */
|
temp.private_value = 1; /* capture */
|
||||||
|
temp.tlv.p = db_scale_analog_capture;
|
||||||
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
|
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
|
@ -673,8 +673,12 @@ static struct lbuspath lbus_rec_path = {
|
||||||
#define FIRMWARE_VERSIONS 1
|
#define FIRMWARE_VERSIONS 1
|
||||||
static union firmware_version firmware_versions[] = {
|
static union firmware_version firmware_versions[] = {
|
||||||
{
|
{
|
||||||
.firmware.ASIC = 3,.firmware.CODEC = 2,
|
.firmware = {
|
||||||
.firmware.AUXDSP = 3,.firmware.PROG = 773,
|
.ASIC = 3,
|
||||||
|
.CODEC = 2,
|
||||||
|
.AUXDSP = 3,
|
||||||
|
.PROG = 773,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -726,23 +726,37 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hdsp_check_for_firmware (struct hdsp *hdsp, int show_err)
|
#ifdef HDSP_FW_LOADER
|
||||||
|
static int __devinit hdsp_request_fw_loader(struct hdsp *hdsp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
|
||||||
{
|
{
|
||||||
if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
|
if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
|
||||||
|
return 0;
|
||||||
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
|
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
|
||||||
snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
|
|
||||||
hdsp->state &= ~HDSP_FirmwareLoaded;
|
hdsp->state &= ~HDSP_FirmwareLoaded;
|
||||||
if (! show_err)
|
if (! load_on_demand)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
|
||||||
/* try to load firmware */
|
/* try to load firmware */
|
||||||
if (hdsp->state & HDSP_FirmwareCached) {
|
if (! (hdsp->state & HDSP_FirmwareCached)) {
|
||||||
if (snd_hdsp_load_firmware_from_cache(hdsp) != 0)
|
#ifdef HDSP_FW_LOADER
|
||||||
snd_printk(KERN_ERR "Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n");
|
if (! hdsp_request_fw_loader(hdsp))
|
||||||
} else {
|
return 0;
|
||||||
snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n");
|
#endif
|
||||||
}
|
snd_printk(KERN_ERR
|
||||||
|
"Hammerfall-DSP: No firmware loaded nor "
|
||||||
|
"cached, please upload firmware.\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
|
||||||
|
snd_printk(KERN_ERR
|
||||||
|
"Hammerfall-DSP: Firmware loading from "
|
||||||
|
"cache failed, please upload manually.\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3181,10 +3195,18 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snd_iprintf(buffer, "No firmware loaded nor cached, please upload firmware.\n");
|
int err = -EINVAL;
|
||||||
|
#ifdef HDSP_FW_LOADER
|
||||||
|
err = hdsp_request_fw_loader(hdsp);
|
||||||
|
#endif
|
||||||
|
if (err < 0) {
|
||||||
|
snd_iprintf(buffer,
|
||||||
|
"No firmware loaded nor cached, "
|
||||||
|
"please upload firmware.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
status = hdsp_read(hdsp, HDSP_statusRegister);
|
status = hdsp_read(hdsp, HDSP_statusRegister);
|
||||||
status2 = hdsp_read(hdsp, HDSP_status2Register);
|
status2 = hdsp_read(hdsp, HDSP_status2Register);
|
||||||
|
@ -3851,7 +3873,7 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
if (hdsp_check_for_iobox (hdsp))
|
if (hdsp_check_for_iobox (hdsp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (hdsp_check_for_firmware(hdsp, 1))
|
if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
spin_lock(&hdsp->lock);
|
spin_lock(&hdsp->lock);
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/trident.h>
|
#include <sound/trident.h>
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
|
|
||||||
|
@ -2627,6 +2628,8 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
|
||||||
|
|
||||||
static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
|
static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
|
@ -2653,6 +2656,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata =
|
||||||
.get = snd_trident_vol_control_get,
|
.get = snd_trident_vol_control_get,
|
||||||
.put = snd_trident_vol_control_put,
|
.put = snd_trident_vol_control_put,
|
||||||
.private_value = 16,
|
.private_value = 16,
|
||||||
|
.tlv = { .p = db_scale_gvol },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata =
|
static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata =
|
||||||
|
@ -2663,6 +2667,7 @@ static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata =
|
||||||
.get = snd_trident_vol_control_get,
|
.get = snd_trident_vol_control_get,
|
||||||
.put = snd_trident_vol_control_put,
|
.put = snd_trident_vol_control_put,
|
||||||
.private_value = 0,
|
.private_value = 0,
|
||||||
|
.tlv = { .p = db_scale_gvol },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
/*---------------------------------------------------------------------------
|
||||||
|
@ -2730,6 +2735,7 @@ static struct snd_kcontrol_new snd_trident_pcm_vol_control __devinitdata =
|
||||||
.info = snd_trident_pcm_vol_control_info,
|
.info = snd_trident_pcm_vol_control_info,
|
||||||
.get = snd_trident_pcm_vol_control_get,
|
.get = snd_trident_pcm_vol_control_get,
|
||||||
.put = snd_trident_pcm_vol_control_put,
|
.put = snd_trident_pcm_vol_control_put,
|
||||||
|
/* FIXME: no tlv yet */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
/*---------------------------------------------------------------------------
|
||||||
|
@ -2839,6 +2845,8 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
|
static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
|
||||||
{
|
{
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
@ -2848,6 +2856,7 @@ static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
|
||||||
.info = snd_trident_pcm_rvol_control_info,
|
.info = snd_trident_pcm_rvol_control_info,
|
||||||
.get = snd_trident_pcm_rvol_control_get,
|
.get = snd_trident_pcm_rvol_control_get,
|
||||||
.put = snd_trident_pcm_rvol_control_put,
|
.put = snd_trident_pcm_rvol_control_put,
|
||||||
|
.tlv = { .p = db_scale_crvol },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
/*---------------------------------------------------------------------------
|
||||||
|
@ -2903,6 +2912,7 @@ static struct snd_kcontrol_new snd_trident_pcm_cvol_control __devinitdata =
|
||||||
.info = snd_trident_pcm_cvol_control_info,
|
.info = snd_trident_pcm_cvol_control_info,
|
||||||
.get = snd_trident_pcm_cvol_control_get,
|
.get = snd_trident_pcm_cvol_control_get,
|
||||||
.put = snd_trident_pcm_cvol_control_put,
|
.put = snd_trident_pcm_cvol_control_put,
|
||||||
|
.tlv = { .p = db_scale_crvol },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void snd_trident_notify_pcm_change1(struct snd_card *card,
|
static void snd_trident_notify_pcm_change1(struct snd_card *card,
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ac97_codec.h>
|
#include <sound/ac97_codec.h>
|
||||||
#include <sound/mpu401.h>
|
#include <sound/mpu401.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
@ -1277,7 +1278,18 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
|
||||||
if (! ratep->used)
|
if (! ratep->used)
|
||||||
ratep->rate = 0;
|
ratep->rate = 0;
|
||||||
spin_unlock_irq(&ratep->lock);
|
spin_unlock_irq(&ratep->lock);
|
||||||
|
if (! ratep->rate) {
|
||||||
|
if (! viadev->direction) {
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_FRONT_DAC_RATE, 0);
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_SURR_DAC_RATE, 0);
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_LFE_DAC_RATE, 0);
|
||||||
|
} else
|
||||||
|
snd_ac97_update_power(chip->ac97,
|
||||||
|
AC97_PCM_LR_ADC_RATE, 0);
|
||||||
|
}
|
||||||
viadev->substream = NULL;
|
viadev->substream = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1687,21 +1699,29 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = {
|
static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = {
|
||||||
.name = "PCM Playback Volume",
|
.name = "PCM Playback Volume",
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.info = snd_via8233_dxs_volume_info,
|
.info = snd_via8233_dxs_volume_info,
|
||||||
.get = snd_via8233_pcmdxs_volume_get,
|
.get = snd_via8233_pcmdxs_volume_get,
|
||||||
.put = snd_via8233_pcmdxs_volume_put,
|
.put = snd_via8233_pcmdxs_volume_put,
|
||||||
|
.tlv = { .p = db_scale_dxs }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = {
|
static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = {
|
||||||
.name = "VIA DXS Playback Volume",
|
.name = "VIA DXS Playback Volume",
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.count = 4,
|
.count = 4,
|
||||||
.info = snd_via8233_dxs_volume_info,
|
.info = snd_via8233_dxs_volume_info,
|
||||||
.get = snd_via8233_dxs_volume_get,
|
.get = snd_via8233_dxs_volume_get,
|
||||||
.put = snd_via8233_dxs_volume_put,
|
.put = snd_via8233_dxs_volume_put,
|
||||||
|
.tlv = { .p = db_scale_dxs }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2393,6 +2413,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision)
|
||||||
{ .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
|
{ .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
|
||||||
{ .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
|
{ .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
|
||||||
{ .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
|
{ .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
|
||||||
|
{ .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */
|
||||||
{ .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
|
{ .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
|
||||||
{ .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
|
{ .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
|
||||||
{ .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
|
{ .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include "vx222.h"
|
#include "vx222.h"
|
||||||
|
|
||||||
#define CARD_NAME "VX222"
|
#define CARD_NAME "VX222"
|
||||||
|
@ -72,6 +73,9 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids);
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
|
||||||
|
|
||||||
static struct snd_vx_hardware vx222_old_hw = {
|
static struct snd_vx_hardware vx222_old_hw = {
|
||||||
|
|
||||||
.name = "VX222/Old",
|
.name = "VX222/Old",
|
||||||
|
@ -81,6 +85,7 @@ static struct snd_vx_hardware vx222_old_hw = {
|
||||||
.num_ins = 1,
|
.num_ins = 1,
|
||||||
.num_outs = 1,
|
.num_outs = 1,
|
||||||
.output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
|
.output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
|
||||||
|
.output_level_db_scale = db_scale_old_vol,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_vx_hardware vx222_v2_hw = {
|
static struct snd_vx_hardware vx222_v2_hw = {
|
||||||
|
@ -92,6 +97,7 @@ static struct snd_vx_hardware vx222_v2_hw = {
|
||||||
.num_ins = 1,
|
.num_ins = 1,
|
||||||
.num_outs = 1,
|
.num_outs = 1,
|
||||||
.output_level_max = VX2_AKM_LEVEL_MAX,
|
.output_level_max = VX2_AKM_LEVEL_MAX,
|
||||||
|
.output_level_db_scale = db_scale_akm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_vx_hardware vx222_mic_hw = {
|
static struct snd_vx_hardware vx222_mic_hw = {
|
||||||
|
@ -103,6 +109,7 @@ static struct snd_vx_hardware vx222_mic_hw = {
|
||||||
.num_ins = 1,
|
.num_ins = 1,
|
||||||
.num_outs = 1,
|
.num_outs = 1,
|
||||||
.output_level_max = VX2_AKM_LEVEL_MAX,
|
.output_level_max = VX2_AKM_LEVEL_MAX,
|
||||||
|
.output_level_db_scale = db_scale_akm,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include "vx222.h"
|
#include "vx222.h"
|
||||||
|
|
||||||
|
@ -845,6 +846,8 @@ static void vx2_set_input_level(struct snd_vx222 *chip)
|
||||||
|
|
||||||
#define MIC_LEVEL_MAX 0xff
|
#define MIC_LEVEL_MAX 0xff
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* controls API for input levels
|
* controls API for input levels
|
||||||
*/
|
*/
|
||||||
|
@ -922,18 +925,24 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
|
||||||
|
|
||||||
static struct snd_kcontrol_new vx_control_input_level = {
|
static struct snd_kcontrol_new vx_control_input_level = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Capture Volume",
|
.name = "Capture Volume",
|
||||||
.info = vx_input_level_info,
|
.info = vx_input_level_info,
|
||||||
.get = vx_input_level_get,
|
.get = vx_input_level_get,
|
||||||
.put = vx_input_level_put,
|
.put = vx_input_level_put,
|
||||||
|
.tlv = { .p = db_scale_mic },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_kcontrol_new vx_control_mic_level = {
|
static struct snd_kcontrol_new vx_control_mic_level = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Mic Capture Volume",
|
.name = "Mic Capture Volume",
|
||||||
.info = vx_mic_level_info,
|
.info = vx_mic_level_info,
|
||||||
.get = vx_mic_level_get,
|
.get = vx_mic_level_get,
|
||||||
.put = vx_mic_level_put,
|
.put = vx_mic_level_put,
|
||||||
|
.tlv = { .p = db_scale_mic },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
#include <sound/info.h>
|
#include <sound/info.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include <sound/ymfpci.h>
|
#include <sound/ymfpci.h>
|
||||||
#include <sound/asoundef.h>
|
#include <sound/asoundef.h>
|
||||||
#include <sound/mpu401.h>
|
#include <sound/mpu401.h>
|
||||||
|
@ -1477,11 +1478,15 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol,
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
|
||||||
|
|
||||||
#define YMFPCI_DOUBLE(xname, xindex, reg) \
|
#define YMFPCI_DOUBLE(xname, xindex, reg) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||||
.info = snd_ymfpci_info_double, \
|
.info = snd_ymfpci_info_double, \
|
||||||
.get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \
|
.get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \
|
||||||
.private_value = reg }
|
.private_value = reg, \
|
||||||
|
.tlv = { .p = db_scale_native } }
|
||||||
|
|
||||||
static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
|
|
|
@ -206,7 +206,7 @@ static void snd_pdacf_detach(struct pcmcia_device *link)
|
||||||
snd_pdacf_powerdown(chip);
|
snd_pdacf_powerdown(chip);
|
||||||
chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
|
chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
|
||||||
snd_card_disconnect(chip->card);
|
snd_card_disconnect(chip->card);
|
||||||
snd_card_free_in_thread(chip->card);
|
snd_card_free_when_closed(chip->card);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <sound/driver.h>
|
#include <sound/driver.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
#include "vxpocket.h"
|
#include "vxpocket.h"
|
||||||
|
|
||||||
#define MIC_LEVEL_MIN 0
|
#define MIC_LEVEL_MIN 0
|
||||||
|
@ -63,12 +64,17 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0);
|
||||||
|
|
||||||
static struct snd_kcontrol_new vx_control_mic_level = {
|
static struct snd_kcontrol_new vx_control_mic_level = {
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
.name = "Mic Capture Volume",
|
.name = "Mic Capture Volume",
|
||||||
.info = vx_mic_level_info,
|
.info = vx_mic_level_info,
|
||||||
.get = vx_mic_level_get,
|
.get = vx_mic_level_get,
|
||||||
.put = vx_mic_level_put,
|
.put = vx_mic_level_put,
|
||||||
|
.tlv = { .p = db_scale_mic },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue