Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (297 commits) ALSA: asihpi - Replace with snd_ctl_boolean_mono_info() ALSA: asihpi - HPI version 4.08 ALSA: asihpi - Add volume mute controls ALSA: asihpi - Control name updates ALSA: asihpi - Use size_t for sizeof result ALSA: asihpi - Explicitly include mutex.h ALSA: asihpi - Add new node and message defines ALSA: asihpi - Make local function static ALSA: asihpi - Fix minor typos and spelling ALSA: asihpi - Remove unused structures, macros and functions ALSA: asihpi - Remove spurious adapter index check ALSA: asihpi - Revise snd_pcm_debug_name, get rid of DEBUG_NAME macro ALSA: asihpi - DSP code loader API now independent of OS ALSA: asihpi - Remove controlex structs and associated special data transfer code ALSA: asihpi - Increase request and response buffer sizes ALSA: asihpi - Give more meaningful name to hpi request message type ALSA: usb-audio - Add quirk for Roland / BOSS BR-800 ALSA: hda - Remove a superfluous argument of via_auto_init_output() ALSA: hda - Fix indep-HP path (de-)activation for VT1708* codecs ALSA: hda - Add documentation for codec-specific mixer controls ...
This commit is contained in:
commit
e498037105
|
@ -1164,7 +1164,7 @@
|
|||
}
|
||||
chip->port = pci_resource_start(pci, 0);
|
||||
if (request_irq(pci->irq, snd_mychip_interrupt,
|
||||
IRQF_SHARED, "My Chip", chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
|
||||
snd_mychip_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1197,7 +1197,7 @@
|
|||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver driver = {
|
||||
.name = "My Own Chip",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_mychip_ids,
|
||||
.probe = snd_mychip_probe,
|
||||
.remove = __devexit_p(snd_mychip_remove),
|
||||
|
@ -1340,7 +1340,7 @@
|
|||
<programlisting>
|
||||
<![CDATA[
|
||||
if (request_irq(pci->irq, snd_mychip_interrupt,
|
||||
IRQF_SHARED, "My Chip", chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
|
||||
snd_mychip_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1616,7 +1616,7 @@
|
|||
<programlisting>
|
||||
<![CDATA[
|
||||
static struct pci_driver driver = {
|
||||
.name = "My Own Chip",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_mychip_ids,
|
||||
.probe = snd_mychip_probe,
|
||||
.remove = __devexit_p(snd_mychip_remove),
|
||||
|
@ -5816,7 +5816,7 @@ struct _snd_pcm_runtime {
|
|||
<programlisting>
|
||||
<![CDATA[
|
||||
static struct pci_driver driver = {
|
||||
.name = "My Chip",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_my_ids,
|
||||
.probe = snd_my_probe,
|
||||
.remove = __devexit_p(snd_my_remove),
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
This file explains the codec-specific mixer controls.
|
||||
|
||||
Realtek codecs
|
||||
--------------
|
||||
|
||||
* Channel Mode
|
||||
This is an enum control to change the surround-channel setup,
|
||||
appears only when the surround channels are available.
|
||||
It gives the number of channels to be used, "2ch", "4ch", "6ch",
|
||||
and "8ch". According to the configuration, this also controls the
|
||||
jack-retasking of multi-I/O jacks.
|
||||
|
||||
* Auto-Mute Mode
|
||||
This is an enum control to change the auto-mute behavior of the
|
||||
headphone and line-out jacks. If built-in speakers and headphone
|
||||
and/or line-out jacks are available on a machine, this controls
|
||||
appears.
|
||||
When there are only either headphones or line-out jacks, it gives
|
||||
"Disabled" and "Enabled" state. When enabled, the speaker is muted
|
||||
automatically when a jack is plugged.
|
||||
|
||||
When both headphone and line-out jacks are present, it gives
|
||||
"Disabled", "Speaker Only" and "Line-Out+Speaker". When
|
||||
speaker-only is chosen, plugging into a headphone or a line-out jack
|
||||
mutes the speakers, but not line-outs. When line-out+speaker is
|
||||
selected, plugging to a headphone jack mutes both speakers and
|
||||
line-outs.
|
||||
|
||||
|
||||
IDT/Sigmatel codecs
|
||||
-------------------
|
||||
|
||||
* Analog Loopback
|
||||
This control enables/disables the analog-loopback circuit. This
|
||||
appears only when "loopback" is set to true in a codec hint
|
||||
(see HD-Audio.txt). Note that on some codecs the analog-loopback
|
||||
and the normal PCM playback are exclusive, i.e. when this is on, you
|
||||
won't hear any PCM stream.
|
||||
|
||||
* Swap Center/LFE
|
||||
Swaps the center and LFE channel order. Normally, the left
|
||||
corresponds to the center and the right to the LFE. When this is
|
||||
ON, the left to the LFE and the right to the center.
|
||||
|
||||
* Headphone as Line Out
|
||||
When this control is ON, treat the headphone jacks as line-out
|
||||
jacks. That is, the headphone won't auto-mute the other line-outs,
|
||||
and no HP-amp is set to the pins.
|
||||
|
||||
* Mic Jack Mode, Line Jack Mode, etc
|
||||
These enum controls the direction and the bias of the input jack
|
||||
pins. Depending on the jack type, it can set as "Mic In" and "Line
|
||||
In", for determining the input bias, or it can be set to "Line Out"
|
||||
when the pin is a multi-I/O jack for surround channels.
|
||||
|
||||
|
||||
VIA codecs
|
||||
----------
|
||||
|
||||
* Smart 5.1
|
||||
An enum control to re-task the multi-I/O jacks for surround outputs.
|
||||
When it's ON, the corresponding input jacks (usually a line-in and a
|
||||
mic-in) are switched as the surround and the CLFE output jacks.
|
||||
|
||||
* Independent HP
|
||||
When this enum control is enabled, the headphone output is routed
|
||||
from an individual stream (the third PCM such as hw:0,2) instead of
|
||||
the primary stream. In the case the headphone DAC is shared with a
|
||||
side or a CLFE-channel DAC, the DAC is switched to the headphone
|
||||
automatically.
|
||||
|
||||
* Loopback Mixing
|
||||
An enum control to determine whether the analog-loopback route is
|
||||
enabled or not. When it's enabled, the analog-loopback is mixed to
|
||||
the front-channel. Also, the same route is used for the headphone
|
||||
and speaker outputs. As a side-effect, when this mode is set, the
|
||||
individual volume controls will be no longer available for
|
||||
headphones and speakers because there is only one DAC connected to a
|
||||
mixer widget.
|
||||
|
||||
* Dynamic Power-Control
|
||||
This control determines whether the dynamic power-control per jack
|
||||
detection is enabled or not. When enabled, the widgets power state
|
||||
(D0/D3) are changed dynamically depending on the jack plugging
|
||||
state for saving power consumptions. However, if your system
|
||||
doesn't provide a proper jack-detection, this won't work; in such a
|
||||
case, turn this control OFF.
|
||||
|
||||
* Jack Detect
|
||||
This control is provided only for VT1708 codec which gives no proper
|
||||
unsolicited event per jack plug. When this is on, the driver polls
|
||||
the jack detection so that the headphone auto-mute can work, while
|
||||
turning this off would reduce the power consumption.
|
||||
|
||||
|
||||
Conexant codecs
|
||||
---------------
|
||||
|
||||
* Auto-Mute Mode
|
||||
See Reatek codecs.
|
|
@ -534,6 +534,8 @@ L: device-drivers-devel@blackfin.uclinux.org
|
|||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://wiki.analog.com/
|
||||
S: Supported
|
||||
F: sound/soc/codecs/adau*
|
||||
F: sound/soc/codecs/adav*
|
||||
F: sound/soc/codecs/ad1*
|
||||
F: sound/soc/codecs/ssm*
|
||||
|
||||
|
|
|
@ -1308,6 +1308,7 @@
|
|||
#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041
|
||||
#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042
|
||||
#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043
|
||||
#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062
|
||||
#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000
|
||||
|
||||
#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
|
||||
#include "seq_device.h"
|
||||
|
@ -63,6 +64,7 @@ struct snd_rawmidi_global_ops {
|
|||
};
|
||||
|
||||
struct snd_rawmidi_runtime {
|
||||
struct snd_rawmidi_substream *substream;
|
||||
unsigned int drain: 1, /* drain stage */
|
||||
oss: 1; /* OSS compatible mode */
|
||||
/* midi stream buffer */
|
||||
|
@ -79,7 +81,7 @@ struct snd_rawmidi_runtime {
|
|||
/* event handler (new bytes, input only) */
|
||||
void (*event)(struct snd_rawmidi_substream *substream);
|
||||
/* defers calls to event [input] or ops->trigger [output] */
|
||||
struct tasklet_struct tasklet;
|
||||
struct work_struct event_work;
|
||||
/* private data */
|
||||
void *private_data;
|
||||
void (*private_free)(struct snd_rawmidi_substream *substream);
|
||||
|
|
|
@ -209,6 +209,10 @@ struct snd_soc_dai_driver {
|
|||
struct snd_soc_pcm_stream capture;
|
||||
struct snd_soc_pcm_stream playback;
|
||||
unsigned int symmetric_rates:1;
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -348,6 +348,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
|
|||
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_route *route, int num);
|
||||
int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_route *route, int num);
|
||||
|
||||
/* dapm events */
|
||||
int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
|
||||
|
@ -429,6 +431,7 @@ struct snd_soc_dapm_path {
|
|||
/* status */
|
||||
u32 connect:1; /* source and sink widgets are connected */
|
||||
u32 walked:1; /* path has been walked */
|
||||
u32 weak:1; /* path ignored for power management */
|
||||
|
||||
int (*connected)(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink);
|
||||
|
@ -444,6 +447,7 @@ struct snd_soc_dapm_widget {
|
|||
char *name; /* widget name */
|
||||
char *sname; /* stream name */
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_platform *platform;
|
||||
struct list_head list;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
|
||||
|
@ -507,10 +511,11 @@ struct snd_soc_dapm_context {
|
|||
|
||||
struct device *dev; /* from parent - for debug */
|
||||
struct snd_soc_codec *codec; /* parent codec */
|
||||
struct snd_soc_platform *platform; /* parent platform */
|
||||
struct snd_soc_card *card; /* parent card */
|
||||
|
||||
/* used during DAPM updates */
|
||||
int dev_power;
|
||||
enum snd_soc_bias_level target_bias_level;
|
||||
struct list_head list;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
|
|
@ -202,6 +202,16 @@
|
|||
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
|
||||
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
|
||||
|
||||
/*
|
||||
* Component probe and remove ordering levels for components with runtime
|
||||
* dependencies.
|
||||
*/
|
||||
#define SND_SOC_COMP_ORDER_FIRST -2
|
||||
#define SND_SOC_COMP_ORDER_EARLY -1
|
||||
#define SND_SOC_COMP_ORDER_NORMAL 0
|
||||
#define SND_SOC_COMP_ORDER_LATE 1
|
||||
#define SND_SOC_COMP_ORDER_LAST 2
|
||||
|
||||
/*
|
||||
* Bias levels
|
||||
*
|
||||
|
@ -214,10 +224,10 @@
|
|||
* @OFF: Power Off. No restrictions on transition times.
|
||||
*/
|
||||
enum snd_soc_bias_level {
|
||||
SND_SOC_BIAS_OFF,
|
||||
SND_SOC_BIAS_STANDBY,
|
||||
SND_SOC_BIAS_PREPARE,
|
||||
SND_SOC_BIAS_ON,
|
||||
SND_SOC_BIAS_OFF = 0,
|
||||
SND_SOC_BIAS_STANDBY = 1,
|
||||
SND_SOC_BIAS_PREPARE = 2,
|
||||
SND_SOC_BIAS_ON = 3,
|
||||
};
|
||||
|
||||
struct snd_jack;
|
||||
|
@ -258,6 +268,11 @@ enum snd_soc_compress_type {
|
|||
SND_SOC_RBTREE_COMPRESSION
|
||||
};
|
||||
|
||||
enum snd_soc_pcm_subclass {
|
||||
SND_SOC_PCM_CLASS_PCM = 0,
|
||||
SND_SOC_PCM_CLASS_BE = 1,
|
||||
};
|
||||
|
||||
int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
unsigned int freq, int dir);
|
||||
int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
|
||||
|
@ -297,6 +312,10 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,
|
|||
unsigned int reg);
|
||||
int snd_soc_default_writable_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
int snd_soc_platform_read(struct snd_soc_platform *platform,
|
||||
unsigned int reg);
|
||||
int snd_soc_platform_write(struct snd_soc_platform *platform,
|
||||
unsigned int reg, unsigned int val);
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
|
@ -349,6 +368,8 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
|
|||
const char *prefix);
|
||||
int snd_soc_add_controls(struct snd_soc_codec *codec,
|
||||
const struct snd_kcontrol_new *controls, int num_controls);
|
||||
int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
|
||||
const struct snd_kcontrol_new *controls, int num_controls);
|
||||
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
|
||||
|
@ -612,6 +633,10 @@ struct snd_soc_codec_driver {
|
|||
|
||||
void (*seq_notifier)(struct snd_soc_dapm_context *,
|
||||
enum snd_soc_dapm_type, int);
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
};
|
||||
|
||||
/* SoC platform interface */
|
||||
|
@ -623,10 +648,17 @@ struct snd_soc_platform_driver {
|
|||
int (*resume)(struct snd_soc_dai *dai);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
|
||||
struct snd_pcm *);
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* Default control and setup, added after probe() is run */
|
||||
const struct snd_kcontrol_new *controls;
|
||||
int num_controls;
|
||||
const struct snd_soc_dapm_widget *dapm_widgets;
|
||||
int num_dapm_widgets;
|
||||
const struct snd_soc_dapm_route *dapm_routes;
|
||||
int num_dapm_routes;
|
||||
|
||||
/*
|
||||
* For platform caused delay reporting.
|
||||
* Optional.
|
||||
|
@ -636,6 +668,14 @@ struct snd_soc_platform_driver {
|
|||
|
||||
/* platform stream ops */
|
||||
struct snd_pcm_ops *ops;
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
|
||||
/* platform IO - used for platform DAPM */
|
||||
unsigned int (*read)(struct snd_soc_platform *, unsigned int);
|
||||
int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
|
||||
};
|
||||
|
||||
struct snd_soc_platform {
|
||||
|
@ -650,6 +690,8 @@ struct snd_soc_platform {
|
|||
struct snd_soc_card *card;
|
||||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
|
||||
struct snd_soc_dapm_context dapm;
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link {
|
||||
|
@ -725,8 +767,10 @@ struct snd_soc_card {
|
|||
|
||||
/* callbacks */
|
||||
int (*set_bias_level)(struct snd_soc_card *,
|
||||
struct snd_soc_dapm_context *dapm,
|
||||
enum snd_soc_bias_level level);
|
||||
int (*set_bias_level_post)(struct snd_soc_card *,
|
||||
struct snd_soc_dapm_context *dapm,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
long pmdown_time;
|
||||
|
@ -789,6 +833,9 @@ struct snd_soc_pcm_runtime {
|
|||
struct device dev;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
struct mutex pcm_mutex;
|
||||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
struct snd_pcm_ops ops;
|
||||
|
||||
unsigned int complete:1;
|
||||
unsigned int dev_registered:1;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
struct snd_soc_jack;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_platform;
|
||||
struct snd_soc_card;
|
||||
struct snd_soc_dapm_widget;
|
||||
|
||||
|
@ -59,6 +60,50 @@ DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
|
|||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_preg,
|
||||
|
||||
TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(platform, reg, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, platform->name )
|
||||
__field( int, id )
|
||||
__field( unsigned int, reg )
|
||||
__field( unsigned int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, platform->name);
|
||||
__entry->id = platform->id;
|
||||
__entry->reg = reg;
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name),
|
||||
(int)__entry->id, (unsigned int)__entry->reg,
|
||||
(unsigned int)__entry->val)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write,
|
||||
|
||||
TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(platform, reg, val)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read,
|
||||
|
||||
TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(platform, reg, val)
|
||||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_card,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card, int val),
|
||||
|
|
|
@ -92,16 +92,12 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre
|
|||
(!substream->append || runtime->avail >= count);
|
||||
}
|
||||
|
||||
static void snd_rawmidi_input_event_tasklet(unsigned long data)
|
||||
static void snd_rawmidi_input_event_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data;
|
||||
substream->runtime->event(substream);
|
||||
}
|
||||
|
||||
static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
|
||||
{
|
||||
struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data;
|
||||
substream->ops->trigger(substream, 1);
|
||||
struct snd_rawmidi_runtime *runtime =
|
||||
container_of(work, struct snd_rawmidi_runtime, event_work);
|
||||
if (runtime->event)
|
||||
runtime->event(runtime->substream);
|
||||
}
|
||||
|
||||
static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
|
||||
|
@ -110,16 +106,10 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
|
|||
|
||||
if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL)
|
||||
return -ENOMEM;
|
||||
runtime->substream = substream;
|
||||
spin_lock_init(&runtime->lock);
|
||||
init_waitqueue_head(&runtime->sleep);
|
||||
if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
|
||||
tasklet_init(&runtime->tasklet,
|
||||
snd_rawmidi_input_event_tasklet,
|
||||
(unsigned long)substream);
|
||||
else
|
||||
tasklet_init(&runtime->tasklet,
|
||||
snd_rawmidi_output_trigger_tasklet,
|
||||
(unsigned long)substream);
|
||||
INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
|
||||
runtime->event = NULL;
|
||||
runtime->buffer_size = PAGE_SIZE;
|
||||
runtime->avail_min = 1;
|
||||
|
@ -150,12 +140,7 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs
|
|||
{
|
||||
if (!substream->opened)
|
||||
return;
|
||||
if (up) {
|
||||
tasklet_schedule(&substream->runtime->tasklet);
|
||||
} else {
|
||||
tasklet_kill(&substream->runtime->tasklet);
|
||||
substream->ops->trigger(substream, 0);
|
||||
}
|
||||
substream->ops->trigger(substream, up);
|
||||
}
|
||||
|
||||
static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
|
||||
|
@ -163,8 +148,8 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i
|
|||
if (!substream->opened)
|
||||
return;
|
||||
substream->ops->trigger(substream, up);
|
||||
if (!up && substream->runtime->event)
|
||||
tasklet_kill(&substream->runtime->tasklet);
|
||||
if (!up)
|
||||
cancel_work_sync(&substream->runtime->event_work);
|
||||
}
|
||||
|
||||
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
|
||||
|
@ -641,10 +626,10 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
if (params->buffer_size != runtime->buffer_size) {
|
||||
newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
|
||||
newbuf = krealloc(runtime->buffer, params->buffer_size,
|
||||
GFP_KERNEL);
|
||||
if (!newbuf)
|
||||
return -ENOMEM;
|
||||
kfree(runtime->buffer);
|
||||
runtime->buffer = newbuf;
|
||||
runtime->buffer_size = params->buffer_size;
|
||||
runtime->avail = runtime->buffer_size;
|
||||
|
@ -668,10 +653,10 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
if (params->buffer_size != runtime->buffer_size) {
|
||||
newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
|
||||
newbuf = krealloc(runtime->buffer, params->buffer_size,
|
||||
GFP_KERNEL);
|
||||
if (!newbuf)
|
||||
return -ENOMEM;
|
||||
kfree(runtime->buffer);
|
||||
runtime->buffer = newbuf;
|
||||
runtime->buffer_size = params->buffer_size;
|
||||
}
|
||||
|
@ -926,7 +911,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
|
|||
}
|
||||
if (result > 0) {
|
||||
if (runtime->event)
|
||||
tasklet_schedule(&runtime->tasklet);
|
||||
schedule_work(&runtime->event_work);
|
||||
else if (snd_rawmidi_ready(substream))
|
||||
wake_up(&runtime->sleep);
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ static int fwspk_open(struct snd_pcm_substream *substream)
|
|||
|
||||
err = snd_pcm_hw_constraint_minmax(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
||||
5000, 8192000);
|
||||
5000, UINT_MAX);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -944,7 +944,7 @@ snd_ad1889_create(struct snd_card *card,
|
|||
spin_lock_init(&chip->lock); /* only now can we call ad1889_free */
|
||||
|
||||
if (request_irq(pci->irq, snd_ad1889_interrupt,
|
||||
IRQF_SHARED, card->driver, chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
|
||||
snd_ad1889_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1055,7 +1055,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
|
|||
MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);
|
||||
|
||||
static struct pci_driver ad1889_pci_driver = {
|
||||
.name = "AD1889 Audio",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_ad1889_ids,
|
||||
.probe = snd_ad1889_probe,
|
||||
.remove = __devexit_p(snd_ad1889_remove),
|
||||
|
|
|
@ -2090,7 +2090,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
|
|||
codec->port = pci_resource_start(codec->pci, 0);
|
||||
|
||||
if (request_irq(codec->pci->irq, snd_ali_card_interrupt,
|
||||
IRQF_SHARED, "ALI 5451", codec)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, codec)) {
|
||||
snd_printk(KERN_ERR "Unable to request irq.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -2295,7 +2295,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ALI 5451",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_ali_ids,
|
||||
.probe = snd_ali_probe,
|
||||
.remove = __devexit_p(snd_ali_remove),
|
||||
|
|
|
@ -722,7 +722,7 @@ static int __devinit snd_als300_create(struct snd_card *card,
|
|||
irq_handler = snd_als300_interrupt;
|
||||
|
||||
if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
|
||||
card->shortname, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_als300_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -846,7 +846,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ALS300",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_als300_ids,
|
||||
.probe = snd_als300_probe,
|
||||
.remove = __devexit_p(snd_als300_remove),
|
||||
|
|
|
@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci)
|
|||
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ALS4000",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_als4000_ids,
|
||||
.probe = snd_card_als4000_probe,
|
||||
.remove = __devexit_p(snd_card_als4000_remove),
|
||||
|
|
|
@ -49,19 +49,21 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
|
|||
#if defined CONFIG_SND_DEBUG
|
||||
/* copied from pcm_lib.c, hope later patch will make that version public
|
||||
and this copy can be removed */
|
||||
static void pcm_debug_name(struct snd_pcm_substream *substream,
|
||||
char *name, size_t len)
|
||||
static inline void
|
||||
snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
|
||||
{
|
||||
snprintf(name, len, "pcmC%dD%d%c:%d",
|
||||
snprintf(buf, size, "pcmC%dD%d%c:%d",
|
||||
substream->pcm->card->number,
|
||||
substream->pcm->device,
|
||||
substream->stream ? 'c' : 'p',
|
||||
substream->number);
|
||||
}
|
||||
#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name))
|
||||
#else
|
||||
#define pcm_debug_name(s, n, l) do { } while (0)
|
||||
#define DEBUG_NAME(name, substream) do { } while (0)
|
||||
static inline void
|
||||
snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
|
||||
{
|
||||
*buf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_SND_DEBUG_VERBOSE
|
||||
|
@ -304,7 +306,8 @@ static u16 handle_error(u16 err, int line, char *filename)
|
|||
static void print_hwparams(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *p)
|
||||
{
|
||||
DEBUG_NAME(substream, name);
|
||||
char name[16];
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_printd("%s HWPARAMS\n", name);
|
||||
snd_printd(" samplerate %d Hz\n", params_rate(p));
|
||||
snd_printd(" channels %d\n", params_channels(p));
|
||||
|
@ -576,8 +579,9 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
|
|||
struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_substream *s;
|
||||
u16 e;
|
||||
DEBUG_NAME(substream, name);
|
||||
char name[16];
|
||||
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_printdd("%s trigger\n", name);
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -741,7 +745,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
|
|||
int loops = 0;
|
||||
u16 state;
|
||||
u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
|
||||
DEBUG_NAME(substream, name);
|
||||
char name[16];
|
||||
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
|
||||
snd_printdd("%s snd_card_asihpi_timer_function\n", name);
|
||||
|
||||
|
@ -1323,10 +1329,12 @@ static const char * const asihpi_src_names[] = {
|
|||
"RF",
|
||||
"Clock",
|
||||
"Bitstream",
|
||||
"Microphone",
|
||||
"Cobranet",
|
||||
"Mic",
|
||||
"Net",
|
||||
"Analog",
|
||||
"Adapter",
|
||||
"RTP",
|
||||
"GPI",
|
||||
};
|
||||
|
||||
compile_time_assert(
|
||||
|
@ -1341,8 +1349,10 @@ static const char * const asihpi_dst_names[] = {
|
|||
"Digital",
|
||||
"RF",
|
||||
"Speaker",
|
||||
"Cobranet Out",
|
||||
"Analog"
|
||||
"Net",
|
||||
"Analog",
|
||||
"RTP",
|
||||
"GPO",
|
||||
};
|
||||
|
||||
compile_time_assert(
|
||||
|
@ -1476,11 +1486,40 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
|
||||
|
||||
#define snd_asihpi_volume_mute_info snd_ctl_boolean_mono_info
|
||||
|
||||
static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 h_control = kcontrol->private_value;
|
||||
u32 mute;
|
||||
|
||||
hpi_handle_error(hpi_volume_get_mute(h_control, &mute));
|
||||
ucontrol->value.integer.value[0] = mute ? 0 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 h_control = kcontrol->private_value;
|
||||
int change = 1;
|
||||
/* HPI currently only supports all or none muting of multichannel volume
|
||||
ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted
|
||||
*/
|
||||
int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;
|
||||
hpi_handle_error(hpi_volume_set_mute(h_control, mute));
|
||||
return change;
|
||||
}
|
||||
|
||||
static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
|
||||
struct hpi_control *hpi_ctl)
|
||||
{
|
||||
struct snd_card *card = asihpi->card;
|
||||
struct snd_kcontrol_new snd_control;
|
||||
int err;
|
||||
u32 mute;
|
||||
|
||||
asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
|
||||
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
|
@ -1490,7 +1529,19 @@ static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
|
|||
snd_control.put = snd_asihpi_volume_put;
|
||||
snd_control.tlv.p = db_scale_100;
|
||||
|
||||
return ctl_add(card, &snd_control, asihpi);
|
||||
err = ctl_add(card, &snd_control, asihpi);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) {
|
||||
asihpi_ctl_init(&snd_control, hpi_ctl, "Switch");
|
||||
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
snd_control.info = snd_asihpi_volume_mute_info;
|
||||
snd_control.get = snd_asihpi_volume_mute_get;
|
||||
snd_control.put = snd_asihpi_volume_mute_put;
|
||||
err = ctl_add(card, &snd_control, asihpi);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------
|
||||
|
@ -2923,7 +2974,7 @@ static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
|
|||
MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "asihpi",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = asihpi_pci_tbl,
|
||||
.probe = snd_asihpi_probe,
|
||||
.remove = __devexit_p(snd_asihpi_remove),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
|
||||
Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -42,12 +42,11 @@ i.e 3.05.02 is a development version
|
|||
#define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF))
|
||||
#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
|
||||
|
||||
/* Use single digits for versions less that 10 to avoid octal. */
|
||||
#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 6, 0)
|
||||
#define HPI_VER_STRING "4.06.00"
|
||||
#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 8, 0)
|
||||
#define HPI_VER_STRING "4.08.00"
|
||||
|
||||
/* Library version as documented in hpi-api-versions.txt */
|
||||
#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0)
|
||||
#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(10, 0, 0)
|
||||
|
||||
#include <linux/types.h>
|
||||
#define HPI_BUILD_EXCLUDE_DEPRECATED
|
||||
|
@ -211,8 +210,12 @@ enum HPI_SOURCENODES {
|
|||
HPI_SOURCENODE_COBRANET = 109,
|
||||
HPI_SOURCENODE_ANALOG = 110, /**< analog input node. */
|
||||
HPI_SOURCENODE_ADAPTER = 111, /**< adapter node. */
|
||||
/** RTP stream input node - This node is a destination for
|
||||
packets of RTP audio samples from other devices. */
|
||||
HPI_SOURCENODE_RTP_DESTINATION = 112,
|
||||
HPI_SOURCENODE_GP_IN = 113, /**< general purpose input. */
|
||||
/* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */
|
||||
HPI_SOURCENODE_LAST_INDEX = 111 /**< largest ID */
|
||||
HPI_SOURCENODE_LAST_INDEX = 113 /**< largest ID */
|
||||
/* AX6 max sourcenode types = 15 */
|
||||
};
|
||||
|
||||
|
@ -228,7 +231,7 @@ enum HPI_DESTNODES {
|
|||
HPI_DESTNODE_NONE = 200,
|
||||
/** In Stream (Record) node. */
|
||||
HPI_DESTNODE_ISTREAM = 201,
|
||||
HPI_DESTNODE_LINEOUT = 202, /**< line out node. */
|
||||
HPI_DESTNODE_LINEOUT = 202, /**< line out node. */
|
||||
HPI_DESTNODE_AESEBU_OUT = 203, /**< AES/EBU output node. */
|
||||
HPI_DESTNODE_RF = 204, /**< RF output node. */
|
||||
HPI_DESTNODE_SPEAKER = 205, /**< speaker output node. */
|
||||
|
@ -236,9 +239,12 @@ enum HPI_DESTNODES {
|
|||
Audio samples from the device are sent out on the Cobranet network.*/
|
||||
HPI_DESTNODE_COBRANET = 206,
|
||||
HPI_DESTNODE_ANALOG = 207, /**< analog output node. */
|
||||
|
||||
/** RTP stream output node - This node is a source for
|
||||
packets of RTP audio samples that are sent to other devices. */
|
||||
HPI_DESTNODE_RTP_SOURCE = 208,
|
||||
HPI_DESTNODE_GP_OUT = 209, /**< general purpose output node. */
|
||||
/* !!!Update this AND hpidebug.h if you add a new destnode type!!! */
|
||||
HPI_DESTNODE_LAST_INDEX = 207 /**< largest ID */
|
||||
HPI_DESTNODE_LAST_INDEX = 209 /**< largest ID */
|
||||
/* AX6 max destnode types = 15 */
|
||||
};
|
||||
|
||||
|
|
|
@ -359,7 +359,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
|
|||
HPI_ERROR_PROCESSING_MESSAGE);
|
||||
|
||||
switch (phm->type) {
|
||||
case HPI_TYPE_MESSAGE:
|
||||
case HPI_TYPE_REQUEST:
|
||||
switch (phm->object) {
|
||||
case HPI_OBJ_SUBSYSTEM:
|
||||
subsys_message(phm, phr);
|
||||
|
@ -538,7 +538,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
|
|||
|
||||
HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n");
|
||||
memset(&hm, 0, sizeof(hm));
|
||||
hm.type = HPI_TYPE_MESSAGE;
|
||||
hm.type = HPI_TYPE_REQUEST;
|
||||
hm.size = sizeof(struct hpi_message);
|
||||
hm.object = HPI_OBJ_ADAPTER;
|
||||
hm.function = HPI_ADAPTER_GET_INFO;
|
||||
|
@ -946,11 +946,8 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
|
|||
}
|
||||
|
||||
/* write the DSP code down into the DSPs memory */
|
||||
/*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */
|
||||
dsp_code.ps_dev = pao->pci.pci_dev;
|
||||
|
||||
error = hpi_dsp_code_open(boot_load_family, &dsp_code,
|
||||
pos_error_code);
|
||||
error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev,
|
||||
&dsp_code, pos_error_code);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
|
|
@ -373,6 +373,7 @@ static void instream_message(struct hpi_adapter_obj *pao,
|
|||
/** Entry point to this HPI backend
|
||||
* All calls to the HPI start here
|
||||
*/
|
||||
static
|
||||
void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
|
||||
struct hpi_response *phr)
|
||||
{
|
||||
|
@ -392,7 +393,7 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
|
|||
|
||||
HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
|
||||
switch (phm->type) {
|
||||
case HPI_TYPE_MESSAGE:
|
||||
case HPI_TYPE_REQUEST:
|
||||
switch (phm->object) {
|
||||
case HPI_OBJ_SUBSYSTEM:
|
||||
subsys_message(pao, phm, phr);
|
||||
|
@ -402,7 +403,6 @@ void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
|
|||
adapter_message(pao, phm, phr);
|
||||
break;
|
||||
|
||||
case HPI_OBJ_CONTROLEX:
|
||||
case HPI_OBJ_CONTROL:
|
||||
control_message(pao, phm, phr);
|
||||
break;
|
||||
|
@ -634,11 +634,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
|
|||
|
||||
HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
|
||||
memset(&hm, 0, sizeof(hm));
|
||||
hm.type = HPI_TYPE_MESSAGE;
|
||||
/* wAdapterIndex == version == 0 */
|
||||
hm.type = HPI_TYPE_REQUEST;
|
||||
hm.size = sizeof(hm);
|
||||
hm.object = HPI_OBJ_ADAPTER;
|
||||
hm.function = HPI_ADAPTER_GET_INFO;
|
||||
hm.adapter_index = 0;
|
||||
|
||||
memset(&hr, 0, sizeof(hr));
|
||||
hr.size = sizeof(hr);
|
||||
|
||||
|
@ -658,9 +659,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
|
|||
hr.u.ax.info.num_outstreams +
|
||||
hr.u.ax.info.num_instreams;
|
||||
|
||||
hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams,
|
||||
65536, pao->pci.pci_dev);
|
||||
|
||||
HPI_DEBUG_LOG(VERBOSE,
|
||||
"got adapter info type %x index %d serial %d\n",
|
||||
hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
|
||||
|
@ -709,9 +707,6 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao)
|
|||
[i]);
|
||||
phw->outstream_host_buffer_size[i] = 0;
|
||||
}
|
||||
|
||||
hpios_locked_mem_unprepare(pao->pci.pci_dev);
|
||||
|
||||
kfree(phw);
|
||||
}
|
||||
|
||||
|
@ -1371,9 +1366,8 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
|
|||
return err;
|
||||
|
||||
/* write the DSP code down into the DSPs memory */
|
||||
dsp_code.ps_dev = pao->pci.pci_dev;
|
||||
err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code,
|
||||
pos_error_code);
|
||||
err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev,
|
||||
&dsp_code, pos_error_code);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -2084,13 +2078,13 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
|
|||
u16 err = 0;
|
||||
|
||||
message_count++;
|
||||
if (phm->size > sizeof(interface->u)) {
|
||||
if (phm->size > sizeof(interface->u.message_buffer)) {
|
||||
phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
|
||||
phr->specific_error = sizeof(interface->u);
|
||||
phr->specific_error = sizeof(interface->u.message_buffer);
|
||||
phr->size = sizeof(struct hpi_response_header);
|
||||
HPI_DEBUG_LOG(ERROR,
|
||||
"message len %d too big for buffer %zd \n", phm->size,
|
||||
sizeof(interface->u));
|
||||
sizeof(interface->u.message_buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2122,18 +2116,19 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
|
|||
|
||||
/* read the result */
|
||||
if (time_out) {
|
||||
if (interface->u.response_buffer.size <= phr->size)
|
||||
if (interface->u.response_buffer.response.size <= phr->size)
|
||||
memcpy(phr, &interface->u.response_buffer,
|
||||
interface->u.response_buffer.size);
|
||||
interface->u.response_buffer.response.size);
|
||||
else {
|
||||
HPI_DEBUG_LOG(ERROR,
|
||||
"response len %d too big for buffer %d\n",
|
||||
interface->u.response_buffer.size, phr->size);
|
||||
interface->u.response_buffer.response.size,
|
||||
phr->size);
|
||||
memcpy(phr, &interface->u.response_buffer,
|
||||
sizeof(struct hpi_response_header));
|
||||
phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
|
||||
phr->specific_error =
|
||||
interface->u.response_buffer.size;
|
||||
interface->u.response_buffer.response.size;
|
||||
phr->size = sizeof(struct hpi_response_header);
|
||||
}
|
||||
}
|
||||
|
@ -2202,23 +2197,6 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
|
|||
phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
|
||||
break;
|
||||
|
||||
case HPI_CONTROL_SET_STATE:
|
||||
if (phm->object == HPI_OBJ_CONTROLEX
|
||||
&& phm->u.cx.attribute == HPI_COBRANET_SET_DATA)
|
||||
err = hpi6205_transfer_data(pao,
|
||||
phm->u.cx.u.cobranet_bigdata.pb_data,
|
||||
phm->u.cx.u.cobranet_bigdata.byte_count,
|
||||
H620_HIF_SEND_DATA);
|
||||
break;
|
||||
|
||||
case HPI_CONTROL_GET_STATE:
|
||||
if (phm->object == HPI_OBJ_CONTROLEX
|
||||
&& phm->u.cx.attribute == HPI_COBRANET_GET_DATA)
|
||||
err = hpi6205_transfer_data(pao,
|
||||
phm->u.cx.u.cobranet_bigdata.pb_data,
|
||||
phr->u.cx.u.cobranet_data.byte_count,
|
||||
H620_HIF_GET_DATA);
|
||||
break;
|
||||
}
|
||||
phr->error = err;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
|
||||
Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -70,15 +70,28 @@ The Host located memory buffer that the 6205 will bus master
|
|||
in and out of.
|
||||
************************************************************/
|
||||
#define HPI6205_SIZEOF_DATA (16*1024)
|
||||
|
||||
struct message_buffer_6205 {
|
||||
struct hpi_message message;
|
||||
char data[256];
|
||||
};
|
||||
|
||||
struct response_buffer_6205 {
|
||||
struct hpi_response response;
|
||||
char data[256];
|
||||
};
|
||||
|
||||
union buffer_6205 {
|
||||
struct message_buffer_6205 message_buffer;
|
||||
struct response_buffer_6205 response_buffer;
|
||||
u8 b_data[HPI6205_SIZEOF_DATA];
|
||||
};
|
||||
|
||||
struct bus_master_interface {
|
||||
u32 host_cmd;
|
||||
u32 dsp_ack;
|
||||
u32 transfer_size_in_bytes;
|
||||
union {
|
||||
struct hpi_message_header message_buffer;
|
||||
struct hpi_response_header response_buffer;
|
||||
u8 b_data[HPI6205_SIZEOF_DATA];
|
||||
} u;
|
||||
union buffer_6205 u;
|
||||
struct controlcache_6205 control_cache;
|
||||
struct async_event_buffer_6205 async_buffer;
|
||||
struct hpi_hostbuffer_status
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
|
||||
Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -32,12 +32,6 @@ HPI internal definitions
|
|||
#include "hpios.h"
|
||||
|
||||
/* physical memory allocation */
|
||||
void hpios_locked_mem_init(void
|
||||
);
|
||||
void hpios_locked_mem_free_all(void
|
||||
);
|
||||
#define hpios_locked_mem_prepare(a, b, c, d);
|
||||
#define hpios_locked_mem_unprepare(a)
|
||||
|
||||
/** Allocate and map an area of locked memory for bus master DMA operations.
|
||||
|
||||
|
@ -226,8 +220,8 @@ enum HPI_CONTROL_ATTRIBUTES {
|
|||
|
||||
HPI_COBRANET_SET = HPI_CTL_ATTR(COBRANET, 1),
|
||||
HPI_COBRANET_GET = HPI_CTL_ATTR(COBRANET, 2),
|
||||
HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3),
|
||||
HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4),
|
||||
/*HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3), */
|
||||
/*HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4), */
|
||||
HPI_COBRANET_GET_STATUS = HPI_CTL_ATTR(COBRANET, 5),
|
||||
HPI_COBRANET_SEND_PACKET = HPI_CTL_ATTR(COBRANET, 6),
|
||||
HPI_COBRANET_GET_PACKET = HPI_CTL_ATTR(COBRANET, 7),
|
||||
|
@ -364,10 +358,12 @@ Used in DLL to indicate device not present
|
|||
#define HPI_ADAPTER_ASI(f) (f)
|
||||
|
||||
enum HPI_MESSAGE_TYPES {
|
||||
HPI_TYPE_MESSAGE = 1,
|
||||
HPI_TYPE_REQUEST = 1,
|
||||
HPI_TYPE_RESPONSE = 2,
|
||||
HPI_TYPE_DATA = 3,
|
||||
HPI_TYPE_SSX2BYPASS_MESSAGE = 4
|
||||
HPI_TYPE_SSX2BYPASS_MESSAGE = 4,
|
||||
HPI_TYPE_COMMAND = 5,
|
||||
HPI_TYPE_NOTIFICATION = 6
|
||||
};
|
||||
|
||||
enum HPI_OBJECT_TYPES {
|
||||
|
@ -383,7 +379,7 @@ enum HPI_OBJECT_TYPES {
|
|||
HPI_OBJ_WATCHDOG = 10,
|
||||
HPI_OBJ_CLOCK = 11,
|
||||
HPI_OBJ_PROFILE = 12,
|
||||
HPI_OBJ_CONTROLEX = 13,
|
||||
/* HPI_ OBJ_ CONTROLEX = 13, */
|
||||
HPI_OBJ_ASYNCEVENT = 14
|
||||
#define HPI_OBJ_MAXINDEX 14
|
||||
};
|
||||
|
@ -608,7 +604,7 @@ struct hpi_data_compat32 {
|
|||
#endif
|
||||
|
||||
struct hpi_buffer {
|
||||
/** placehoder for backward compatibility (see dwBufferSize) */
|
||||
/** placeholder for backward compatibility (see dwBufferSize) */
|
||||
struct hpi_msg_format reserved;
|
||||
u32 command; /**< HPI_BUFFER_CMD_xxx*/
|
||||
u32 pci_address; /**< PCI physical address of buffer for DSP DMA */
|
||||
|
@ -912,95 +908,13 @@ union hpi_control_union_res {
|
|||
u32 remaining_chars;
|
||||
} chars8;
|
||||
char c_data12[12];
|
||||
};
|
||||
|
||||
/* HPI_CONTROLX_STRUCTURES */
|
||||
|
||||
/* Message */
|
||||
|
||||
/** Used for all HMI variables where max length <= 8 bytes
|
||||
*/
|
||||
struct hpi_controlx_msg_cobranet_data {
|
||||
u32 hmi_address;
|
||||
u32 byte_count;
|
||||
u32 data[2];
|
||||
};
|
||||
|
||||
/** Used for string data, and for packet bridge
|
||||
*/
|
||||
struct hpi_controlx_msg_cobranet_bigdata {
|
||||
u32 hmi_address;
|
||||
u32 byte_count;
|
||||
u8 *pb_data;
|
||||
#ifndef HPI64BIT
|
||||
u32 padding;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Used for PADS control reading of string fields.
|
||||
*/
|
||||
struct hpi_controlx_msg_pad_data {
|
||||
u32 field;
|
||||
u32 byte_count;
|
||||
u8 *pb_data;
|
||||
#ifndef HPI64BIT
|
||||
u32 padding;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Used for generic data
|
||||
*/
|
||||
|
||||
struct hpi_controlx_msg_generic {
|
||||
u32 param1;
|
||||
u32 param2;
|
||||
};
|
||||
|
||||
struct hpi_controlx_msg {
|
||||
u16 attribute; /* control attribute or property */
|
||||
u16 saved_index;
|
||||
union {
|
||||
struct hpi_controlx_msg_cobranet_data cobranet_data;
|
||||
struct hpi_controlx_msg_cobranet_bigdata cobranet_bigdata;
|
||||
struct hpi_controlx_msg_generic generic;
|
||||
struct hpi_controlx_msg_pad_data pad_data;
|
||||
/*struct param_value universal_value; */
|
||||
/* nothing extra to send for status read */
|
||||
} u;
|
||||
};
|
||||
|
||||
/* Response */
|
||||
/**
|
||||
*/
|
||||
struct hpi_controlx_res_cobranet_data {
|
||||
u32 byte_count;
|
||||
u32 data[2];
|
||||
};
|
||||
|
||||
struct hpi_controlx_res_cobranet_bigdata {
|
||||
u32 byte_count;
|
||||
};
|
||||
|
||||
struct hpi_controlx_res_cobranet_status {
|
||||
u32 status;
|
||||
u32 readable_size;
|
||||
u32 writeable_size;
|
||||
};
|
||||
|
||||
struct hpi_controlx_res_generic {
|
||||
u32 param1;
|
||||
u32 param2;
|
||||
};
|
||||
|
||||
struct hpi_controlx_res {
|
||||
union {
|
||||
struct hpi_controlx_res_cobranet_bigdata cobranet_bigdata;
|
||||
struct hpi_controlx_res_cobranet_data cobranet_data;
|
||||
struct hpi_controlx_res_cobranet_status cobranet_status;
|
||||
struct hpi_controlx_res_generic generic;
|
||||
/*struct param_info universal_info; */
|
||||
/*struct param_value universal_value; */
|
||||
} u;
|
||||
struct {
|
||||
u32 status;
|
||||
u32 readable_size;
|
||||
u32 writeable_size;
|
||||
} status;
|
||||
} cobranet;
|
||||
};
|
||||
|
||||
struct hpi_nvmemory_msg {
|
||||
|
@ -1126,7 +1040,6 @@ struct hpi_message {
|
|||
/* identical to struct hpi_control_msg,
|
||||
but field naming is improved */
|
||||
struct hpi_control_union_msg cu;
|
||||
struct hpi_controlx_msg cx; /* extended mixer control; */
|
||||
struct hpi_nvmemory_msg n;
|
||||
struct hpi_gpio_msg l; /* digital i/o */
|
||||
struct hpi_watchdog_msg w;
|
||||
|
@ -1151,7 +1064,7 @@ struct hpi_message {
|
|||
sizeof(struct hpi_message_header) + sizeof(struct hpi_watchdog_msg),\
|
||||
sizeof(struct hpi_message_header) + sizeof(struct hpi_clock_msg),\
|
||||
sizeof(struct hpi_message_header) + sizeof(struct hpi_profile_msg),\
|
||||
sizeof(struct hpi_message_header) + sizeof(struct hpi_controlx_msg),\
|
||||
sizeof(struct hpi_message_header), /* controlx obj removed */ \
|
||||
sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1101,6 @@ struct hpi_response {
|
|||
struct hpi_control_res c; /* mixer control; */
|
||||
/* identical to hpi_control_res, but field naming is improved */
|
||||
union hpi_control_union_res cu;
|
||||
struct hpi_controlx_res cx; /* extended mixer control; */
|
||||
struct hpi_nvmemory_res n;
|
||||
struct hpi_gpio_res l; /* digital i/o */
|
||||
struct hpi_watchdog_res w;
|
||||
|
@ -1213,7 +1125,7 @@ struct hpi_response {
|
|||
sizeof(struct hpi_response_header) + sizeof(struct hpi_watchdog_res),\
|
||||
sizeof(struct hpi_response_header) + sizeof(struct hpi_clock_res),\
|
||||
sizeof(struct hpi_response_header) + sizeof(struct hpi_profile_res),\
|
||||
sizeof(struct hpi_response_header) + sizeof(struct hpi_controlx_res),\
|
||||
sizeof(struct hpi_response_header), /* controlx obj removed */ \
|
||||
sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \
|
||||
}
|
||||
|
||||
|
@ -1308,6 +1220,30 @@ struct hpi_res_adapter_debug_read {
|
|||
u8 bytes[256];
|
||||
};
|
||||
|
||||
struct hpi_msg_cobranet_hmi {
|
||||
u16 attribute;
|
||||
u16 padding;
|
||||
u32 hmi_address;
|
||||
u32 byte_count;
|
||||
};
|
||||
|
||||
struct hpi_msg_cobranet_hmiwrite {
|
||||
struct hpi_message_header h;
|
||||
struct hpi_msg_cobranet_hmi p;
|
||||
u8 bytes[256];
|
||||
};
|
||||
|
||||
struct hpi_msg_cobranet_hmiread {
|
||||
struct hpi_message_header h;
|
||||
struct hpi_msg_cobranet_hmi p;
|
||||
};
|
||||
|
||||
struct hpi_res_cobranet_hmiread {
|
||||
struct hpi_response_header h;
|
||||
u32 byte_count;
|
||||
u8 bytes[256];
|
||||
};
|
||||
|
||||
#if 1
|
||||
#define hpi_message_header_v1 hpi_message_header
|
||||
#define hpi_response_header_v1 hpi_response_header
|
||||
|
@ -1338,7 +1274,6 @@ struct hpi_msg_payload_v0 {
|
|||
union hpi_mixerx_msg mx;
|
||||
struct hpi_control_msg c;
|
||||
struct hpi_control_union_msg cu;
|
||||
struct hpi_controlx_msg cx;
|
||||
struct hpi_nvmemory_msg n;
|
||||
struct hpi_gpio_msg l;
|
||||
struct hpi_watchdog_msg w;
|
||||
|
@ -1358,7 +1293,6 @@ struct hpi_res_payload_v0 {
|
|||
union hpi_mixerx_res mx;
|
||||
struct hpi_control_res c;
|
||||
union hpi_control_union_res cu;
|
||||
struct hpi_controlx_res cx;
|
||||
struct hpi_nvmemory_res n;
|
||||
struct hpi_gpio_res l;
|
||||
struct hpi_watchdog_res w;
|
||||
|
@ -1493,12 +1427,6 @@ struct hpi_control_cache_microphone {
|
|||
char temp_padding[6];
|
||||
};
|
||||
|
||||
struct hpi_control_cache_generic {
|
||||
struct hpi_control_cache_info i;
|
||||
u32 dw1;
|
||||
u32 dw2;
|
||||
};
|
||||
|
||||
struct hpi_control_cache_single {
|
||||
union {
|
||||
struct hpi_control_cache_info i;
|
||||
|
@ -1514,7 +1442,6 @@ struct hpi_control_cache_single {
|
|||
struct hpi_control_cache_silencedetector silence;
|
||||
struct hpi_control_cache_sampleclock clk;
|
||||
struct hpi_control_cache_microphone microphone;
|
||||
struct hpi_control_cache_generic generic;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
|
|||
}
|
||||
|
||||
if (phr->function != phm->function) {
|
||||
HPI_DEBUG_LOG(ERROR, "header type %d invalid\n",
|
||||
HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
|
||||
phr->function);
|
||||
return HPI_ERROR_INVALID_RESPONSE;
|
||||
}
|
||||
|
@ -315,8 +315,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
|
|||
short found = 1;
|
||||
struct hpi_control_cache_info *pI;
|
||||
struct hpi_control_cache_single *pC;
|
||||
struct hpi_control_cache_pad *p_pad;
|
||||
|
||||
size_t response_size;
|
||||
if (!find_control(phm->obj_index, p_cache, &pI)) {
|
||||
HPI_DEBUG_LOG(VERBOSE,
|
||||
"HPICMN find_control() failed for adap %d\n",
|
||||
|
@ -326,11 +325,15 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
|
|||
|
||||
phr->error = 0;
|
||||
|
||||
/* set the default response size */
|
||||
response_size =
|
||||
sizeof(struct hpi_response_header) +
|
||||
sizeof(struct hpi_control_res);
|
||||
|
||||
/* pC is the default cached control strucure. May be cast to
|
||||
something else in the following switch statement.
|
||||
*/
|
||||
pC = (struct hpi_control_cache_single *)pI;
|
||||
p_pad = (struct hpi_control_cache_pad *)pI;
|
||||
|
||||
switch (pI->control_type) {
|
||||
|
||||
|
@ -529,9 +532,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
|
|||
pI->control_index, pI->control_type, phm->u.c.attribute);
|
||||
|
||||
if (found)
|
||||
phr->size =
|
||||
sizeof(struct hpi_response_header) +
|
||||
sizeof(struct hpi_control_res);
|
||||
phr->size = (u16)response_size;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
@ -682,7 +683,7 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
|
|||
void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
|
||||
{
|
||||
switch (phm->type) {
|
||||
case HPI_TYPE_MESSAGE:
|
||||
case HPI_TYPE_REQUEST:
|
||||
switch (phm->object) {
|
||||
case HPI_OBJ_SUBSYSTEM:
|
||||
subsys_message(phm, phr);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/***********************************************************************/
|
||||
/*!
|
||||
/**
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
|
||||
Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -18,90 +18,59 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
\file
|
||||
Functions for reading DSP code to load into DSP
|
||||
|
||||
(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using
|
||||
Functions for reading DSP code using
|
||||
hotplug firmware loader from individual dsp code files
|
||||
|
||||
If neither of the above is defined, code is read from linked arrays.
|
||||
DSPCODE_ARRAY is defined.
|
||||
|
||||
HPI_INCLUDE_**** must be defined
|
||||
and the appropriate hzz?????.c or hex?????.c linked in
|
||||
|
||||
*/
|
||||
*/
|
||||
/***********************************************************************/
|
||||
#define SOURCEFILE_NAME "hpidspcd.c"
|
||||
#include "hpidspcd.h"
|
||||
#include "hpidebug.h"
|
||||
|
||||
/**
|
||||
Header structure for binary dsp code file (see asidsp.doc)
|
||||
This structure must match that used in s2bin.c for generation of asidsp.bin
|
||||
*/
|
||||
|
||||
#ifndef DISABLE_PRAGMA_PACK1
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct code_header {
|
||||
u32 size;
|
||||
char type[4];
|
||||
u32 adapter;
|
||||
u32 version;
|
||||
u32 crc;
|
||||
struct dsp_code_private {
|
||||
/** Firmware descriptor */
|
||||
const struct firmware *firmware;
|
||||
struct pci_dev *dev;
|
||||
};
|
||||
|
||||
#ifndef DISABLE_PRAGMA_PACK1
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
|
||||
HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
|
||||
|
||||
/***********************************************************************/
|
||||
#include <linux/pci.h>
|
||||
/*-------------------------------------------------------------------*/
|
||||
short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
|
||||
u32 *pos_error_code)
|
||||
short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
|
||||
u32 *os_error_code)
|
||||
{
|
||||
const struct firmware *ps_firmware = ps_dsp_code->ps_firmware;
|
||||
const struct firmware *firmware;
|
||||
struct pci_dev *dev = os_data;
|
||||
struct code_header header;
|
||||
char fw_name[20];
|
||||
int err;
|
||||
|
||||
sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
|
||||
|
||||
err = request_firmware(&ps_firmware, fw_name,
|
||||
&ps_dsp_code->ps_dev->dev);
|
||||
err = request_firmware(&firmware, fw_name, &dev->dev);
|
||||
|
||||
if (err != 0) {
|
||||
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
|
||||
if (err || !firmware) {
|
||||
dev_printk(KERN_ERR, &dev->dev,
|
||||
"%d, request_firmware failed for %s\n", err,
|
||||
fw_name);
|
||||
goto error1;
|
||||
}
|
||||
if (ps_firmware->size < sizeof(header)) {
|
||||
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
|
||||
"Header size too small %s\n", fw_name);
|
||||
if (firmware->size < sizeof(header)) {
|
||||
dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n",
|
||||
fw_name);
|
||||
goto error2;
|
||||
}
|
||||
memcpy(&header, ps_firmware->data, sizeof(header));
|
||||
if (header.adapter != adapter) {
|
||||
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
|
||||
"Adapter type incorrect %4x != %4x\n", header.adapter,
|
||||
adapter);
|
||||
goto error2;
|
||||
}
|
||||
if (header.size != ps_firmware->size) {
|
||||
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
|
||||
"Code size wrong %d != %ld\n", header.size,
|
||||
(unsigned long)ps_firmware->size);
|
||||
memcpy(&header, firmware->data, sizeof(header));
|
||||
|
||||
if ((header.type != 0x45444F43) || /* "CODE" */
|
||||
(header.adapter != adapter)
|
||||
|| (header.size != firmware->size)) {
|
||||
dev_printk(KERN_ERR, &dev->dev, "Invalid firmware file\n");
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if (header.version / 100 != HPI_VER_DECIMAL / 100) {
|
||||
dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
|
||||
if ((header.version / 100 & ~1) != (HPI_VER_DECIMAL / 100 & ~1)) {
|
||||
dev_printk(KERN_ERR, &dev->dev,
|
||||
"Incompatible firmware version "
|
||||
"DSP image %d != Driver %d\n", header.version,
|
||||
HPI_VER_DECIMAL);
|
||||
|
@ -109,67 +78,70 @@ short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
|
|||
}
|
||||
|
||||
if (header.version != HPI_VER_DECIMAL) {
|
||||
dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev,
|
||||
dev_printk(KERN_WARNING, &dev->dev,
|
||||
"Firmware: release version mismatch DSP image %d != Driver %d\n",
|
||||
header.version, HPI_VER_DECIMAL);
|
||||
}
|
||||
|
||||
HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
|
||||
ps_dsp_code->ps_firmware = ps_firmware;
|
||||
ps_dsp_code->block_length = header.size / sizeof(u32);
|
||||
ps_dsp_code->word_count = sizeof(header) / sizeof(u32);
|
||||
ps_dsp_code->version = header.version;
|
||||
ps_dsp_code->crc = header.crc;
|
||||
dsp_code->pvt = kmalloc(sizeof(*dsp_code->pvt), GFP_KERNEL);
|
||||
if (!dsp_code->pvt)
|
||||
return HPI_ERROR_MEMORY_ALLOC;
|
||||
|
||||
dsp_code->pvt->dev = dev;
|
||||
dsp_code->pvt->firmware = firmware;
|
||||
dsp_code->header = header;
|
||||
dsp_code->block_length = header.size / sizeof(u32);
|
||||
dsp_code->word_count = sizeof(header) / sizeof(u32);
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
release_firmware(ps_firmware);
|
||||
release_firmware(firmware);
|
||||
error1:
|
||||
ps_dsp_code->ps_firmware = NULL;
|
||||
ps_dsp_code->block_length = 0;
|
||||
dsp_code->block_length = 0;
|
||||
return HPI_ERROR_DSP_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
void hpi_dsp_code_close(struct dsp_code *ps_dsp_code)
|
||||
void hpi_dsp_code_close(struct dsp_code *dsp_code)
|
||||
{
|
||||
if (ps_dsp_code->ps_firmware != NULL) {
|
||||
if (dsp_code->pvt->firmware) {
|
||||
HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
|
||||
release_firmware(ps_dsp_code->ps_firmware);
|
||||
ps_dsp_code->ps_firmware = NULL;
|
||||
release_firmware(dsp_code->pvt->firmware);
|
||||
dsp_code->pvt->firmware = NULL;
|
||||
}
|
||||
kfree(dsp_code->pvt);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code)
|
||||
void hpi_dsp_code_rewind(struct dsp_code *dsp_code)
|
||||
{
|
||||
/* Go back to start of data, after header */
|
||||
ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
|
||||
dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword)
|
||||
short hpi_dsp_code_read_word(struct dsp_code *dsp_code, u32 *pword)
|
||||
{
|
||||
if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length)
|
||||
if (dsp_code->word_count + 1 > dsp_code->block_length)
|
||||
return HPI_ERROR_DSP_FILE_FORMAT;
|
||||
|
||||
*pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code->
|
||||
*pword = ((u32 *)(dsp_code->pvt->firmware->data))[dsp_code->
|
||||
word_count];
|
||||
ps_dsp_code->word_count++;
|
||||
dsp_code->word_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
short hpi_dsp_code_read_block(size_t words_requested,
|
||||
struct dsp_code *ps_dsp_code, u32 **ppblock)
|
||||
struct dsp_code *dsp_code, u32 **ppblock)
|
||||
{
|
||||
if (ps_dsp_code->word_count + words_requested >
|
||||
ps_dsp_code->block_length)
|
||||
if (dsp_code->word_count + words_requested > dsp_code->block_length)
|
||||
return HPI_ERROR_DSP_FILE_FORMAT;
|
||||
|
||||
*ppblock =
|
||||
((u32 *)(ps_dsp_code->ps_firmware->data)) +
|
||||
ps_dsp_code->word_count;
|
||||
ps_dsp_code->word_count += words_requested;
|
||||
((u32 *)(dsp_code->pvt->firmware->data)) +
|
||||
dsp_code->word_count;
|
||||
dsp_code->word_count += words_requested;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
|
||||
Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -20,19 +20,6 @@
|
|||
\file
|
||||
Functions for reading DSP code to load into DSP
|
||||
|
||||
hpi_dspcode_defines HPI DSP code loading method
|
||||
Define exactly one of these to select how the DSP code is supplied to
|
||||
the adapter.
|
||||
|
||||
End users writing applications that use the HPI interface do not have to
|
||||
use any of the below defines; they are only necessary for building drivers
|
||||
|
||||
HPI_DSPCODE_FILE:
|
||||
DSP code is supplied as a file that is opened and read from by the driver.
|
||||
|
||||
HPI_DSPCODE_FIRMWARE:
|
||||
DSP code is read using the hotplug firmware loader module.
|
||||
Only valid when compiling the HPI kernel driver under Linux.
|
||||
*/
|
||||
/***********************************************************************/
|
||||
#ifndef _HPIDSPCD_H_
|
||||
|
@ -40,37 +27,56 @@ DSP code is read using the hotplug firmware loader module.
|
|||
|
||||
#include "hpi_internal.h"
|
||||
|
||||
#ifndef DISABLE_PRAGMA_PACK1
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
/** Code header version is decimal encoded e.g. 4.06.10 is 40601 */
|
||||
#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
|
||||
HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
|
||||
|
||||
/** Header structure for dsp firmware file
|
||||
This structure must match that used in s2bin.c for generation of asidsp.bin
|
||||
*/
|
||||
/*#ifndef DISABLE_PRAGMA_PACK1 */
|
||||
/*#pragma pack(push, 1) */
|
||||
/*#endif */
|
||||
struct code_header {
|
||||
/** Size in bytes including header */
|
||||
u32 size;
|
||||
/** File type tag "CODE" == 0x45444F43 */
|
||||
u32 type;
|
||||
/** Adapter model number */
|
||||
u32 adapter;
|
||||
/** Firmware version*/
|
||||
u32 version;
|
||||
/** Data checksum */
|
||||
u32 checksum;
|
||||
};
|
||||
/*#ifndef DISABLE_PRAGMA_PACK1 */
|
||||
/*#pragma pack(pop) */
|
||||
/*#endif */
|
||||
|
||||
/*? Don't need the pragmas? */
|
||||
compile_time_assert((sizeof(struct code_header) == 20), code_header_size);
|
||||
|
||||
/** Descriptor for dspcode from firmware loader */
|
||||
struct dsp_code {
|
||||
/** Firmware descriptor */
|
||||
const struct firmware *ps_firmware;
|
||||
struct pci_dev *ps_dev;
|
||||
/** copy of file header */
|
||||
struct code_header header;
|
||||
/** Expected number of words in the whole dsp code,INCL header */
|
||||
long int block_length;
|
||||
u32 block_length;
|
||||
/** Number of words read so far */
|
||||
long int word_count;
|
||||
/** Version read from dsp code file */
|
||||
u32 version;
|
||||
/** CRC read from dsp code file */
|
||||
u32 crc;
|
||||
u32 word_count;
|
||||
|
||||
/** internal state of DSP code reader */
|
||||
struct dsp_code_private *pvt;
|
||||
};
|
||||
|
||||
#ifndef DISABLE_PRAGMA_PACK1
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
/** Prepare *psDspCode to refer to the requuested adapter.
|
||||
Searches the file, or selects the appropriate linked array
|
||||
/** Prepare *psDspCode to refer to the requested adapter's firmware.
|
||||
Code file name is obtained from HpiOs_GetDspCodePath
|
||||
|
||||
\return 0 for success, or error code if requested code is not available
|
||||
*/
|
||||
short hpi_dsp_code_open(
|
||||
/** Code identifier, usually adapter family */
|
||||
u32 adapter,
|
||||
u32 adapter, void *pci_dev,
|
||||
/** Pointer to DSP code control structure */
|
||||
struct dsp_code *ps_dsp_code,
|
||||
/** Pointer to dword to receive OS specific error code */
|
||||
|
|
|
@ -1663,68 +1663,64 @@ u16 hpi_channel_mode_get(u32 h_control, u16 *mode)
|
|||
u16 hpi_cobranet_hmi_write(u32 h_control, u32 hmi_address, u32 byte_count,
|
||||
u8 *pb_data)
|
||||
{
|
||||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
struct hpi_msg_cobranet_hmiwrite hm;
|
||||
struct hpi_response_header hr;
|
||||
|
||||
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
|
||||
HPI_CONTROL_SET_STATE);
|
||||
if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
|
||||
hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr, sizeof(hr),
|
||||
HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
|
||||
|
||||
if (hpi_handle_indexes(h_control, &hm.h.adapter_index,
|
||||
&hm.h.obj_index))
|
||||
return HPI_ERROR_INVALID_HANDLE;
|
||||
|
||||
hm.u.cx.u.cobranet_data.byte_count = byte_count;
|
||||
hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
|
||||
if (byte_count > sizeof(hm.bytes))
|
||||
return HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
|
||||
|
||||
if (byte_count <= 8) {
|
||||
memcpy(hm.u.cx.u.cobranet_data.data, pb_data, byte_count);
|
||||
hm.u.cx.attribute = HPI_COBRANET_SET;
|
||||
} else {
|
||||
hm.u.cx.u.cobranet_bigdata.pb_data = pb_data;
|
||||
hm.u.cx.attribute = HPI_COBRANET_SET_DATA;
|
||||
}
|
||||
|
||||
hpi_send_recv(&hm, &hr);
|
||||
hm.p.attribute = HPI_COBRANET_SET;
|
||||
hm.p.byte_count = byte_count;
|
||||
hm.p.hmi_address = hmi_address;
|
||||
memcpy(hm.bytes, pb_data, byte_count);
|
||||
hm.h.size = (u16)(sizeof(hm.h) + sizeof(hm.p) + byte_count);
|
||||
|
||||
hpi_send_recvV1(&hm.h, &hr);
|
||||
return hr.error;
|
||||
}
|
||||
|
||||
u16 hpi_cobranet_hmi_read(u32 h_control, u32 hmi_address, u32 max_byte_count,
|
||||
u32 *pbyte_count, u8 *pb_data)
|
||||
{
|
||||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
struct hpi_msg_cobranet_hmiread hm;
|
||||
struct hpi_res_cobranet_hmiread hr;
|
||||
|
||||
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
|
||||
HPI_CONTROL_GET_STATE);
|
||||
if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
|
||||
hpi_init_message_responseV1(&hm.h, sizeof(hm), &hr.h, sizeof(hr),
|
||||
HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE);
|
||||
|
||||
if (hpi_handle_indexes(h_control, &hm.h.adapter_index,
|
||||
&hm.h.obj_index))
|
||||
return HPI_ERROR_INVALID_HANDLE;
|
||||
|
||||
hm.u.cx.u.cobranet_data.byte_count = max_byte_count;
|
||||
hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
|
||||
if (max_byte_count > sizeof(hr.bytes))
|
||||
return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
|
||||
|
||||
if (max_byte_count <= 8) {
|
||||
hm.u.cx.attribute = HPI_COBRANET_GET;
|
||||
} else {
|
||||
hm.u.cx.u.cobranet_bigdata.pb_data = pb_data;
|
||||
hm.u.cx.attribute = HPI_COBRANET_GET_DATA;
|
||||
}
|
||||
hm.p.attribute = HPI_COBRANET_GET;
|
||||
hm.p.byte_count = max_byte_count;
|
||||
hm.p.hmi_address = hmi_address;
|
||||
|
||||
hpi_send_recv(&hm, &hr);
|
||||
if (!hr.error && pb_data) {
|
||||
hpi_send_recvV1(&hm.h, &hr.h);
|
||||
|
||||
*pbyte_count = hr.u.cx.u.cobranet_data.byte_count;
|
||||
if (!hr.h.error && pb_data) {
|
||||
if (hr.byte_count > sizeof(hr.bytes))
|
||||
|
||||
if (*pbyte_count < max_byte_count)
|
||||
return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
|
||||
|
||||
*pbyte_count = hr.byte_count;
|
||||
|
||||
if (hr.byte_count < max_byte_count)
|
||||
max_byte_count = *pbyte_count;
|
||||
|
||||
if (hm.u.cx.attribute == HPI_COBRANET_GET) {
|
||||
memcpy(pb_data, hr.u.cx.u.cobranet_data.data,
|
||||
max_byte_count);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
memcpy(pb_data, hr.bytes, max_byte_count);
|
||||
}
|
||||
return hr.error;
|
||||
return hr.h.error;
|
||||
}
|
||||
|
||||
u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus,
|
||||
|
@ -1733,23 +1729,23 @@ u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus,
|
|||
struct hpi_message hm;
|
||||
struct hpi_response hr;
|
||||
|
||||
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
|
||||
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
|
||||
HPI_CONTROL_GET_STATE);
|
||||
if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
|
||||
return HPI_ERROR_INVALID_HANDLE;
|
||||
|
||||
hm.u.cx.attribute = HPI_COBRANET_GET_STATUS;
|
||||
hm.u.c.attribute = HPI_COBRANET_GET_STATUS;
|
||||
|
||||
hpi_send_recv(&hm, &hr);
|
||||
if (!hr.error) {
|
||||
if (pstatus)
|
||||
*pstatus = hr.u.cx.u.cobranet_status.status;
|
||||
*pstatus = hr.u.cu.cobranet.status.status;
|
||||
if (preadable_size)
|
||||
*preadable_size =
|
||||
hr.u.cx.u.cobranet_status.readable_size;
|
||||
hr.u.cu.cobranet.status.readable_size;
|
||||
if (pwriteable_size)
|
||||
*pwriteable_size =
|
||||
hr.u.cx.u.cobranet_status.writeable_size;
|
||||
hr.u.cu.cobranet.status.writeable_size;
|
||||
}
|
||||
return hr.error;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ static void hpi_init_message(struct hpi_message *phm, u16 object,
|
|||
if (gwSSX2_bypass)
|
||||
phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE;
|
||||
else
|
||||
phm->type = HPI_TYPE_MESSAGE;
|
||||
phm->type = HPI_TYPE_REQUEST;
|
||||
phm->object = object;
|
||||
phm->function = function;
|
||||
phm->version = 0;
|
||||
|
@ -89,7 +89,7 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
|
|||
memset(phm, 0, sizeof(*phm));
|
||||
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) {
|
||||
phm->size = size;
|
||||
phm->type = HPI_TYPE_MESSAGE;
|
||||
phm->type = HPI_TYPE_REQUEST;
|
||||
phm->object = object;
|
||||
phm->function = function;
|
||||
phm->version = 1;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Extended Message Function With Response Cacheing
|
||||
Extended Message Function With Response Caching
|
||||
|
||||
(C) Copyright AudioScience Inc. 2002
|
||||
*****************************************************************************/
|
||||
|
@ -186,7 +186,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
|
|||
/* Initialize this module's internal state */
|
||||
hpios_msgxlock_init(&msgx_lock);
|
||||
memset(&hpi_entry_points, 0, sizeof(hpi_entry_points));
|
||||
hpios_locked_mem_init();
|
||||
/* Init subsys_findadapters response to no-adapters */
|
||||
HPIMSGX__reset(HPIMSGX_ALLADAPTERS);
|
||||
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
|
||||
|
@ -197,7 +196,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
|
|||
case HPI_SUBSYS_DRIVER_UNLOAD:
|
||||
HPI_COMMON(phm, phr);
|
||||
HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner);
|
||||
hpios_locked_mem_free_all();
|
||||
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
|
||||
HPI_SUBSYS_DRIVER_UNLOAD, 0);
|
||||
return;
|
||||
|
@ -315,7 +313,7 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
|
|||
{
|
||||
HPI_DEBUG_MESSAGE(DEBUG, phm);
|
||||
|
||||
if (phm->type != HPI_TYPE_MESSAGE) {
|
||||
if (phm->type != HPI_TYPE_REQUEST) {
|
||||
hpi_init_response(phr, phm->object, phm->function,
|
||||
HPI_ERROR_INVALID_TYPE);
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*******************************************************************************
|
||||
|
||||
AudioScience HPI driver
|
||||
Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
|
||||
Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -157,11 +157,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (hm->h.adapter_index >= HPI_MAX_ADAPTERS) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (hm->h.function) {
|
||||
case HPI_SUBSYS_CREATE_ADAPTER:
|
||||
case HPI_ADAPTER_DELETE:
|
||||
|
@ -187,7 +182,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
/* -1=no data 0=read from user mem, 1=write to user mem */
|
||||
int wrflag = -1;
|
||||
u32 adapter = hm->h.adapter_index;
|
||||
pa = &adapters[adapter];
|
||||
|
||||
if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
|
||||
hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
|
||||
|
@ -203,6 +197,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
goto out;
|
||||
}
|
||||
|
||||
pa = &adapters[adapter];
|
||||
|
||||
if (mutex_lock_interruptible(&adapters[adapter].mutex)) {
|
||||
err = -EINTR;
|
||||
goto out;
|
||||
|
|
|
@ -39,10 +39,6 @@ void hpios_delay_micro_seconds(u32 num_micro_sec)
|
|||
|
||||
}
|
||||
|
||||
void hpios_locked_mem_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/** Allocated an area of locked memory for bus master DMA operations.
|
||||
|
||||
On error, return -ENOMEM, and *pMemArea.size = 0
|
||||
|
@ -85,7 +81,3 @@ u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void hpios_locked_mem_free_all(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ HPI Operating System Specific macros for Linux Kernel driver
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define HPI_NO_OS_FILE_OPS
|
||||
|
||||
|
|
|
@ -1624,7 +1624,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
|
||||
card->shortname, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_atiixp_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1701,7 +1701,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ATI IXP AC97 controller",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_atiixp_ids,
|
||||
.probe = snd_atiixp_probe,
|
||||
.remove = __devexit_p(snd_atiixp_remove),
|
||||
|
|
|
@ -1260,7 +1260,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
|
||||
card->shortname, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_atiixp_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1332,7 +1332,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ATI IXP MC97 controller",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_atiixp_ids,
|
||||
.probe = snd_atiixp_probe,
|
||||
.remove = __devexit_p(snd_atiixp_remove),
|
||||
|
|
|
@ -196,7 +196,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
|
|||
}
|
||||
|
||||
if ((err = request_irq(pci->irq, vortex_interrupt,
|
||||
IRQF_SHARED, CARD_NAME_SHORT,
|
||||
IRQF_SHARED, KBUILD_MODNAME,
|
||||
chip)) != 0) {
|
||||
printk(KERN_ERR "cannot grab irq\n");
|
||||
goto irq_out;
|
||||
|
@ -375,7 +375,7 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci)
|
|||
|
||||
// pci_driver definition
|
||||
static struct pci_driver driver = {
|
||||
.name = CARD_NAME_SHORT,
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_vortex_ids,
|
||||
.probe = snd_vortex_probe,
|
||||
.remove = __devexit_p(snd_vortex_remove),
|
||||
|
|
|
@ -171,7 +171,7 @@ MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
|
|||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver driver = {
|
||||
.name = "Emagic Audiowerk 2",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_aw2_ids,
|
||||
.probe = snd_aw2_probe,
|
||||
.remove = __devexit_p(snd_aw2_remove),
|
||||
|
@ -317,7 +317,7 @@ static int __devinit snd_aw2_create(struct snd_card *card,
|
|||
snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
|
||||
|
||||
if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
|
||||
IRQF_SHARED, "Audiowerk2", chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq);
|
||||
|
||||
iounmap(chip->iobase_virt);
|
||||
|
|
|
@ -2559,7 +2559,7 @@ snd_azf3328_create(struct snd_card *card,
|
|||
codec_setup->name = "I2S_OUT";
|
||||
|
||||
if (request_irq(pci->irq, snd_azf3328_interrupt,
|
||||
IRQF_SHARED, card->shortname, chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
err = -EBUSY;
|
||||
goto out_err;
|
||||
|
@ -2860,7 +2860,7 @@ snd_azf3328_resume(struct pci_dev *pci)
|
|||
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "AZF3328",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_azf3328_ids,
|
||||
.probe = snd_azf3328_probe,
|
||||
.remove = __devexit_p(snd_azf3328_remove),
|
||||
|
|
|
@ -760,7 +760,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card,
|
|||
snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
|
||||
|
||||
err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
|
||||
"Bt87x audio", chip);
|
||||
KBUILD_MODNAME, chip);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
|
||||
goto fail;
|
||||
|
@ -965,7 +965,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
|
|||
};
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "Bt87x",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_bt87x_ids,
|
||||
.probe = snd_bt87x_probe,
|
||||
.remove = __devexit_p(snd_bt87x_remove),
|
||||
|
|
|
@ -1666,7 +1666,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_ca0106_interrupt,
|
||||
IRQF_SHARED, "snd_ca0106", chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
snd_ca0106_free(chip);
|
||||
printk(KERN_ERR "cannot grab irq\n");
|
||||
return -EBUSY;
|
||||
|
@ -1933,7 +1933,7 @@ MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
|
|||
|
||||
// pci_driver definition
|
||||
static struct pci_driver driver = {
|
||||
.name = "CA0106",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_ca0106_ids,
|
||||
.probe = snd_ca0106_probe,
|
||||
.remove = __devexit_p(snd_ca0106_remove),
|
||||
|
|
|
@ -3053,7 +3053,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
|
|||
cm->iobase = pci_resource_start(pci, 0);
|
||||
|
||||
if (request_irq(pci->irq, snd_cmipci_interrupt,
|
||||
IRQF_SHARED, card->driver, cm)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, cm)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_cmipci_free(cm);
|
||||
return -EBUSY;
|
||||
|
@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci)
|
|||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "C-Media PCI",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_cmipci_ids,
|
||||
.probe = snd_cmipci_probe,
|
||||
.remove = __devexit_p(snd_cmipci_remove),
|
||||
|
|
|
@ -1382,7 +1382,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
|
||||
"CS4281", chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_cs4281_free(chip);
|
||||
return -ENOMEM;
|
||||
|
@ -2085,7 +2085,7 @@ static int cs4281_resume(struct pci_dev *pci)
|
|||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "CS4281",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_cs4281_ids,
|
||||
.probe = snd_cs4281_probe,
|
||||
.remove = __devexit_p(snd_cs4281_remove),
|
||||
|
|
|
@ -162,7 +162,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "Sound Fusion CS46xx",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_cs46xx_ids,
|
||||
.probe = snd_card_cs46xx_probe,
|
||||
.remove = __devexit_p(snd_card_cs46xx_remove),
|
||||
|
|
|
@ -3835,7 +3835,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED,
|
||||
"CS46XX", chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_cs46xx_free(chip);
|
||||
return -EBUSY;
|
||||
|
|
|
@ -285,7 +285,7 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "CS5530_Audio",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_cs5530_ids,
|
||||
.probe = snd_cs5530_probe,
|
||||
.remove = __devexit_p(snd_cs5530_remove),
|
||||
|
|
|
@ -311,7 +311,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card,
|
|||
cs5535au->port = pci_resource_start(pci, 0);
|
||||
|
||||
if (request_irq(pci->irq, snd_cs5535audio_interrupt,
|
||||
IRQF_SHARED, "CS5535 Audio", cs5535au)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, cs5535au)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
err = -EBUSY;
|
||||
goto sndfail;
|
||||
|
@ -395,7 +395,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_cs5535audio_ids,
|
||||
.probe = snd_cs5535audio_probe,
|
||||
.remove = __devexit_p(snd_cs5535audio_remove),
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
/* GPIO Registers */
|
||||
#define GPIO_DATA 0x1B7020
|
||||
#define GPIO_CTRL 0x1B7024
|
||||
#define GPIO_EXT_DATA 0x1B70A0
|
||||
|
||||
/* Virtual memory registers */
|
||||
#define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "ctatc.h"
|
||||
#include "ctpcm.h"
|
||||
#include "ctmixer.h"
|
||||
#include "cthardware.h"
|
||||
#include "ctsrc.h"
|
||||
#include "ctamixer.h"
|
||||
#include "ctdaio.h"
|
||||
|
@ -30,7 +29,6 @@
|
|||
#include <sound/asoundef.h>
|
||||
|
||||
#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */
|
||||
#define DAIONUM 7
|
||||
#define MAX_MULTI_CHN 8
|
||||
|
||||
#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
|
||||
|
@ -53,6 +51,8 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
|
|||
static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
|
||||
"SB0760", CTSB0760),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
|
||||
"SB1270", CTSB1270),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
|
||||
"SB0880", CTSB0880),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
|
||||
|
@ -75,6 +75,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
|
|||
[CTSB0760] = "SB076x",
|
||||
[CTHENDRIX] = "Hendrix",
|
||||
[CTSB0880] = "SB0880",
|
||||
[CTSB1270] = "SB1270",
|
||||
[CT20K2_UNKNOWN] = "Unknown",
|
||||
};
|
||||
|
||||
|
@ -459,12 +460,12 @@ static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
|
|||
apcm->substream->runtime->rate);
|
||||
*n_srcc = 0;
|
||||
|
||||
if (1 == atc->msr) {
|
||||
if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
|
||||
*n_srcc = apcm->substream->runtime->channels;
|
||||
conf[0].pitch = pitch;
|
||||
conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
|
||||
conf[0].vo = 1;
|
||||
} else if (2 == atc->msr) {
|
||||
} else if (2 <= atc->msr) {
|
||||
if (0x8000000 < pitch) {
|
||||
/* Need two-stage SRCs, SRCIMPs and
|
||||
* AMIXERs for converting format */
|
||||
|
@ -970,11 +971,39 @@ static int atc_select_mic_in(struct ct_atc *atc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atc_have_digit_io_switch(struct ct_atc *atc)
|
||||
static struct capabilities atc_capabilities(struct ct_atc *atc)
|
||||
{
|
||||
struct hw *hw = atc->hw;
|
||||
|
||||
return hw->have_digit_io_switch(hw);
|
||||
return hw->capabilities(hw);
|
||||
}
|
||||
|
||||
static int atc_output_switch_get(struct ct_atc *atc)
|
||||
{
|
||||
struct hw *hw = atc->hw;
|
||||
|
||||
return hw->output_switch_get(hw);
|
||||
}
|
||||
|
||||
static int atc_output_switch_put(struct ct_atc *atc, int position)
|
||||
{
|
||||
struct hw *hw = atc->hw;
|
||||
|
||||
return hw->output_switch_put(hw, position);
|
||||
}
|
||||
|
||||
static int atc_mic_source_switch_get(struct ct_atc *atc)
|
||||
{
|
||||
struct hw *hw = atc->hw;
|
||||
|
||||
return hw->mic_source_switch_get(hw);
|
||||
}
|
||||
|
||||
static int atc_mic_source_switch_put(struct ct_atc *atc, int position)
|
||||
{
|
||||
struct hw *hw = atc->hw;
|
||||
|
||||
return hw->mic_source_switch_put(hw, position);
|
||||
}
|
||||
|
||||
static int atc_select_digit_io(struct ct_atc *atc)
|
||||
|
@ -1045,6 +1074,11 @@ static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
|
|||
return atc_daio_unmute(atc, state, LINEIM);
|
||||
}
|
||||
|
||||
static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
|
||||
{
|
||||
return atc_daio_unmute(atc, state, MIC);
|
||||
}
|
||||
|
||||
static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
|
||||
{
|
||||
return atc_daio_unmute(atc, state, SPDIFOO);
|
||||
|
@ -1331,17 +1365,20 @@ static int atc_get_resources(struct ct_atc *atc)
|
|||
struct srcimp_mgr *srcimp_mgr;
|
||||
struct sum_desc sum_dsc = {0};
|
||||
struct sum_mgr *sum_mgr;
|
||||
int err, i;
|
||||
int err, i, num_srcs, num_daios;
|
||||
|
||||
atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
|
||||
num_daios = ((atc->model == CTSB1270) ? 8 : 7);
|
||||
num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
|
||||
|
||||
atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL);
|
||||
if (!atc->daios)
|
||||
return -ENOMEM;
|
||||
|
||||
atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
|
||||
atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
|
||||
if (!atc->srcs)
|
||||
return -ENOMEM;
|
||||
|
||||
atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
|
||||
atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
|
||||
if (!atc->srcimps)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1351,8 +1388,9 @@ static int atc_get_resources(struct ct_atc *atc)
|
|||
|
||||
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
|
||||
da_desc.msr = atc->msr;
|
||||
for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
|
||||
da_desc.type = i;
|
||||
for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
|
||||
da_desc.type = (atc->model != CTSB073X) ? i :
|
||||
((i == SPDIFIO) ? SPDIFI1 : i);
|
||||
err = daio_mgr->get_daio(daio_mgr, &da_desc,
|
||||
(struct daio **)&atc->daios[i]);
|
||||
if (err) {
|
||||
|
@ -1362,23 +1400,12 @@ static int atc_get_resources(struct ct_atc *atc)
|
|||
}
|
||||
atc->n_daio++;
|
||||
}
|
||||
if (atc->model == CTSB073X)
|
||||
da_desc.type = SPDIFI1;
|
||||
else
|
||||
da_desc.type = SPDIFIO;
|
||||
err = daio_mgr->get_daio(daio_mgr, &da_desc,
|
||||
(struct daio **)&atc->daios[i]);
|
||||
if (err) {
|
||||
printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
|
||||
return err;
|
||||
}
|
||||
atc->n_daio++;
|
||||
|
||||
src_mgr = atc->rsc_mgrs[SRC];
|
||||
src_dsc.multi = 1;
|
||||
src_dsc.msr = atc->msr;
|
||||
src_dsc.mode = ARCRW;
|
||||
for (i = 0, atc->n_src = 0; i < (2*2); i++) {
|
||||
for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
|
||||
err = src_mgr->get_src(src_mgr, &src_dsc,
|
||||
(struct src **)&atc->srcs[i]);
|
||||
if (err)
|
||||
|
@ -1388,8 +1415,8 @@ static int atc_get_resources(struct ct_atc *atc)
|
|||
}
|
||||
|
||||
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
|
||||
srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
|
||||
for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
|
||||
srcimp_dsc.msr = 8;
|
||||
for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
|
||||
err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
|
||||
(struct srcimp **)&atc->srcimps[i]);
|
||||
if (err)
|
||||
|
@ -1397,15 +1424,6 @@ static int atc_get_resources(struct ct_atc *atc)
|
|||
|
||||
atc->n_srcimp++;
|
||||
}
|
||||
srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
|
||||
for (i = 0; i < (2*1); i++) {
|
||||
err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
|
||||
(struct srcimp **)&atc->srcimps[2*1+i]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
atc->n_srcimp++;
|
||||
}
|
||||
|
||||
sum_mgr = atc->rsc_mgrs[SUM];
|
||||
sum_dsc.msr = atc->msr;
|
||||
|
@ -1488,6 +1506,18 @@ static void atc_connect_resources(struct ct_atc *atc)
|
|||
src = atc->srcs[3];
|
||||
mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
|
||||
|
||||
if (atc->model == CTSB1270) {
|
||||
/* Titanium HD has a dedicated ADC for the Mic. */
|
||||
dai = container_of(atc->daios[MIC], struct dai, daio);
|
||||
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
|
||||
(struct src **)&atc->srcs[4],
|
||||
(struct srcimp **)&atc->srcimps[4]);
|
||||
src = atc->srcs[4];
|
||||
mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
|
||||
src = atc->srcs[5];
|
||||
mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
|
||||
}
|
||||
|
||||
dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
|
||||
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
|
||||
(struct src **)&atc->srcs[0],
|
||||
|
@ -1606,12 +1636,17 @@ static struct ct_atc atc_preset __devinitdata = {
|
|||
.line_clfe_unmute = atc_line_clfe_unmute,
|
||||
.line_rear_unmute = atc_line_rear_unmute,
|
||||
.line_in_unmute = atc_line_in_unmute,
|
||||
.mic_unmute = atc_mic_unmute,
|
||||
.spdif_out_unmute = atc_spdif_out_unmute,
|
||||
.spdif_in_unmute = atc_spdif_in_unmute,
|
||||
.spdif_out_get_status = atc_spdif_out_get_status,
|
||||
.spdif_out_set_status = atc_spdif_out_set_status,
|
||||
.spdif_out_passthru = atc_spdif_out_passthru,
|
||||
.have_digit_io_switch = atc_have_digit_io_switch,
|
||||
.capabilities = atc_capabilities,
|
||||
.output_switch_get = atc_output_switch_get,
|
||||
.output_switch_put = atc_output_switch_put,
|
||||
.mic_source_switch_get = atc_mic_source_switch_get,
|
||||
.mic_source_switch_put = atc_mic_source_switch_put,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = atc_suspend,
|
||||
.resume = atc_resume,
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <sound/core.h>
|
||||
|
||||
#include "ctvmem.h"
|
||||
#include "cthardware.h"
|
||||
#include "ctresource.h"
|
||||
|
||||
enum CTALSADEVS { /* Types of alsa devices */
|
||||
|
@ -115,12 +116,17 @@ struct ct_atc {
|
|||
int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
|
||||
int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
|
||||
int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
|
||||
int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
|
||||
int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
|
||||
int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
|
||||
int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
|
||||
int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
|
||||
int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
|
||||
int (*have_digit_io_switch)(struct ct_atc *atc);
|
||||
struct capabilities (*capabilities)(struct ct_atc *atc);
|
||||
int (*output_switch_get)(struct ct_atc *atc);
|
||||
int (*output_switch_put)(struct ct_atc *atc, int position);
|
||||
int (*mic_source_switch_get)(struct ct_atc *atc);
|
||||
int (*mic_source_switch_put)(struct ct_atc *atc, int position);
|
||||
|
||||
/* Don't touch! Used for internal object. */
|
||||
void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
|
||||
|
|
|
@ -22,20 +22,9 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define DAIO_RESOURCE_NUM NUM_DAIOTYP
|
||||
#define DAIO_OUT_MAX SPDIFOO
|
||||
|
||||
union daio_usage {
|
||||
struct {
|
||||
unsigned short lineo1:1;
|
||||
unsigned short lineo2:1;
|
||||
unsigned short lineo3:1;
|
||||
unsigned short lineo4:1;
|
||||
unsigned short spdifoo:1;
|
||||
unsigned short lineim:1;
|
||||
unsigned short spdifio:1;
|
||||
unsigned short spdifi1:1;
|
||||
} bf;
|
||||
struct daio_usage {
|
||||
unsigned short data;
|
||||
};
|
||||
|
||||
|
@ -61,6 +50,7 @@ struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
|
|||
[LINEO3] = {.left = 0x50, .right = 0x51},
|
||||
[LINEO4] = {.left = 0x70, .right = 0x71},
|
||||
[LINEIM] = {.left = 0x45, .right = 0xc5},
|
||||
[MIC] = {.left = 0x55, .right = 0xd5},
|
||||
[SPDIFOO] = {.left = 0x00, .right = 0x01},
|
||||
[SPDIFIO] = {.left = 0x05, .right = 0x85},
|
||||
};
|
||||
|
@ -138,6 +128,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
|
|||
case LINEO3: return 5;
|
||||
case LINEO4: return 6;
|
||||
case LINEIM: return 4;
|
||||
case MIC: return 5;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
default:
|
||||
|
@ -519,17 +510,17 @@ static int dai_rsc_uninit(struct dai *dai)
|
|||
|
||||
static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
|
||||
{
|
||||
if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
|
||||
if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))
|
||||
return -ENOENT;
|
||||
|
||||
((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
|
||||
((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
|
||||
{
|
||||
((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
|
||||
((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -712,7 +703,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
|
|||
if (!daio_mgr)
|
||||
return -ENOMEM;
|
||||
|
||||
err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
|
||||
err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);
|
||||
if (err)
|
||||
goto error1;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ enum DAIOTYP {
|
|||
SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */
|
||||
LINEIM,
|
||||
SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */
|
||||
MIC, /* Dedicated mic on Titanium HD */
|
||||
SPDIFI1, /* S/PDIF In on internal Drive Bay */
|
||||
NUM_DAIOTYP
|
||||
};
|
||||
|
|
|
@ -39,6 +39,7 @@ enum CTCARDS {
|
|||
CT20K2_MODEL_FIRST = CTSB0760,
|
||||
CTHENDRIX,
|
||||
CTSB0880,
|
||||
CTSB1270,
|
||||
CT20K2_UNKNOWN,
|
||||
NUM_CTCARDS /* This should always be the last */
|
||||
};
|
||||
|
@ -60,6 +61,13 @@ struct card_conf {
|
|||
unsigned int msr; /* master sample rate in rsrs */
|
||||
};
|
||||
|
||||
struct capabilities {
|
||||
unsigned int digit_io_switch:1;
|
||||
unsigned int dedicated_mic:1;
|
||||
unsigned int output_switch:1;
|
||||
unsigned int mic_source_switch:1;
|
||||
};
|
||||
|
||||
struct hw {
|
||||
int (*card_init)(struct hw *hw, struct card_conf *info);
|
||||
int (*card_stop)(struct hw *hw);
|
||||
|
@ -70,7 +78,11 @@ struct hw {
|
|||
#endif
|
||||
int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
|
||||
int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
|
||||
int (*have_digit_io_switch)(struct hw *hw);
|
||||
struct capabilities (*capabilities)(struct hw *hw);
|
||||
int (*output_switch_get)(struct hw *hw);
|
||||
int (*output_switch_put)(struct hw *hw, int position);
|
||||
int (*mic_source_switch_get)(struct hw *hw);
|
||||
int (*mic_source_switch_put)(struct hw *hw, int position);
|
||||
|
||||
/* SRC operations */
|
||||
int (*src_rsc_get_ctrl_blk)(void **rblk);
|
||||
|
|
|
@ -1777,10 +1777,17 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
|
|||
return adc_init_SBx(hw, info->input, info->mic20db);
|
||||
}
|
||||
|
||||
static int hw_have_digit_io_switch(struct hw *hw)
|
||||
static struct capabilities hw_capabilities(struct hw *hw)
|
||||
{
|
||||
struct capabilities cap;
|
||||
|
||||
/* SB073x and Vista compatible cards have no digit IO switch */
|
||||
return !(hw->model == CTSB073X || hw->model == CTUAA);
|
||||
cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
|
||||
cap.dedicated_mic = 0;
|
||||
cap.output_switch = 0;
|
||||
cap.mic_source_switch = 0;
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
#define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
||||
|
@ -1933,7 +1940,7 @@ static int hw_card_start(struct hw *hw)
|
|||
|
||||
if (hw->irq < 0) {
|
||||
err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
|
||||
"ctxfi", hw);
|
||||
KBUILD_MODNAME, hw);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
|
||||
goto error2;
|
||||
|
@ -2172,7 +2179,7 @@ static struct hw ct20k1_preset __devinitdata = {
|
|||
.pll_init = hw_pll_init,
|
||||
.is_adc_source_selected = hw_is_adc_input_selected,
|
||||
.select_adc_source = hw_adc_input_select,
|
||||
.have_digit_io_switch = hw_have_digit_io_switch,
|
||||
.capabilities = hw_capabilities,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = hw_suspend,
|
||||
.resume = hw_resume,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @File cthw20k2.c
|
||||
*
|
||||
* @Brief
|
||||
* This file contains the implementation of hardware access methord for 20k2.
|
||||
* This file contains the implementation of hardware access method for 20k2.
|
||||
*
|
||||
* @Author Liu Chun
|
||||
* @Date May 14 2008
|
||||
|
@ -38,6 +38,8 @@ struct hw20k2 {
|
|||
unsigned char dev_id;
|
||||
unsigned char addr_size;
|
||||
unsigned char data_size;
|
||||
|
||||
int mic_source;
|
||||
};
|
||||
|
||||
static u32 hw_read_20kx(struct hw *hw, u32 reg);
|
||||
|
@ -1163,7 +1165,12 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
|
|||
hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
|
||||
hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
|
||||
} else if (2 == info->msr) {
|
||||
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
|
||||
if (hw->model != CTSB1270) {
|
||||
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
|
||||
} else {
|
||||
/* PCM4220 on Titanium HD is different. */
|
||||
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
|
||||
}
|
||||
/* Specify all playing 96khz
|
||||
* EA [0] - Enabled
|
||||
* RTA [4:5] - 96kHz
|
||||
|
@ -1175,6 +1182,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
|
|||
* RTD [28:29] - 96kHz */
|
||||
hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
|
||||
hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
|
||||
} else if ((4 == info->msr) && (hw->model == CTSB1270)) {
|
||||
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
|
||||
hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
|
||||
hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
|
||||
} else {
|
||||
printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
|
||||
return -EINVAL;
|
||||
|
@ -1182,6 +1193,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
|
|||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i <= 3) {
|
||||
/* This comment looks wrong since loop is over 4 */
|
||||
/* channels and emu20k2 supports 4 spdif IOs. */
|
||||
/* 1st 3 channels are SPDIFs (SB0960) */
|
||||
if (i == 3)
|
||||
data = 0x1001001;
|
||||
|
@ -1206,12 +1219,16 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
|
|||
|
||||
hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
|
||||
} else {
|
||||
/* Again, loop is over 4 channels not 5. */
|
||||
/* Next 5 channels are I2S (SB0960) */
|
||||
data = 0x11;
|
||||
hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
|
||||
if (2 == info->msr) {
|
||||
/* Four channels per sample period */
|
||||
data |= 0x1000;
|
||||
} else if (4 == info->msr) {
|
||||
/* FIXME: check this against the chip spec */
|
||||
data |= 0x2000;
|
||||
}
|
||||
hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
|
||||
}
|
||||
|
@ -1299,21 +1316,18 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
|
|||
|
||||
pllenb = 0xB;
|
||||
hw_write_20kx(hw, PLL_ENB, pllenb);
|
||||
pllctl = 0x20D00000;
|
||||
set_field(&pllctl, PLLCTL_FD, 16 - 4);
|
||||
hw_write_20kx(hw, PLL_CTL, pllctl);
|
||||
mdelay(40);
|
||||
pllctl = hw_read_20kx(hw, PLL_CTL);
|
||||
pllctl = 0x20C00000;
|
||||
set_field(&pllctl, PLLCTL_B, 0);
|
||||
if (48000 == rsr) {
|
||||
set_field(&pllctl, PLLCTL_FD, 16 - 2);
|
||||
set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */
|
||||
} else { /* 44100 */
|
||||
set_field(&pllctl, PLLCTL_FD, 147 - 2);
|
||||
set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */
|
||||
}
|
||||
set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4);
|
||||
set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1);
|
||||
hw_write_20kx(hw, PLL_CTL, pllctl);
|
||||
mdelay(40);
|
||||
|
||||
pllctl = hw_read_20kx(hw, PLL_CTL);
|
||||
set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2);
|
||||
hw_write_20kx(hw, PLL_CTL, pllctl);
|
||||
mdelay(40);
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
pllstat = hw_read_20kx(hw, PLL_STAT);
|
||||
if (get_field(pllstat, PLLSTAT_PD))
|
||||
|
@ -1557,7 +1571,7 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
|
|||
|
||||
hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
|
||||
hw20k2_i2c_wait_data_ready(hw);
|
||||
/* Dummy write to trigger the write oprtation */
|
||||
/* Dummy write to trigger the write operation */
|
||||
hw_write_20kx(hw, I2C_IF_WDATA, 0);
|
||||
hw20k2_i2c_wait_data_ready(hw);
|
||||
|
||||
|
@ -1568,6 +1582,30 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hw_dac_stop(struct hw *hw)
|
||||
{
|
||||
u32 data;
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
data &= 0xFFFFFFFD;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
static void hw_dac_start(struct hw *hw)
|
||||
{
|
||||
u32 data;
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
data |= 0x2;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(50);
|
||||
}
|
||||
|
||||
static void hw_dac_reset(struct hw *hw)
|
||||
{
|
||||
hw_dac_stop(hw);
|
||||
hw_dac_start(hw);
|
||||
}
|
||||
|
||||
static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
|
||||
{
|
||||
int err;
|
||||
|
@ -1594,6 +1632,21 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
|
|||
0x00000000 /* Vol Control B4 */
|
||||
};
|
||||
|
||||
if (hw->model == CTSB1270) {
|
||||
hw_dac_stop(hw);
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
data &= ~0x0600;
|
||||
if (1 == info->msr)
|
||||
data |= 0x0000; /* Single Speed Mode 0-50kHz */
|
||||
else if (2 == info->msr)
|
||||
data |= 0x0200; /* Double Speed Mode 50-100kHz */
|
||||
else
|
||||
data |= 0x0600; /* Quad Speed Mode 100-200kHz */
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
hw_dac_start(hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set DAC reset bit as output */
|
||||
data = hw_read_20kx(hw, GPIO_CTRL);
|
||||
data |= 0x02;
|
||||
|
@ -1606,22 +1659,8 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
|
|||
for (i = 0; i < 2; i++) {
|
||||
/* Reset DAC twice just in-case the chip
|
||||
* didn't initialized properly */
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
/* GPIO data bit 1 */
|
||||
data &= 0xFFFFFFFD;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(10);
|
||||
data |= 0x2;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(50);
|
||||
|
||||
/* Reset the 2nd time */
|
||||
data &= 0xFFFFFFFD;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(10);
|
||||
data |= 0x2;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(50);
|
||||
hw_dac_reset(hw);
|
||||
hw_dac_reset(hw);
|
||||
|
||||
if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1))
|
||||
continue;
|
||||
|
@ -1725,7 +1764,11 @@ End:
|
|||
static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
if (hw->model == CTSB1270) {
|
||||
/* Titanium HD has two ADC chips, one for line in and one */
|
||||
/* for MIC. We don't need to switch the ADC input. */
|
||||
return 1;
|
||||
}
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
switch (type) {
|
||||
case ADC_MICIN:
|
||||
|
@ -1742,35 +1785,47 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
|
|||
|
||||
#define MIC_BOOST_0DB 0xCF
|
||||
#define MIC_BOOST_STEPS_PER_DB 2
|
||||
#define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB)
|
||||
|
||||
static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db)
|
||||
{
|
||||
u32 adcmc, gain;
|
||||
|
||||
if (input > 3)
|
||||
input = 3;
|
||||
|
||||
adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
|
||||
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
|
||||
MAKE_WM8775_DATA(adcmc));
|
||||
|
||||
if (gain_in_db < -103)
|
||||
gain_in_db = -103;
|
||||
if (gain_in_db > 24)
|
||||
gain_in_db = 24;
|
||||
|
||||
gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB;
|
||||
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
|
||||
MAKE_WM8775_DATA(gain));
|
||||
/* ...so there should be no need for the following. */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
|
||||
MAKE_WM8775_DATA(gain));
|
||||
}
|
||||
|
||||
static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
switch (type) {
|
||||
case ADC_MICIN:
|
||||
data |= (0x1 << 14);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
|
||||
MAKE_WM8775_DATA(0x101)); /* Mic-in */
|
||||
hw20k2_i2c_write(hw,
|
||||
MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
|
||||
MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
|
||||
hw20k2_i2c_write(hw,
|
||||
MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
|
||||
MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
|
||||
hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */
|
||||
break;
|
||||
case ADC_LINEIN:
|
||||
data &= ~(0x1 << 14);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
|
||||
MAKE_WM8775_DATA(0x102)); /* Line-in */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
|
||||
MAKE_WM8775_DATA(0xCF)); /* No boost */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
|
||||
MAKE_WM8775_DATA(0xCF)); /* No boost */
|
||||
hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1782,7 +1837,7 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
|
|||
static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
|
||||
{
|
||||
int err;
|
||||
u32 mux = 2, data, ctl;
|
||||
u32 data, ctl;
|
||||
|
||||
/* Set ADC reset bit as output */
|
||||
data = hw_read_20kx(hw, GPIO_CTRL);
|
||||
|
@ -1796,19 +1851,42 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* Make ADC in normal operation */
|
||||
/* Reset the ADC (reset is active low). */
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
data &= ~(0x1 << 15);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
|
||||
if (hw->model == CTSB1270) {
|
||||
/* Set up the PCM4220 ADC on Titanium HD */
|
||||
data &= ~0x0C;
|
||||
if (1 == info->msr)
|
||||
data |= 0x00; /* Single Speed Mode 32-50kHz */
|
||||
else if (2 == info->msr)
|
||||
data |= 0x08; /* Double Speed Mode 50-108kHz */
|
||||
else
|
||||
data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
/* Return the ADC to normal operation. */
|
||||
data |= (0x1 << 15);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
mdelay(50);
|
||||
|
||||
/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
|
||||
/* invert bit, interface format to I2S, word length to 24-bit, */
|
||||
/* enable ADC high pass filter. Fixes bug 5323? */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
|
||||
MAKE_WM8775_DATA(0x26));
|
||||
|
||||
/* Set the master mode (256fs) */
|
||||
if (1 == info->msr) {
|
||||
/* slave mode, 128x oversampling 256fs */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
|
||||
MAKE_WM8775_DATA(0x02));
|
||||
} else if (2 == info->msr) {
|
||||
} else if ((2 == info->msr) || (4 == info->msr)) {
|
||||
/* slave mode, 64x oversampling, 256fs */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
|
||||
MAKE_WM8775_DATA(0x0A));
|
||||
} else {
|
||||
|
@ -1818,55 +1896,113 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* Configure GPIO bit 14 change to line-in/mic-in */
|
||||
ctl = hw_read_20kx(hw, GPIO_CTRL);
|
||||
ctl |= 0x1 << 14;
|
||||
hw_write_20kx(hw, GPIO_CTRL, ctl);
|
||||
|
||||
/* Check using Mic-in or Line-in */
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
|
||||
if (mux == 1) {
|
||||
/* Configures GPIO data to select Mic-in */
|
||||
data |= 0x1 << 14;
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
|
||||
MAKE_WM8775_DATA(0x101)); /* Mic-in */
|
||||
hw20k2_i2c_write(hw,
|
||||
MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
|
||||
MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
|
||||
hw20k2_i2c_write(hw,
|
||||
MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
|
||||
MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
|
||||
} else if (mux == 2) {
|
||||
/* Configures GPIO data to select Line-in */
|
||||
data &= ~(0x1 << 14);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
|
||||
/* Setup ADC */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
|
||||
MAKE_WM8775_DATA(0x102)); /* Line-in */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
|
||||
MAKE_WM8775_DATA(0xCF)); /* No boost */
|
||||
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
|
||||
MAKE_WM8775_DATA(0xCF)); /* No boost */
|
||||
if (hw->model != CTSB1270) {
|
||||
/* Configure GPIO bit 14 change to line-in/mic-in */
|
||||
ctl = hw_read_20kx(hw, GPIO_CTRL);
|
||||
ctl |= 0x1 << 14;
|
||||
hw_write_20kx(hw, GPIO_CTRL, ctl);
|
||||
hw_adc_input_select(hw, ADC_LINEIN);
|
||||
} else {
|
||||
printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
hw_wm8775_input_select(hw, 0, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
hw20k2_i2c_uninit(hw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hw_have_digit_io_switch(struct hw *hw)
|
||||
static struct capabilities hw_capabilities(struct hw *hw)
|
||||
{
|
||||
return 0;
|
||||
struct capabilities cap;
|
||||
|
||||
cap.digit_io_switch = 0;
|
||||
cap.dedicated_mic = hw->model == CTSB1270;
|
||||
cap.output_switch = hw->model == CTSB1270;
|
||||
cap.mic_source_switch = hw->model == CTSB1270;
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
static int hw_output_switch_get(struct hw *hw)
|
||||
{
|
||||
u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
|
||||
|
||||
switch (data & 0x30) {
|
||||
case 0x00:
|
||||
return 0;
|
||||
case 0x10:
|
||||
return 1;
|
||||
case 0x20:
|
||||
return 2;
|
||||
default:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
static int hw_output_switch_put(struct hw *hw, int position)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
if (position == hw_output_switch_get(hw))
|
||||
return 0;
|
||||
|
||||
/* Mute line and headphones (intended for anti-pop). */
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
data |= (0x03 << 11);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
|
||||
data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
|
||||
switch (position) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
data |= 0x10;
|
||||
break;
|
||||
default:
|
||||
data |= 0x20;
|
||||
}
|
||||
hw_write_20kx(hw, GPIO_EXT_DATA, data);
|
||||
|
||||
/* Unmute line and headphones. */
|
||||
data = hw_read_20kx(hw, GPIO_DATA);
|
||||
data &= ~(0x03 << 11);
|
||||
hw_write_20kx(hw, GPIO_DATA, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hw_mic_source_switch_get(struct hw *hw)
|
||||
{
|
||||
struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
|
||||
|
||||
return hw20k2->mic_source;
|
||||
}
|
||||
|
||||
static int hw_mic_source_switch_put(struct hw *hw, int position)
|
||||
{
|
||||
struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
|
||||
|
||||
if (position == hw20k2->mic_source)
|
||||
return 0;
|
||||
|
||||
switch (position) {
|
||||
case 0:
|
||||
hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */
|
||||
break;
|
||||
case 1:
|
||||
hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */
|
||||
break;
|
||||
case 2:
|
||||
hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
hw20k2->mic_source = position;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
|
||||
|
@ -1925,7 +2061,7 @@ static int hw_card_start(struct hw *hw)
|
|||
|
||||
if (hw->irq < 0) {
|
||||
err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
|
||||
"ctxfi", hw);
|
||||
KBUILD_MODNAME, hw);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
|
||||
goto error2;
|
||||
|
@ -2023,13 +2159,16 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
|
|||
/* Reset all SRC pending interrupts */
|
||||
hw_write_20kx(hw, SRC_IP, 0);
|
||||
|
||||
/* TODO: detect the card ID and configure GPIO accordingly. */
|
||||
/* Configures GPIO (0xD802 0x98028) */
|
||||
/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
|
||||
/* Configures GPIO (SB0880) */
|
||||
/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
|
||||
hw_write_20kx(hw, GPIO_CTRL, 0xD802);
|
||||
|
||||
if (hw->model != CTSB1270) {
|
||||
/* TODO: detect the card ID and configure GPIO accordingly. */
|
||||
/* Configures GPIO (0xD802 0x98028) */
|
||||
/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
|
||||
/* Configures GPIO (SB0880) */
|
||||
/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
|
||||
hw_write_20kx(hw, GPIO_CTRL, 0xD802);
|
||||
} else {
|
||||
hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
|
||||
}
|
||||
/* Enable audio ring */
|
||||
hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
|
||||
|
||||
|
@ -2106,7 +2245,11 @@ static struct hw ct20k2_preset __devinitdata = {
|
|||
.pll_init = hw_pll_init,
|
||||
.is_adc_source_selected = hw_is_adc_input_selected,
|
||||
.select_adc_source = hw_adc_input_select,
|
||||
.have_digit_io_switch = hw_have_digit_io_switch,
|
||||
.capabilities = hw_capabilities,
|
||||
.output_switch_get = hw_output_switch_get,
|
||||
.output_switch_put = hw_output_switch_put,
|
||||
.mic_source_switch_get = hw_mic_source_switch_get,
|
||||
.mic_source_switch_put = hw_mic_source_switch_put,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = hw_suspend,
|
||||
.resume = hw_resume,
|
||||
|
|
|
@ -86,9 +86,7 @@ enum CTALSA_MIXER_CTL {
|
|||
MIXER_LINEIN_C_S,
|
||||
MIXER_MIC_C_S,
|
||||
MIXER_SPDIFI_C_S,
|
||||
MIXER_LINEIN_P_S,
|
||||
MIXER_SPDIFO_P_S,
|
||||
MIXER_SPDIFI_P_S,
|
||||
MIXER_WAVEF_P_S,
|
||||
MIXER_WAVER_P_S,
|
||||
MIXER_WAVEC_P_S,
|
||||
|
@ -137,11 +135,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
|
|||
},
|
||||
[MIXER_LINEIN_P] = {
|
||||
.ctl = 1,
|
||||
.name = "Line-in Playback Volume",
|
||||
.name = "Line Playback Volume",
|
||||
},
|
||||
[MIXER_LINEIN_C] = {
|
||||
.ctl = 1,
|
||||
.name = "Line-in Capture Volume",
|
||||
.name = "Line Capture Volume",
|
||||
},
|
||||
[MIXER_MIC_P] = {
|
||||
.ctl = 1,
|
||||
|
@ -153,15 +151,15 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
|
|||
},
|
||||
[MIXER_SPDIFI_P] = {
|
||||
.ctl = 1,
|
||||
.name = "S/PDIF-in Playback Volume",
|
||||
.name = "IEC958 Playback Volume",
|
||||
},
|
||||
[MIXER_SPDIFI_C] = {
|
||||
.ctl = 1,
|
||||
.name = "S/PDIF-in Capture Volume",
|
||||
.name = "IEC958 Capture Volume",
|
||||
},
|
||||
[MIXER_SPDIFO_P] = {
|
||||
.ctl = 1,
|
||||
.name = "S/PDIF-out Playback Volume",
|
||||
.name = "Digital Playback Volume",
|
||||
},
|
||||
[MIXER_WAVEF_P] = {
|
||||
.ctl = 1,
|
||||
|
@ -179,14 +177,13 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
|
|||
.ctl = 1,
|
||||
.name = "Surround Playback Volume",
|
||||
},
|
||||
|
||||
[MIXER_PCM_C_S] = {
|
||||
.ctl = 1,
|
||||
.name = "PCM Capture Switch",
|
||||
},
|
||||
[MIXER_LINEIN_C_S] = {
|
||||
.ctl = 1,
|
||||
.name = "Line-in Capture Switch",
|
||||
.name = "Line Capture Switch",
|
||||
},
|
||||
[MIXER_MIC_C_S] = {
|
||||
.ctl = 1,
|
||||
|
@ -194,19 +191,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
|
|||
},
|
||||
[MIXER_SPDIFI_C_S] = {
|
||||
.ctl = 1,
|
||||
.name = "S/PDIF-in Capture Switch",
|
||||
},
|
||||
[MIXER_LINEIN_P_S] = {
|
||||
.ctl = 1,
|
||||
.name = "Line-in Playback Switch",
|
||||
.name = "IEC958 Capture Switch",
|
||||
},
|
||||
[MIXER_SPDIFO_P_S] = {
|
||||
.ctl = 1,
|
||||
.name = "S/PDIF-out Playback Switch",
|
||||
},
|
||||
[MIXER_SPDIFI_P_S] = {
|
||||
.ctl = 1,
|
||||
.name = "S/PDIF-in Playback Switch",
|
||||
.name = "Digital Playback Switch",
|
||||
},
|
||||
[MIXER_WAVEF_P_S] = {
|
||||
.ctl = 1,
|
||||
|
@ -236,6 +225,8 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
|
|||
static void
|
||||
ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
|
||||
|
||||
/* FIXME: this static looks like it would fail if more than one card was */
|
||||
/* installed. */
|
||||
static struct snd_kcontrol *kctls[2] = {NULL};
|
||||
|
||||
static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
|
||||
|
@ -420,6 +411,77 @@ static struct snd_kcontrol_new vol_ctl = {
|
|||
.tlv = { .p = ct_vol_db_scale },
|
||||
};
|
||||
|
||||
static int output_switch_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[3] = {
|
||||
"FP Headphones", "Headphones", "Speakers"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int output_switch_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
|
||||
ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
|
||||
if (ucontrol->value.enumerated.item[0] > 2)
|
||||
return -EINVAL;
|
||||
return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new output_ctl = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Output Playback Enum",
|
||||
.info = output_switch_info,
|
||||
.get = output_switch_get,
|
||||
.put = output_switch_put,
|
||||
};
|
||||
|
||||
static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[3] = {
|
||||
"Mic", "FP Mic", "Aux"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(info, 1, 3, names);
|
||||
}
|
||||
|
||||
static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
|
||||
ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
|
||||
if (ucontrol->value.enumerated.item[0] > 2)
|
||||
return -EINVAL;
|
||||
return atc->mic_source_switch_put(atc,
|
||||
ucontrol->value.enumerated.item[0]);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new mic_source_ctl = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Mic Source Capture Enum",
|
||||
.info = mic_source_switch_info,
|
||||
.get = mic_source_switch_get,
|
||||
.put = mic_source_switch_put,
|
||||
};
|
||||
|
||||
static void
|
||||
do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
|
||||
{
|
||||
|
@ -465,6 +527,7 @@ do_digit_io_switch(struct ct_atc *atc, int state)
|
|||
static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
|
||||
{
|
||||
struct ct_mixer *mixer = atc->mixer;
|
||||
struct capabilities cap = atc->capabilities(atc);
|
||||
|
||||
/* Do changes in mixer. */
|
||||
if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
|
||||
|
@ -477,8 +540,17 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
|
|||
}
|
||||
}
|
||||
/* Do changes out of mixer. */
|
||||
if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
|
||||
do_line_mic_switch(atc, type);
|
||||
if (!cap.dedicated_mic &&
|
||||
(MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {
|
||||
if (state)
|
||||
do_line_mic_switch(atc, type);
|
||||
atc->line_in_unmute(atc, state);
|
||||
} else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))
|
||||
atc->line_in_unmute(atc, state);
|
||||
else if (cap.dedicated_mic && (MIXER_MIC_C_S == type))
|
||||
atc->mic_unmute(atc, state);
|
||||
else if (MIXER_SPDIFI_C_S == type)
|
||||
atc->spdif_in_unmute(atc, state);
|
||||
else if (MIXER_WAVEF_P_S == type)
|
||||
atc->line_front_unmute(atc, state);
|
||||
else if (MIXER_WAVES_P_S == type)
|
||||
|
@ -487,12 +559,8 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
|
|||
atc->line_clfe_unmute(atc, state);
|
||||
else if (MIXER_WAVER_P_S == type)
|
||||
atc->line_rear_unmute(atc, state);
|
||||
else if (MIXER_LINEIN_P_S == type)
|
||||
atc->line_in_unmute(atc, state);
|
||||
else if (MIXER_SPDIFO_P_S == type)
|
||||
atc->spdif_out_unmute(atc, state);
|
||||
else if (MIXER_SPDIFI_P_S == type)
|
||||
atc->spdif_in_unmute(atc, state);
|
||||
else if (MIXER_DIGITAL_IO_S == type)
|
||||
do_digit_io_switch(atc, state);
|
||||
|
||||
|
@ -671,6 +739,7 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
|
|||
{
|
||||
enum CTALSA_MIXER_CTL type;
|
||||
struct ct_atc *atc = mixer->atc;
|
||||
struct capabilities cap = atc->capabilities(atc);
|
||||
int err;
|
||||
|
||||
/* Create snd kcontrol instances on demand */
|
||||
|
@ -684,8 +753,8 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
|
|||
}
|
||||
}
|
||||
|
||||
ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
|
||||
atc->have_digit_io_switch(atc);
|
||||
ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;
|
||||
|
||||
for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
|
||||
if (ct_kcontrol_init_table[type].ctl) {
|
||||
swh_ctl.name = ct_kcontrol_init_table[type].name;
|
||||
|
@ -708,6 +777,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (cap.output_switch) {
|
||||
err = ct_mixer_kcontrol_new(mixer, &output_ctl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (cap.mic_source_switch) {
|
||||
err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
atc->line_front_unmute(atc, 1);
|
||||
set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
|
||||
atc->line_surround_unmute(atc, 0);
|
||||
|
@ -719,13 +799,12 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
|
|||
atc->spdif_out_unmute(atc, 0);
|
||||
set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
|
||||
atc->line_in_unmute(atc, 0);
|
||||
set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
|
||||
if (cap.dedicated_mic)
|
||||
atc->mic_unmute(atc, 0);
|
||||
atc->spdif_in_unmute(atc, 0);
|
||||
set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
|
||||
|
||||
set_switch_state(mixer, MIXER_PCM_C_S, 1);
|
||||
set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
|
||||
set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
|
||||
set_switch_state(mixer, MIXER_PCM_C_S, 0);
|
||||
set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
|
||||
set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -80,11 +80,11 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
|
|||
"are 48000 and 44100, Value 48000 is assumed.\n");
|
||||
reference_rate = 48000;
|
||||
}
|
||||
if ((multiple != 1) && (multiple != 2)) {
|
||||
if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
|
||||
printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
|
||||
multiple);
|
||||
printk(KERN_ERR "ctxfi: The valid values for multiple are "
|
||||
"1 and 2, Value 2 is assumed.\n");
|
||||
"1, 2 and 4, Value 2 is assumed.\n");
|
||||
multiple = 2;
|
||||
}
|
||||
err = ct_atc_create(card, pci, reference_rate, multiple,
|
||||
|
@ -143,7 +143,7 @@ static int ct_card_resume(struct pci_dev *pci)
|
|||
#endif
|
||||
|
||||
static struct pci_driver ct_driver = {
|
||||
.name = "SB-XFi",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = ct_pci_dev_ids,
|
||||
.probe = ct_card_probe,
|
||||
.remove = __devexit_p(ct_card_remove),
|
||||
|
|
|
@ -1995,7 +1995,7 @@ static __devinit int snd_echo_create(struct snd_card *card,
|
|||
ioremap_nocache(chip->dsp_registers_phys, sz);
|
||||
|
||||
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
|
||||
ECHOCARD_NAME, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_echo_free(chip);
|
||||
snd_printk(KERN_ERR "cannot grab irq\n");
|
||||
return -EBUSY;
|
||||
|
@ -2286,7 +2286,7 @@ static int snd_echo_resume(struct pci_dev *pci)
|
|||
kfree(commpage_bak);
|
||||
|
||||
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
|
||||
ECHOCARD_NAME, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_echo_free(chip);
|
||||
snd_printk(KERN_ERR "cannot grab irq\n");
|
||||
return -EBUSY;
|
||||
|
@ -2327,7 +2327,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci)
|
|||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver driver = {
|
||||
.name = "Echoaudio " ECHOCARD_NAME,
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_echo_ids,
|
||||
.probe = snd_echo_probe,
|
||||
.remove = __devexit_p(snd_echo_remove),
|
||||
|
|
|
@ -264,7 +264,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci)
|
|||
#endif
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "EMU10K1_Audigy",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_emu10k1_ids,
|
||||
.probe = snd_card_emu10k1_probe,
|
||||
.remove = __devexit_p(snd_card_emu10k1_remove),
|
||||
|
|
|
@ -1912,7 +1912,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
|
|||
|
||||
/* irq handler must be registered after I/O ports are activated */
|
||||
if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_SHARED,
|
||||
"EMU10K1", emu)) {
|
||||
KBUILD_MODNAME, emu)) {
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -925,7 +925,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card,
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_emu10k1x_interrupt,
|
||||
IRQF_SHARED, "EMU10K1X", chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq);
|
||||
snd_emu10k1x_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1613,7 +1613,7 @@ MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
|
|||
|
||||
// pci_driver definition
|
||||
static struct pci_driver driver = {
|
||||
.name = "EMU10K1X",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_emu10k1x_ids,
|
||||
.probe = snd_emu10k1x_probe,
|
||||
.remove = __devexit_p(snd_emu10k1x_remove),
|
||||
|
|
|
@ -2120,7 +2120,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
|
|||
}
|
||||
ensoniq->port = pci_resource_start(pci, 0);
|
||||
if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED,
|
||||
"Ensoniq AudioPCI", ensoniq)) {
|
||||
KBUILD_MODNAME, ensoniq)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_ensoniq_free(ensoniq);
|
||||
return -EBUSY;
|
||||
|
@ -2489,7 +2489,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_audiopci_ids,
|
||||
.probe = snd_audiopci_probe,
|
||||
.remove = __devexit_p(snd_audiopci_remove),
|
||||
|
|
|
@ -1514,7 +1514,7 @@ static int es1938_resume(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
if (request_irq(pci->irq, snd_es1938_interrupt,
|
||||
IRQF_SHARED, "ES1938", chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "es1938: unable to grab IRQ %d, "
|
||||
"disabling device\n", pci->irq);
|
||||
snd_card_disconnect(card);
|
||||
|
@ -1636,7 +1636,7 @@ static int __devinit snd_es1938_create(struct snd_card *card,
|
|||
chip->mpu_port = pci_resource_start(pci, 3);
|
||||
chip->game_port = pci_resource_start(pci, 4);
|
||||
if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
|
||||
"ES1938", chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_es1938_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ESS ES1938 (Solo-1)",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_es1938_ids,
|
||||
.probe = snd_es1938_probe,
|
||||
.remove = __devexit_p(snd_es1938_remove),
|
||||
|
|
|
@ -554,9 +554,8 @@ struct es1968 {
|
|||
#else
|
||||
struct snd_kcontrol *master_switch; /* for h/w volume control */
|
||||
struct snd_kcontrol *master_volume;
|
||||
spinlock_t ac97_lock;
|
||||
struct tasklet_struct hwvol_tq;
|
||||
#endif
|
||||
struct work_struct hwvol_work;
|
||||
|
||||
#ifdef CONFIG_SND_ES1968_RADIO
|
||||
struct snd_tea575x tea;
|
||||
|
@ -646,38 +645,23 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
|
|||
static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
|
||||
{
|
||||
struct es1968 *chip = ac97->private_data;
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
snd_es1968_ac97_wait(chip);
|
||||
|
||||
/* Write the bus */
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
spin_lock_irqsave(&chip->ac97_lock, flags);
|
||||
#endif
|
||||
outw(val, chip->io_port + ESM_AC97_DATA);
|
||||
/*msleep(1);*/
|
||||
outb(reg, chip->io_port + ESM_AC97_INDEX);
|
||||
/*msleep(1);*/
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
spin_unlock_irqrestore(&chip->ac97_lock, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
|
||||
{
|
||||
u16 data = 0;
|
||||
struct es1968 *chip = ac97->private_data;
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
snd_es1968_ac97_wait(chip);
|
||||
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
spin_lock_irqsave(&chip->ac97_lock, flags);
|
||||
#endif
|
||||
outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);
|
||||
/*msleep(1);*/
|
||||
|
||||
|
@ -685,9 +669,6 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short
|
|||
data = inw(chip->io_port + ESM_AC97_DATA);
|
||||
/*msleep(1);*/
|
||||
}
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
spin_unlock_irqrestore(&chip->ac97_lock, flags);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -1904,13 +1885,10 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es)
|
|||
(without wrap around) in response to volume button presses and then
|
||||
generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
|
||||
of a byte wide register. The meaning of bits 0 and 4 is unknown. */
|
||||
static void es1968_update_hw_volume(unsigned long private_data)
|
||||
static void es1968_update_hw_volume(struct work_struct *work)
|
||||
{
|
||||
struct es1968 *chip = (struct es1968 *) private_data;
|
||||
struct es1968 *chip = container_of(work, struct es1968, hwvol_work);
|
||||
int x, val;
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
/* Figure out which volume control button was pushed,
|
||||
based on differences from the default register
|
||||
|
@ -1929,18 +1907,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
|
|||
if (! chip->master_switch || ! chip->master_volume)
|
||||
return;
|
||||
|
||||
/* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
|
||||
spin_lock_irqsave(&chip->ac97_lock, flags);
|
||||
val = chip->ac97->regs[AC97_MASTER];
|
||||
val = snd_ac97_read(chip->ac97, AC97_MASTER);
|
||||
switch (x) {
|
||||
case 0x88:
|
||||
/* mute */
|
||||
val ^= 0x8000;
|
||||
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_switch->id);
|
||||
break;
|
||||
case 0xaa:
|
||||
/* volume up */
|
||||
|
@ -1948,11 +1919,6 @@ static void es1968_update_hw_volume(unsigned long private_data)
|
|||
val--;
|
||||
if ((val & 0x7f00) > 0)
|
||||
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;
|
||||
case 0x66:
|
||||
/* volume down */
|
||||
|
@ -1960,14 +1926,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
|
|||
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);
|
||||
if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
|
||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&chip->master_volume->id);
|
||||
#else
|
||||
if (!chip->input_dev)
|
||||
return;
|
||||
|
@ -2013,11 +1976,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
|
|||
outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
|
||||
|
||||
if (event & ESM_HWVOL_IRQ)
|
||||
#ifdef CONFIG_SND_ES1968_INPUT
|
||||
es1968_update_hw_volume((unsigned long)chip);
|
||||
#else
|
||||
tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
|
||||
#endif
|
||||
schedule_work(&chip->hwvol_work);
|
||||
|
||||
/* else ack 'em all, i imagine */
|
||||
outb(0xFF, chip->io_port + 0x1A);
|
||||
|
@ -2426,6 +2385,7 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state)
|
|||
return 0;
|
||||
|
||||
chip->in_suspend = 1;
|
||||
cancel_work_sync(&chip->hwvol_work);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
snd_pcm_suspend_all(chip->pcm);
|
||||
snd_ac97_suspend(chip->ac97);
|
||||
|
@ -2638,6 +2598,7 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = {
|
|||
|
||||
static int snd_es1968_free(struct es1968 *chip)
|
||||
{
|
||||
cancel_work_sync(&chip->hwvol_work);
|
||||
#ifdef CONFIG_SND_ES1968_INPUT
|
||||
if (chip->input_dev)
|
||||
input_unregister_device(chip->input_dev);
|
||||
|
@ -2728,10 +2689,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
|
|||
INIT_LIST_HEAD(&chip->buf_list);
|
||||
INIT_LIST_HEAD(&chip->substream_list);
|
||||
mutex_init(&chip->memory_mutex);
|
||||
#ifndef CONFIG_SND_ES1968_INPUT
|
||||
spin_lock_init(&chip->ac97_lock);
|
||||
tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
|
||||
#endif
|
||||
INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume);
|
||||
chip->card = card;
|
||||
chip->pci = pci;
|
||||
chip->irq = -1;
|
||||
|
@ -2746,7 +2704,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
|
|||
}
|
||||
chip->io_port = pci_resource_start(pci, 0);
|
||||
if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED,
|
||||
"ESS Maestro", chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_es1968_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -2925,7 +2883,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ES1968 (ESS Maestro)",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_es1968_ids,
|
||||
.probe = snd_es1968_probe,
|
||||
.remove = __devexit_p(snd_es1968_remove),
|
||||
|
|
|
@ -1199,7 +1199,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
|||
chip->port = pci_resource_start(pci, 0);
|
||||
if ((tea575x_tuner & TUNER_ONLY) == 0) {
|
||||
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
|
||||
"FM801", chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
|
||||
snd_fm801_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1394,7 +1394,7 @@ static int snd_fm801_resume(struct pci_dev *pci)
|
|||
#endif
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "FM801",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_fm801_ids,
|
||||
.probe = snd_card_fm801_probe,
|
||||
.remove = __devexit_p(snd_card_fm801_remove),
|
||||
|
|
|
@ -14,6 +14,19 @@ menuconfig SND_HDA_INTEL
|
|||
|
||||
if SND_HDA_INTEL
|
||||
|
||||
config SND_HDA_PREALLOC_SIZE
|
||||
int "Pre-allocated buffer size for HD-audio driver"
|
||||
range 0 32768
|
||||
default 64
|
||||
help
|
||||
Specifies the default pre-allocated buffer-size in kB for the
|
||||
HD-audio driver. A larger buffer (e.g. 2048) is preferred
|
||||
for systems using PulseAudio. The default 64 is chosen just
|
||||
for compatibility reasons.
|
||||
|
||||
Note that the pre-allocation size can be changed dynamically
|
||||
via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
|
||||
|
||||
config SND_HDA_HWDEP
|
||||
bool "Build hwdep interface for HD-audio driver"
|
||||
select SND_HWDEP
|
||||
|
@ -83,6 +96,19 @@ config SND_HDA_CODEC_REALTEK
|
|||
snd-hda-codec-realtek.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_ENABLE_REALTEK_QUIRKS
|
||||
bool "Build static quirks for Realtek codecs"
|
||||
depends on SND_HDA_CODEC_REALTEK
|
||||
default y
|
||||
help
|
||||
Say Y here to build the static quirks codes for Realtek codecs.
|
||||
If you need the "model" preset that the default BIOS auto-parser
|
||||
can't handle, turn this option on.
|
||||
|
||||
If your device works with model=auto option, basically you don't
|
||||
need the quirk code. By turning this off, you can reduce the
|
||||
module size quite a lot.
|
||||
|
||||
config SND_HDA_CODEC_ANALOG
|
||||
bool "Build Analog Device HD-audio codec support"
|
||||
default y
|
||||
|
@ -171,6 +197,19 @@ config SND_HDA_CODEC_CA0110
|
|||
snd-hda-codec-ca0110.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_CA0132
|
||||
bool "Build Creative CA0132 codec support"
|
||||
depends on SND_HDA_INTEL
|
||||
default y
|
||||
help
|
||||
Say Y here to include Creative CA0132 codec support in
|
||||
snd-hda-intel driver.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-ca0132.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_CMEDIA
|
||||
bool "Build C-Media HD-audio codec support"
|
||||
default y
|
||||
|
|
|
@ -13,6 +13,7 @@ snd-hda-codec-idt-objs := patch_sigmatel.o
|
|||
snd-hda-codec-si3054-objs := patch_si3054.o
|
||||
snd-hda-codec-cirrus-objs := patch_cirrus.o
|
||||
snd-hda-codec-ca0110-objs := patch_ca0110.o
|
||||
snd-hda-codec-ca0132-objs := patch_ca0132.o
|
||||
snd-hda-codec-conexant-objs := patch_conexant.o
|
||||
snd-hda-codec-via-objs := patch_via.o
|
||||
snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
|
||||
|
@ -42,6 +43,9 @@ endif
|
|||
ifdef CONFIG_SND_HDA_CODEC_CA0110
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_CA0132
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_CONEXANT
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
|
||||
endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,636 @@
|
|||
/*
|
||||
* ALC267/ALC268 quirk models
|
||||
* included by patch_realtek.c
|
||||
*/
|
||||
|
||||
/* ALC268 models */
|
||||
enum {
|
||||
ALC268_AUTO,
|
||||
ALC267_QUANTA_IL1,
|
||||
ALC268_3ST,
|
||||
ALC268_TOSHIBA,
|
||||
ALC268_ACER,
|
||||
ALC268_ACER_DMIC,
|
||||
ALC268_ACER_ASPIRE_ONE,
|
||||
ALC268_DELL,
|
||||
ALC268_ZEPTO,
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
ALC268_TEST,
|
||||
#endif
|
||||
ALC268_MODEL_LAST /* last tag */
|
||||
};
|
||||
|
||||
/*
|
||||
* ALC268 channel source setting (2 channel)
|
||||
*/
|
||||
#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
|
||||
#define alc268_modes alc260_modes
|
||||
|
||||
static const hda_nid_t alc268_dac_nids[2] = {
|
||||
/* front, hp */
|
||||
0x02, 0x03
|
||||
};
|
||||
|
||||
static const hda_nid_t alc268_adc_nids[2] = {
|
||||
/* ADC0-1 */
|
||||
0x08, 0x07
|
||||
};
|
||||
|
||||
static const hda_nid_t alc268_adc_nids_alt[1] = {
|
||||
/* ADC0 */
|
||||
0x08
|
||||
};
|
||||
|
||||
static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
|
||||
|
||||
static const struct snd_kcontrol_new alc268_base_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
|
||||
ALC262_HIPPO_MASTER_SWITCH,
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc268_eapd_verbs[] = {
|
||||
{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
||||
{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Toshiba specific */
|
||||
static const struct hda_verb alc268_toshiba_verbs[] = {
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* Acer specific */
|
||||
/* bind volumes of both NID 0x02 and 0x03 */
|
||||
static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
|
||||
.ops = &snd_hda_bind_vol,
|
||||
.values = {
|
||||
HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
static void alc268_acer_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
spec->autocfg.hp_pins[0] = 0x14;
|
||||
spec->autocfg.speaker_pins[0] = 0x15;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
#define alc268_acer_master_sw_get alc262_hp_master_sw_get
|
||||
#define alc268_acer_master_sw_put alc262_hp_master_sw_put
|
||||
|
||||
static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = alc268_acer_master_sw_get,
|
||||
.put = alc268_acer_master_sw_put,
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc268_acer_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = alc268_acer_master_sw_get,
|
||||
.put = alc268_acer_master_sw_put,
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = alc268_acer_master_sw_get,
|
||||
.put = alc268_acer_master_sw_put,
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
|
||||
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc268_acer_verbs[] = {
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
|
||||
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* unsolicited event for HP jack sensing */
|
||||
#define alc268_toshiba_setup alc262_hippo_setup
|
||||
|
||||
static void alc268_acer_lc_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x12;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new alc268_dell_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc268_dell_verbs[] = {
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* mute/unmute internal speaker according to the hp jack and mute state */
|
||||
static void alc268_dell_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x19;
|
||||
spec->auto_mic = 1;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_PIN;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc267_quanta_il1_verbs[] = {
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void alc267_quanta_il1_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x19;
|
||||
spec->auto_mic = 1;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_PIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* generic initialization of ADC, input mixers and output mixers
|
||||
*/
|
||||
static const struct hda_verb alc268_base_init_verbs[] = {
|
||||
/* Unmute DAC0-1 and set vol = 0 */
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
|
||||
/*
|
||||
* Set up output mixers (0x0c - 0x0e)
|
||||
*/
|
||||
/* set vol=0 to output mixers */
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
||||
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
|
||||
/* set PCBEEP vol = 0, mute connections */
|
||||
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
|
||||
/* Unmute Selector 23h,24h and set the default input to mic-in */
|
||||
|
||||
{0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
/* only for model=test */
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
/*
|
||||
* generic initialization of ADC, input mixers and output mixers
|
||||
*/
|
||||
static const struct hda_verb alc268_volume_init_verbs[] = {
|
||||
/* set output DAC */
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
||||
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{ }
|
||||
};
|
||||
#endif /* CONFIG_SND_DEBUG */
|
||||
|
||||
static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
|
||||
_DEFINE_CAPSRC(1),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc268_capture_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
|
||||
_DEFINE_CAPSRC(2),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct hda_input_mux alc268_capture_source = {
|
||||
.num_items = 4,
|
||||
.items = {
|
||||
{ "Mic", 0x0 },
|
||||
{ "Front Mic", 0x1 },
|
||||
{ "Line", 0x2 },
|
||||
{ "CD", 0x3 },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_input_mux alc268_acer_capture_source = {
|
||||
.num_items = 3,
|
||||
.items = {
|
||||
{ "Mic", 0x0 },
|
||||
{ "Internal Mic", 0x1 },
|
||||
{ "Line", 0x2 },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_input_mux alc268_acer_dmic_capture_source = {
|
||||
.num_items = 3,
|
||||
.items = {
|
||||
{ "Mic", 0x0 },
|
||||
{ "Internal Mic", 0x6 },
|
||||
{ "Line", 0x2 },
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
static const struct snd_kcontrol_new alc268_test_mixer[] = {
|
||||
/* Volume widgets */
|
||||
HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
|
||||
HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
|
||||
HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
|
||||
HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
|
||||
HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
|
||||
HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
|
||||
/* The below appears problematic on some hardwares */
|
||||
/*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
|
||||
HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
|
||||
|
||||
/* Modes for retasking pin widgets */
|
||||
ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
|
||||
ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
|
||||
ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
|
||||
ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
|
||||
|
||||
/* Controls for GPIO pins, assuming they are configured as outputs */
|
||||
ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
|
||||
ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
|
||||
ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
|
||||
ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
|
||||
|
||||
/* Switches to allow the digital SPDIF output pin to be enabled.
|
||||
* The ALC268 does not have an SPDIF input.
|
||||
*/
|
||||
ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
|
||||
|
||||
/* A switch allowing EAPD to be enabled. Some laptops seem to use
|
||||
* this output to turn on an external amplifier.
|
||||
*/
|
||||
ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
|
||||
ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* configuration and preset
|
||||
*/
|
||||
static const char * const alc268_models[ALC268_MODEL_LAST] = {
|
||||
[ALC267_QUANTA_IL1] = "quanta-il1",
|
||||
[ALC268_3ST] = "3stack",
|
||||
[ALC268_TOSHIBA] = "toshiba",
|
||||
[ALC268_ACER] = "acer",
|
||||
[ALC268_ACER_DMIC] = "acer-dmic",
|
||||
[ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
|
||||
[ALC268_DELL] = "dell",
|
||||
[ALC268_ZEPTO] = "zepto",
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
[ALC268_TEST] = "test",
|
||||
#endif
|
||||
[ALC268_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc268_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
|
||||
SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
|
||||
SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
|
||||
SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
|
||||
SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
|
||||
SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
|
||||
ALC268_ACER_ASPIRE_ONE),
|
||||
SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
|
||||
SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
|
||||
SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
|
||||
"Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
|
||||
/* almost compatible with toshiba but with optional digital outs;
|
||||
* auto-probing seems working fine
|
||||
*/
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
|
||||
ALC268_AUTO),
|
||||
SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
|
||||
SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
|
||||
SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
|
||||
SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
|
||||
{}
|
||||
};
|
||||
|
||||
/* Toshiba laptops have no unique PCI SSID but only codec SSID */
|
||||
static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
|
||||
SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
|
||||
SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
|
||||
ALC268_TOSHIBA),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct alc_config_preset alc268_presets[] = {
|
||||
[ALC267_QUANTA_IL1] = {
|
||||
.mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
|
||||
alc268_capture_nosrc_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc267_quanta_il1_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc267_quanta_il1_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC268_3ST] = {
|
||||
.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
|
||||
alc268_beep_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x03,
|
||||
.dig_out_nid = ALC268_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.input_mux = &alc268_capture_source,
|
||||
},
|
||||
[ALC268_TOSHIBA] = {
|
||||
.mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
|
||||
alc268_beep_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_toshiba_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.input_mux = &alc268_capture_source,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc268_toshiba_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC268_ACER] = {
|
||||
.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
|
||||
alc268_beep_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_acer_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x02,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.input_mux = &alc268_acer_capture_source,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc268_acer_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC268_ACER_DMIC] = {
|
||||
.mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
|
||||
alc268_beep_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_acer_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x02,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.input_mux = &alc268_acer_dmic_capture_source,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc268_acer_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC268_ACER_ASPIRE_ONE] = {
|
||||
.mixers = { alc268_acer_aspire_one_mixer,
|
||||
alc268_beep_mixer,
|
||||
alc268_capture_nosrc_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_acer_aspire_one_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc268_acer_lc_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC268_DELL] = {
|
||||
.mixers = { alc268_dell_mixer, alc268_beep_mixer,
|
||||
alc268_capture_nosrc_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_dell_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x02,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc268_dell_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC268_ZEPTO] = {
|
||||
.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
|
||||
alc268_beep_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_toshiba_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x03,
|
||||
.dig_out_nid = ALC268_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.input_mux = &alc268_capture_source,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc268_toshiba_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
[ALC268_TEST] = {
|
||||
.mixers = { alc268_test_mixer, alc268_capture_mixer },
|
||||
.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
|
||||
alc268_volume_init_verbs,
|
||||
alc268_beep_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc268_dac_nids),
|
||||
.dac_nids = alc268_dac_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
|
||||
.adc_nids = alc268_adc_nids_alt,
|
||||
.capsrc_nids = alc268_capsrc_nids,
|
||||
.hp_nid = 0x03,
|
||||
.dig_out_nid = ALC268_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc268_modes),
|
||||
.channel_mode = alc268_modes,
|
||||
.input_mux = &alc268_capture_source,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
* ALC269/ALC270/ALC275/ALC276 quirk models
|
||||
* included by patch_realtek.c
|
||||
*/
|
||||
|
||||
/* ALC269 models */
|
||||
enum {
|
||||
ALC269_AUTO,
|
||||
ALC269_BASIC,
|
||||
ALC269_QUANTA_FL1,
|
||||
ALC269_AMIC,
|
||||
ALC269_DMIC,
|
||||
ALC269VB_AMIC,
|
||||
ALC269VB_DMIC,
|
||||
ALC269_FUJITSU,
|
||||
ALC269_LIFEBOOK,
|
||||
ALC271_ACER,
|
||||
ALC269_MODEL_LAST /* last tag */
|
||||
};
|
||||
|
||||
/*
|
||||
* ALC269 channel source setting (2 channel)
|
||||
*/
|
||||
#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
|
||||
|
||||
#define alc269_dac_nids alc260_dac_nids
|
||||
|
||||
static const hda_nid_t alc269_adc_nids[1] = {
|
||||
/* ADC1 */
|
||||
0x08,
|
||||
};
|
||||
|
||||
static const hda_nid_t alc269_capsrc_nids[1] = {
|
||||
0x23,
|
||||
};
|
||||
|
||||
static const hda_nid_t alc269vb_adc_nids[1] = {
|
||||
/* ADC1 */
|
||||
0x09,
|
||||
};
|
||||
|
||||
static const hda_nid_t alc269vb_capsrc_nids[1] = {
|
||||
0x22,
|
||||
};
|
||||
|
||||
#define alc269_modes alc260_modes
|
||||
#define alc269_capture_source alc880_lg_lw_capture_source
|
||||
|
||||
static const struct snd_kcontrol_new alc269_base_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.subdevice = HDA_SUBDEV_AMP_FLAG,
|
||||
.info = snd_hda_mixer_amp_switch_info,
|
||||
.get = snd_hda_mixer_amp_switch_get,
|
||||
.put = alc268_acer_master_sw_put,
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.subdevice = HDA_SUBDEV_AMP_FLAG,
|
||||
.info = snd_hda_mixer_amp_switch_info,
|
||||
.get = snd_hda_mixer_amp_switch_get,
|
||||
.put = alc268_acer_master_sw_put,
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
|
||||
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
|
||||
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269_asus_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* capture mixer elements */
|
||||
static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* FSC amilo */
|
||||
#define alc269_fujitsu_mixer alc269_laptop_mixer
|
||||
|
||||
static const struct hda_verb alc269_quanta_fl1_verbs[] = {
|
||||
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc269_lifebook_verbs[] = {
|
||||
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* toggle speaker-output according to the hp-jack state */
|
||||
static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
|
||||
{
|
||||
alc_hp_automute(codec);
|
||||
|
||||
snd_hda_codec_write(codec, 0x20, 0,
|
||||
AC_VERB_SET_COEF_INDEX, 0x0c);
|
||||
snd_hda_codec_write(codec, 0x20, 0,
|
||||
AC_VERB_SET_PROC_COEF, 0x680);
|
||||
|
||||
snd_hda_codec_write(codec, 0x20, 0,
|
||||
AC_VERB_SET_COEF_INDEX, 0x0c);
|
||||
snd_hda_codec_write(codec, 0x20, 0,
|
||||
AC_VERB_SET_PROC_COEF, 0x480);
|
||||
}
|
||||
|
||||
#define alc269_lifebook_speaker_automute \
|
||||
alc269_quanta_fl1_speaker_automute
|
||||
|
||||
static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present_laptop;
|
||||
unsigned int present_dock;
|
||||
|
||||
present_laptop = snd_hda_jack_detect(codec, 0x18);
|
||||
present_dock = snd_hda_jack_detect(codec, 0x1b);
|
||||
|
||||
/* Laptop mic port overrides dock mic port, design decision */
|
||||
if (present_dock)
|
||||
snd_hda_codec_write(codec, 0x23, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, 0x3);
|
||||
if (present_laptop)
|
||||
snd_hda_codec_write(codec, 0x23, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, 0x0);
|
||||
if (!present_dock && !present_laptop)
|
||||
snd_hda_codec_write(codec, 0x23, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, 0x1);
|
||||
}
|
||||
|
||||
static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
switch (res >> 26) {
|
||||
case ALC_HP_EVENT:
|
||||
alc269_quanta_fl1_speaker_automute(codec);
|
||||
break;
|
||||
case ALC_MIC_EVENT:
|
||||
alc_mic_automute(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void alc269_lifebook_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
if ((res >> 26) == ALC_HP_EVENT)
|
||||
alc269_lifebook_speaker_automute(codec);
|
||||
if ((res >> 26) == ALC_MIC_EVENT)
|
||||
alc269_lifebook_mic_autoswitch(codec);
|
||||
}
|
||||
|
||||
static void alc269_quanta_fl1_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute_mixer_nid[0] = 0x0c;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_MIXER;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x19;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
|
||||
{
|
||||
alc269_quanta_fl1_speaker_automute(codec);
|
||||
alc_mic_automute(codec);
|
||||
}
|
||||
|
||||
static void alc269_lifebook_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.hp_pins[1] = 0x1a;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute_mixer_nid[0] = 0x0c;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_MIXER;
|
||||
}
|
||||
|
||||
static void alc269_lifebook_init_hook(struct hda_codec *codec)
|
||||
{
|
||||
alc269_lifebook_speaker_automute(codec);
|
||||
alc269_lifebook_mic_autoswitch(codec);
|
||||
}
|
||||
|
||||
static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
|
||||
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
|
||||
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
|
||||
{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
|
||||
{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct hda_verb alc271_acer_dmic_verbs[] = {
|
||||
{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
|
||||
{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{0x22, AC_VERB_SET_CONNECT_SEL, 6},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void alc269_laptop_amic_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute_mixer_nid[0] = 0x0c;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_MIXER;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x19;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
static void alc269_laptop_dmic_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute_mixer_nid[0] = 0x0c;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_MIXER;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x12;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x21;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute_mixer_nid[0] = 0x0c;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_MIXER;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x19;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x21;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute_mixer_nid[0] = 0x0c;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_MIXER;
|
||||
spec->ext_mic_pin = 0x18;
|
||||
spec->int_mic_pin = 0x12;
|
||||
spec->auto_mic = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* generic initialization of ADC, input mixers and output mixers
|
||||
*/
|
||||
static const struct hda_verb alc269_init_verbs[] = {
|
||||
/*
|
||||
* Unmute ADC0 and set the default input to mic-in
|
||||
*/
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
|
||||
/*
|
||||
* Set up output mixers (0x02 - 0x03)
|
||||
*/
|
||||
/* set vol=0 to output mixers */
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
|
||||
/* set up input amps for analog loopback */
|
||||
/* Amp Indices: DAC = 0, mixer = 1 */
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
/* FIXME: use Mux-type input source selection */
|
||||
/* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
|
||||
/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
|
||||
{0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
|
||||
/* set EAPD */
|
||||
{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc269vb_init_verbs[] = {
|
||||
/*
|
||||
* Unmute ADC0 and set the default input to mic-in
|
||||
*/
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
|
||||
/*
|
||||
* Set up output mixers (0x02 - 0x03)
|
||||
*/
|
||||
/* set vol=0 to output mixers */
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
|
||||
/* set up input amps for analog loopback */
|
||||
/* Amp Indices: DAC = 0, mixer = 1 */
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
/* FIXME: use Mux-type input source selection */
|
||||
/* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
|
||||
/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
|
||||
{0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
|
||||
/* set EAPD */
|
||||
{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* configuration and preset
|
||||
*/
|
||||
static const char * const alc269_models[ALC269_MODEL_LAST] = {
|
||||
[ALC269_BASIC] = "basic",
|
||||
[ALC269_QUANTA_FL1] = "quanta",
|
||||
[ALC269_AMIC] = "laptop-amic",
|
||||
[ALC269_DMIC] = "laptop-dmic",
|
||||
[ALC269_FUJITSU] = "fujitsu",
|
||||
[ALC269_LIFEBOOK] = "lifebook",
|
||||
[ALC269_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc269_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
|
||||
SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
|
||||
SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
|
||||
ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
|
||||
ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
|
||||
ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
|
||||
SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
|
||||
SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
|
||||
SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
|
||||
SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct alc_config_preset alc269_presets[] = {
|
||||
[ALC269_BASIC] = {
|
||||
.mixers = { alc269_base_mixer },
|
||||
.init_verbs = { alc269_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.input_mux = &alc269_capture_source,
|
||||
},
|
||||
[ALC269_QUANTA_FL1] = {
|
||||
.mixers = { alc269_quanta_fl1_mixer },
|
||||
.init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.input_mux = &alc269_capture_source,
|
||||
.unsol_event = alc269_quanta_fl1_unsol_event,
|
||||
.setup = alc269_quanta_fl1_setup,
|
||||
.init_hook = alc269_quanta_fl1_init_hook,
|
||||
},
|
||||
[ALC269_AMIC] = {
|
||||
.mixers = { alc269_laptop_mixer },
|
||||
.cap_mixer = alc269_laptop_analog_capture_mixer,
|
||||
.init_verbs = { alc269_init_verbs,
|
||||
alc269_laptop_amic_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc269_laptop_amic_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC269_DMIC] = {
|
||||
.mixers = { alc269_laptop_mixer },
|
||||
.cap_mixer = alc269_laptop_digital_capture_mixer,
|
||||
.init_verbs = { alc269_init_verbs,
|
||||
alc269_laptop_dmic_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc269_laptop_dmic_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC269VB_AMIC] = {
|
||||
.mixers = { alc269vb_laptop_mixer },
|
||||
.cap_mixer = alc269vb_laptop_analog_capture_mixer,
|
||||
.init_verbs = { alc269vb_init_verbs,
|
||||
alc269vb_laptop_amic_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc269vb_laptop_amic_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC269VB_DMIC] = {
|
||||
.mixers = { alc269vb_laptop_mixer },
|
||||
.cap_mixer = alc269vb_laptop_digital_capture_mixer,
|
||||
.init_verbs = { alc269vb_init_verbs,
|
||||
alc269vb_laptop_dmic_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc269vb_laptop_dmic_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC269_FUJITSU] = {
|
||||
.mixers = { alc269_fujitsu_mixer },
|
||||
.cap_mixer = alc269_laptop_digital_capture_mixer,
|
||||
.init_verbs = { alc269_init_verbs,
|
||||
alc269_laptop_dmic_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc269_laptop_dmic_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
[ALC269_LIFEBOOK] = {
|
||||
.mixers = { alc269_lifebook_mixer },
|
||||
.init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.hp_nid = 0x03,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.input_mux = &alc269_capture_source,
|
||||
.unsol_event = alc269_lifebook_unsol_event,
|
||||
.setup = alc269_lifebook_setup,
|
||||
.init_hook = alc269_lifebook_init_hook,
|
||||
},
|
||||
[ALC271_ACER] = {
|
||||
.mixers = { alc269_asus_mixer },
|
||||
.cap_mixer = alc269vb_laptop_digital_capture_mixer,
|
||||
.init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc269_dac_nids),
|
||||
.dac_nids = alc269_dac_nids,
|
||||
.adc_nids = alc262_dmic_adc_nids,
|
||||
.num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
|
||||
.capsrc_nids = alc262_dmic_capsrc_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc269_modes),
|
||||
.channel_mode = alc269_modes,
|
||||
.input_mux = &alc269_capture_source,
|
||||
.dig_out_nid = ALC880_DIGOUT_NID,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc269vb_laptop_dmic_setup,
|
||||
.init_hook = alc_inithook,
|
||||
},
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* ALC680 quirk models
|
||||
* included by patch_realtek.c
|
||||
*/
|
||||
|
||||
/* ALC680 models */
|
||||
enum {
|
||||
ALC680_AUTO,
|
||||
ALC680_BASE,
|
||||
ALC680_MODEL_LAST,
|
||||
};
|
||||
|
||||
#define ALC680_DIGIN_NID ALC880_DIGIN_NID
|
||||
#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
|
||||
#define alc680_modes alc260_modes
|
||||
|
||||
static const hda_nid_t alc680_dac_nids[3] = {
|
||||
/* Lout1, Lout2, hp */
|
||||
0x02, 0x03, 0x04
|
||||
};
|
||||
|
||||
static const hda_nid_t alc680_adc_nids[3] = {
|
||||
/* ADC0-2 */
|
||||
/* DMIC, MIC, Line-in*/
|
||||
0x07, 0x08, 0x09
|
||||
};
|
||||
|
||||
/*
|
||||
* Analog capture ADC cgange
|
||||
*/
|
||||
static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec)
|
||||
{
|
||||
static hda_nid_t pins[] = {0x18, 0x19};
|
||||
static hda_nid_t adcs[] = {0x08, 0x09};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pins); i++) {
|
||||
if (!is_jack_detectable(codec, pins[i]))
|
||||
continue;
|
||||
if (snd_hda_jack_detect(codec, pins[i]))
|
||||
return adcs[i];
|
||||
}
|
||||
return 0x07;
|
||||
}
|
||||
|
||||
static void alc680_rec_autoswitch(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
hda_nid_t nid = alc680_get_cur_adc(codec);
|
||||
if (spec->cur_adc && nid != spec->cur_adc) {
|
||||
__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
|
||||
spec->cur_adc = nid;
|
||||
snd_hda_codec_setup_stream(codec, nid,
|
||||
spec->cur_adc_stream_tag, 0,
|
||||
spec->cur_adc_format);
|
||||
}
|
||||
}
|
||||
|
||||
static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
hda_nid_t nid = alc680_get_cur_adc(codec);
|
||||
|
||||
spec->cur_adc = nid;
|
||||
spec->cur_adc_stream_tag = stream_tag;
|
||||
spec->cur_adc_format = format;
|
||||
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
|
||||
spec->cur_adc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
|
||||
.substreams = 1, /* can be overridden */
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
/* NID is set in alc_build_pcms */
|
||||
.ops = {
|
||||
.prepare = alc680_capture_pcm_prepare,
|
||||
.cleanup = alc680_capture_pcm_cleanup
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc680_base_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_bind_ctls alc680_bind_cap_vol = {
|
||||
.ops = &snd_hda_bind_vol,
|
||||
.values = {
|
||||
HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_bind_ctls alc680_bind_cap_switch = {
|
||||
.ops = &snd_hda_bind_sw,
|
||||
.values = {
|
||||
HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
|
||||
HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
|
||||
HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/*
|
||||
* generic initialization of ADC, input mixers and output mixers
|
||||
*/
|
||||
static const struct hda_verb alc680_init_verbs[] = {
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
|
||||
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
/* toggle speaker-output according to the hp-jack state */
|
||||
static void alc680_base_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
spec->autocfg.hp_pins[0] = 0x16;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->autocfg.speaker_pins[1] = 0x15;
|
||||
spec->autocfg.num_inputs = 2;
|
||||
spec->autocfg.inputs[0].pin = 0x18;
|
||||
spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
|
||||
spec->autocfg.inputs[1].pin = 0x19;
|
||||
spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
static void alc680_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
if ((res >> 26) == ALC_HP_EVENT)
|
||||
alc_hp_automute(codec);
|
||||
if ((res >> 26) == ALC_MIC_EVENT)
|
||||
alc680_rec_autoswitch(codec);
|
||||
}
|
||||
|
||||
static void alc680_inithook(struct hda_codec *codec)
|
||||
{
|
||||
alc_hp_automute(codec);
|
||||
alc680_rec_autoswitch(codec);
|
||||
}
|
||||
|
||||
/*
|
||||
* configuration and preset
|
||||
*/
|
||||
static const char * const alc680_models[ALC680_MODEL_LAST] = {
|
||||
[ALC680_BASE] = "base",
|
||||
[ALC680_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc680_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct alc_config_preset alc680_presets[] = {
|
||||
[ALC680_BASE] = {
|
||||
.mixers = { alc680_base_mixer },
|
||||
.cap_mixer = alc680_master_capture_mixer,
|
||||
.init_verbs = { alc680_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc680_dac_nids),
|
||||
.dac_nids = alc680_dac_nids,
|
||||
.dig_out_nid = ALC680_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc680_modes),
|
||||
.channel_mode = alc680_modes,
|
||||
.unsol_event = alc680_unsol_event,
|
||||
.setup = alc680_base_setup,
|
||||
.init_hook = alc680_inithook,
|
||||
|
||||
},
|
||||
};
|
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
* ALC660/ALC861 quirk models
|
||||
* included by patch_realtek.c
|
||||
*/
|
||||
|
||||
/* ALC861 models */
|
||||
enum {
|
||||
ALC861_AUTO,
|
||||
ALC861_3ST,
|
||||
ALC660_3ST,
|
||||
ALC861_3ST_DIG,
|
||||
ALC861_6ST_DIG,
|
||||
ALC861_UNIWILL_M31,
|
||||
ALC861_TOSHIBA,
|
||||
ALC861_ASUS,
|
||||
ALC861_ASUS_LAPTOP,
|
||||
ALC861_MODEL_LAST,
|
||||
};
|
||||
|
||||
/*
|
||||
* ALC861 channel source setting (2/6 channel selection for 3-stack)
|
||||
*/
|
||||
|
||||
/*
|
||||
* set the path ways for 2 channel output
|
||||
* need to set the codec line out and mic 1 pin widgets to inputs
|
||||
*/
|
||||
static const struct hda_verb alc861_threestack_ch2_init[] = {
|
||||
/* set pin widget 1Ah (line in) for input */
|
||||
{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
|
||||
/* set pin widget 18h (mic1/2) for input, for mic also enable
|
||||
* the vref
|
||||
*/
|
||||
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
|
||||
#if 0
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
|
||||
#endif
|
||||
{ } /* end */
|
||||
};
|
||||
/*
|
||||
* 6ch mode
|
||||
* need to set the codec line out and mic 1 pin widgets to outputs
|
||||
*/
|
||||
static const struct hda_verb alc861_threestack_ch6_init[] = {
|
||||
/* set pin widget 1Ah (line in) for output (Back Surround)*/
|
||||
{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||
/* set pin widget 18h (mic1) for output (CLFE)*/
|
||||
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||
|
||||
{ 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
|
||||
#if 0
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
|
||||
#endif
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct hda_channel_mode alc861_threestack_modes[2] = {
|
||||
{ 2, alc861_threestack_ch2_init },
|
||||
{ 6, alc861_threestack_ch6_init },
|
||||
};
|
||||
/* Set mic1 as input and unmute the mixer */
|
||||
static const 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 const 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 const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
|
||||
{ 2, alc861_uniwill_m31_ch2_init },
|
||||
{ 4, alc861_uniwill_m31_ch4_init },
|
||||
};
|
||||
|
||||
/* Set mic1 and line-in as input and unmute the mixer */
|
||||
static const struct hda_verb alc861_asus_ch2_init[] = {
|
||||
/* set pin widget 1Ah (line in) for input */
|
||||
{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
|
||||
/* set pin widget 18h (mic1/2) for input, for mic also enable
|
||||
* the vref
|
||||
*/
|
||||
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
|
||||
#if 0
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
|
||||
#endif
|
||||
{ } /* end */
|
||||
};
|
||||
/* Set mic1 nad line-in as output and mute mixer */
|
||||
static const struct hda_verb alc861_asus_ch6_init[] = {
|
||||
/* set pin widget 1Ah (line in) for output (Back Surround)*/
|
||||
{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||
/* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
|
||||
/* set pin widget 18h (mic1) for output (CLFE)*/
|
||||
{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||
/* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
|
||||
{ 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
|
||||
#if 0
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
|
||||
#endif
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct hda_channel_mode alc861_asus_modes[2] = {
|
||||
{ 2, alc861_asus_ch2_init },
|
||||
{ 6, alc861_asus_ch6_init },
|
||||
};
|
||||
|
||||
/* patch-ALC861 */
|
||||
|
||||
static const struct snd_kcontrol_new alc861_base_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),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc861_3ST_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),
|
||||
|
||||
{
|
||||
.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_threestack_modes),
|
||||
},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
|
||||
/* output mixer control */
|
||||
HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const 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),
|
||||
|
||||
{
|
||||
.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 */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc861_asus_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_OUTPUT),
|
||||
|
||||
{
|
||||
.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_asus_modes),
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* additional mixer */
|
||||
static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* generic initialization of ADC, input mixers and output mixers
|
||||
*/
|
||||
static const struct hda_verb alc861_base_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, 0x40 },
|
||||
{ 0x0e, AC_VERB_SET_CONNECT_SEL, 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, 0xc0 },
|
||||
/* route front PCM to HP */
|
||||
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
/* 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, 0x40 },
|
||||
{ 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
/* port-H for side (rear panel) */
|
||||
{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||
{ 0x20, AC_VERB_SET_CONNECT_SEL, 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)},
|
||||
/* hp used DAC 3 (Front) */
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc861_threestack_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, 0xc0 },
|
||||
/* route front PCM to HP */
|
||||
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
/* 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)},
|
||||
/* hp used DAC 3 (Front) */
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const 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) */
|
||||
/* this has to be set to VREF80 */
|
||||
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||
/* route front PCM to HP */
|
||||
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
/* 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)},
|
||||
/* hp used DAC 3 (Front) */
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc861_asus_init_verbs[] = {
|
||||
/*
|
||||
* Unmute ADC0 and set the default input to mic-in
|
||||
*/
|
||||
/* port-A for surround (rear panel)
|
||||
* according to codec#0 this is the HP jack
|
||||
*/
|
||||
{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
|
||||
/* route front PCM to HP */
|
||||
{ 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
|
||||
/* 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) */
|
||||
/* this has to be set to VREF80 */
|
||||
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
|
||||
/* route front PCM to HP */
|
||||
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
|
||||
/* 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, 0x40 },
|
||||
/* port-H for side (rear panel) */
|
||||
{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
|
||||
/* 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)},
|
||||
/* hp used DAC 3 (Front) */
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* additional init verbs for ASUS laptops */
|
||||
static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
|
||||
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
|
||||
{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc861_toshiba_init_verbs[] = {
|
||||
{0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
/* toggle speaker-output according to the hp-jack state */
|
||||
static void alc861_toshiba_automute(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present = snd_hda_jack_detect(codec, 0x0f);
|
||||
|
||||
snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
|
||||
HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
|
||||
snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
|
||||
HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
|
||||
}
|
||||
|
||||
static void alc861_toshiba_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
if ((res >> 26) == ALC_HP_EVENT)
|
||||
alc861_toshiba_automute(codec);
|
||||
}
|
||||
|
||||
#define ALC861_DIGOUT_NID 0x07
|
||||
|
||||
static const struct hda_channel_mode alc861_8ch_modes[1] = {
|
||||
{ 8, NULL }
|
||||
};
|
||||
|
||||
static const hda_nid_t alc861_dac_nids[4] = {
|
||||
/* front, surround, clfe, side */
|
||||
0x03, 0x06, 0x05, 0x04
|
||||
};
|
||||
|
||||
static const hda_nid_t alc660_dac_nids[3] = {
|
||||
/* front, clfe, surround */
|
||||
0x03, 0x05, 0x06
|
||||
};
|
||||
|
||||
static const hda_nid_t alc861_adc_nids[1] = {
|
||||
/* ADC0-2 */
|
||||
0x08,
|
||||
};
|
||||
|
||||
static const struct hda_input_mux alc861_capture_source = {
|
||||
.num_items = 5,
|
||||
.items = {
|
||||
{ "Mic", 0x0 },
|
||||
{ "Front Mic", 0x3 },
|
||||
{ "Line", 0x1 },
|
||||
{ "CD", 0x4 },
|
||||
{ "Mixer", 0x5 },
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* configuration and preset
|
||||
*/
|
||||
static const char * const alc861_models[ALC861_MODEL_LAST] = {
|
||||
[ALC861_3ST] = "3stack",
|
||||
[ALC660_3ST] = "3stack-660",
|
||||
[ALC861_3ST_DIG] = "3stack-dig",
|
||||
[ALC861_6ST_DIG] = "6stack-dig",
|
||||
[ALC861_UNIWILL_M31] = "uniwill-m31",
|
||||
[ALC861_TOSHIBA] = "toshiba",
|
||||
[ALC861_ASUS] = "asus",
|
||||
[ALC861_ASUS_LAPTOP] = "asus-laptop",
|
||||
[ALC861_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc861_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
|
||||
SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
|
||||
SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
|
||||
SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
|
||||
SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
|
||||
SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
|
||||
SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
|
||||
/* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
|
||||
* Any other models that need this preset?
|
||||
*/
|
||||
/* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
|
||||
SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
|
||||
SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
|
||||
SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
|
||||
SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
|
||||
SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
|
||||
/* FIXME: the below seems conflict */
|
||||
/* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
|
||||
SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
|
||||
SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct alc_config_preset alc861_presets[] = {
|
||||
[ALC861_3ST] = {
|
||||
.mixers = { alc861_3ST_mixer },
|
||||
.init_verbs = { alc861_threestack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861_dac_nids),
|
||||
.dac_nids = alc861_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
||||
.channel_mode = alc861_threestack_modes,
|
||||
.need_dac_fix = 1,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.input_mux = &alc861_capture_source,
|
||||
},
|
||||
[ALC861_3ST_DIG] = {
|
||||
.mixers = { alc861_base_mixer },
|
||||
.init_verbs = { alc861_threestack_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_threestack_modes),
|
||||
.channel_mode = alc861_threestack_modes,
|
||||
.need_dac_fix = 1,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.input_mux = &alc861_capture_source,
|
||||
},
|
||||
[ALC861_6ST_DIG] = {
|
||||
.mixers = { alc861_base_mixer },
|
||||
.init_verbs = { alc861_base_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_8ch_modes),
|
||||
.channel_mode = alc861_8ch_modes,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.input_mux = &alc861_capture_source,
|
||||
},
|
||||
[ALC660_3ST] = {
|
||||
.mixers = { alc861_3ST_mixer },
|
||||
.init_verbs = { alc861_threestack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc660_dac_nids),
|
||||
.dac_nids = alc660_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
|
||||
.channel_mode = alc861_threestack_modes,
|
||||
.need_dac_fix = 1,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.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,
|
||||
},
|
||||
[ALC861_TOSHIBA] = {
|
||||
.mixers = { alc861_toshiba_mixer },
|
||||
.init_verbs = { alc861_base_init_verbs,
|
||||
alc861_toshiba_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861_dac_nids),
|
||||
.dac_nids = alc861_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
|
||||
.channel_mode = alc883_3ST_2ch_modes,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.input_mux = &alc861_capture_source,
|
||||
.unsol_event = alc861_toshiba_unsol_event,
|
||||
.init_hook = alc861_toshiba_automute,
|
||||
},
|
||||
[ALC861_ASUS] = {
|
||||
.mixers = { alc861_asus_mixer },
|
||||
.init_verbs = { alc861_asus_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_asus_modes),
|
||||
.channel_mode = alc861_asus_modes,
|
||||
.need_dac_fix = 1,
|
||||
.hp_nid = 0x06,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.input_mux = &alc861_capture_source,
|
||||
},
|
||||
[ALC861_ASUS_LAPTOP] = {
|
||||
.mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
|
||||
.init_verbs = { alc861_asus_init_verbs,
|
||||
alc861_asus_laptop_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(alc883_3ST_2ch_modes),
|
||||
.channel_mode = alc883_3ST_2ch_modes,
|
||||
.need_dac_fix = 1,
|
||||
.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
|
||||
.adc_nids = alc861_adc_nids,
|
||||
.input_mux = &alc861_capture_source,
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
* ALC660-VD/ALC861-VD quirk models
|
||||
* included by patch_realtek.c
|
||||
*/
|
||||
|
||||
/* ALC861-VD models */
|
||||
enum {
|
||||
ALC861VD_AUTO,
|
||||
ALC660VD_3ST,
|
||||
ALC660VD_3ST_DIG,
|
||||
ALC660VD_ASUS_V1S,
|
||||
ALC861VD_3ST,
|
||||
ALC861VD_3ST_DIG,
|
||||
ALC861VD_6ST_DIG,
|
||||
ALC861VD_LENOVO,
|
||||
ALC861VD_DALLAS,
|
||||
ALC861VD_HP,
|
||||
ALC861VD_MODEL_LAST,
|
||||
};
|
||||
|
||||
#define ALC861VD_DIGOUT_NID 0x06
|
||||
|
||||
static const hda_nid_t alc861vd_dac_nids[4] = {
|
||||
/* front, surr, clfe, side surr */
|
||||
0x02, 0x03, 0x04, 0x05
|
||||
};
|
||||
|
||||
/* dac_nids for ALC660vd are in a different order - according to
|
||||
* Realtek's driver.
|
||||
* This should probably result in a different mixer for 6stack models
|
||||
* of ALC660vd codecs, but for now there is only 3stack mixer
|
||||
* - and it is the same as in 861vd.
|
||||
* adc_nids in ALC660vd are (is) the same as in 861vd
|
||||
*/
|
||||
static const hda_nid_t alc660vd_dac_nids[3] = {
|
||||
/* front, rear, clfe, rear_surr */
|
||||
0x02, 0x04, 0x03
|
||||
};
|
||||
|
||||
static const hda_nid_t alc861vd_adc_nids[1] = {
|
||||
/* ADC0 */
|
||||
0x09,
|
||||
};
|
||||
|
||||
static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
|
||||
|
||||
/* input MUX */
|
||||
/* FIXME: should be a matrix-type input source selection */
|
||||
static const struct hda_input_mux alc861vd_capture_source = {
|
||||
.num_items = 4,
|
||||
.items = {
|
||||
{ "Mic", 0x0 },
|
||||
{ "Front Mic", 0x1 },
|
||||
{ "Line", 0x2 },
|
||||
{ "CD", 0x4 },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_input_mux alc861vd_dallas_capture_source = {
|
||||
.num_items = 2,
|
||||
.items = {
|
||||
{ "Mic", 0x0 },
|
||||
{ "Internal Mic", 0x1 },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_input_mux alc861vd_hp_capture_source = {
|
||||
.num_items = 2,
|
||||
.items = {
|
||||
{ "Front Mic", 0x0 },
|
||||
{ "ATAPI Mic", 0x1 },
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* 2ch mode
|
||||
*/
|
||||
static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
|
||||
{ 2, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* 6ch mode
|
||||
*/
|
||||
static const struct hda_verb alc861vd_6stack_ch6_init[] = {
|
||||
{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
|
||||
{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/*
|
||||
* 8ch mode
|
||||
*/
|
||||
static const struct hda_verb alc861vd_6stack_ch8_init[] = {
|
||||
{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
|
||||
{ 6, alc861vd_6stack_ch6_init },
|
||||
{ 8, alc861vd_6stack_ch8_init },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Channel Mode",
|
||||
.info = alc_ch_mode_info,
|
||||
.get = alc_ch_mode_get,
|
||||
.put = alc_ch_mode_put,
|
||||
},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
|
||||
* Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
|
||||
*/
|
||||
static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
|
||||
HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
|
||||
HDA_OUTPUT),
|
||||
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
|
||||
HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
/*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
|
||||
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* Pin assignment: Speaker=0x14, HP = 0x15,
|
||||
* Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
|
||||
*/
|
||||
static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* Pin assignment: Speaker=0x14, Line-out = 0x15,
|
||||
* Front Mic=0x18, ATAPI Mic = 0x19,
|
||||
*/
|
||||
static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/*
|
||||
* generic initialization of ADC, input mixers and output mixers
|
||||
*/
|
||||
static const struct hda_verb alc861vd_volume_init_verbs[] = {
|
||||
/*
|
||||
* Unmute ADC0 and set the default input to mic-in
|
||||
*/
|
||||
{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
|
||||
/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
|
||||
* the analog-loopback mixer widget
|
||||
*/
|
||||
/* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
|
||||
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
|
||||
/* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
|
||||
|
||||
/*
|
||||
* Set up output mixers (0x02 - 0x05)
|
||||
*/
|
||||
/* set vol=0 to output mixers */
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
|
||||
/* set up input amps for analog loopback */
|
||||
/* Amp Indices: DAC = 0, mixer = 1 */
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* 3-stack pin configuration:
|
||||
* front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
|
||||
*/
|
||||
static const struct hda_verb alc861vd_3stack_init_verbs[] = {
|
||||
/*
|
||||
* Set pin mode and muting
|
||||
*/
|
||||
/* set front pin widgets 0x14 for output */
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
|
||||
/* Mic (rear) pin: input vref at 80% */
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Front Mic pin: input vref at 80% */
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Line In pin: input */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Line-2 In: Headphone output (output 0 - 0x0c) */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* CD pin widget for input */
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* 6-stack pin configuration:
|
||||
*/
|
||||
static const struct hda_verb alc861vd_6stack_init_verbs[] = {
|
||||
/*
|
||||
* Set pin mode and muting
|
||||
*/
|
||||
/* set front pin widgets 0x14 for output */
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
|
||||
/* Rear Pin: output 1 (0x0d) */
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
|
||||
/* CLFE Pin: output 2 (0x0e) */
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
|
||||
/* Side Pin: output 3 (0x0f) */
|
||||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
|
||||
|
||||
/* Mic (rear) pin: input vref at 80% */
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Front Mic pin: input vref at 80% */
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Line In pin: input */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Line-2 In: Headphone output (output 0 - 0x0c) */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* CD pin widget for input */
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc861vd_eapd_verbs[] = {
|
||||
{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
|
||||
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
|
||||
{}
|
||||
};
|
||||
|
||||
static void alc861vd_lenovo_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->autocfg.hp_pins[0] = 0x1b;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
|
||||
{
|
||||
alc_hp_automute(codec);
|
||||
alc88x_simple_mic_automute(codec);
|
||||
}
|
||||
|
||||
static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
switch (res >> 26) {
|
||||
case ALC_MIC_EVENT:
|
||||
alc88x_simple_mic_automute(codec);
|
||||
break;
|
||||
default:
|
||||
alc_sku_unsol_event(codec, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hda_verb alc861vd_dallas_verbs[] = {
|
||||
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
|
||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
|
||||
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* toggle speaker-output according to the hp-jack state */
|
||||
static void alc861vd_dallas_setup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
spec->autocfg.hp_pins[0] = 0x15;
|
||||
spec->autocfg.speaker_pins[0] = 0x14;
|
||||
spec->automute = 1;
|
||||
spec->automute_mode = ALC_AUTOMUTE_AMP;
|
||||
}
|
||||
|
||||
/*
|
||||
* configuration and preset
|
||||
*/
|
||||
static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
|
||||
[ALC660VD_3ST] = "3stack-660",
|
||||
[ALC660VD_3ST_DIG] = "3stack-660-digout",
|
||||
[ALC660VD_ASUS_V1S] = "asus-v1s",
|
||||
[ALC861VD_3ST] = "3stack",
|
||||
[ALC861VD_3ST_DIG] = "3stack-digout",
|
||||
[ALC861VD_6ST_DIG] = "6stack-digout",
|
||||
[ALC861VD_LENOVO] = "lenovo",
|
||||
[ALC861VD_DALLAS] = "dallas",
|
||||
[ALC861VD_HP] = "hp",
|
||||
[ALC861VD_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
|
||||
SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
|
||||
SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
|
||||
/*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
|
||||
SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
|
||||
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
|
||||
SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
|
||||
SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
|
||||
/*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
|
||||
SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
|
||||
SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
|
||||
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
|
||||
SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
|
||||
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
|
||||
SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct alc_config_preset alc861vd_presets[] = {
|
||||
[ALC660VD_3ST] = {
|
||||
.mixers = { alc861vd_3st_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_3stack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
|
||||
.dac_nids = alc660vd_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
},
|
||||
[ALC660VD_3ST_DIG] = {
|
||||
.mixers = { alc861vd_3st_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_3stack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
|
||||
.dac_nids = alc660vd_dac_nids,
|
||||
.dig_out_nid = ALC861VD_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
},
|
||||
[ALC861VD_3ST] = {
|
||||
.mixers = { alc861vd_3st_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_3stack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
|
||||
.dac_nids = alc861vd_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
},
|
||||
[ALC861VD_3ST_DIG] = {
|
||||
.mixers = { alc861vd_3st_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_3stack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
|
||||
.dac_nids = alc861vd_dac_nids,
|
||||
.dig_out_nid = ALC861VD_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
},
|
||||
[ALC861VD_6ST_DIG] = {
|
||||
.mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_6stack_init_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
|
||||
.dac_nids = alc861vd_dac_nids,
|
||||
.dig_out_nid = ALC861VD_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
|
||||
.channel_mode = alc861vd_6stack_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
},
|
||||
[ALC861VD_LENOVO] = {
|
||||
.mixers = { alc861vd_lenovo_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_3stack_init_verbs,
|
||||
alc861vd_eapd_verbs,
|
||||
alc861vd_lenovo_unsol_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
|
||||
.dac_nids = alc660vd_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
.unsol_event = alc861vd_lenovo_unsol_event,
|
||||
.setup = alc861vd_lenovo_setup,
|
||||
.init_hook = alc861vd_lenovo_init_hook,
|
||||
},
|
||||
[ALC861VD_DALLAS] = {
|
||||
.mixers = { alc861vd_dallas_mixer },
|
||||
.init_verbs = { alc861vd_dallas_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
|
||||
.dac_nids = alc861vd_dac_nids,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_dallas_capture_source,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc861vd_dallas_setup,
|
||||
.init_hook = alc_hp_automute,
|
||||
},
|
||||
[ALC861VD_HP] = {
|
||||
.mixers = { alc861vd_hp_mixer },
|
||||
.init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
|
||||
.dac_nids = alc861vd_dac_nids,
|
||||
.dig_out_nid = ALC861VD_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_hp_capture_source,
|
||||
.unsol_event = alc_sku_unsol_event,
|
||||
.setup = alc861vd_dallas_setup,
|
||||
.init_hook = alc_hp_automute,
|
||||
},
|
||||
[ALC660VD_ASUS_V1S] = {
|
||||
.mixers = { alc861vd_lenovo_mixer },
|
||||
.init_verbs = { alc861vd_volume_init_verbs,
|
||||
alc861vd_3stack_init_verbs,
|
||||
alc861vd_eapd_verbs,
|
||||
alc861vd_lenovo_unsol_verbs },
|
||||
.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
|
||||
.dac_nids = alc660vd_dac_nids,
|
||||
.dig_out_nid = ALC861VD_DIGOUT_NID,
|
||||
.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
|
||||
.channel_mode = alc861vd_3stack_2ch_modes,
|
||||
.input_mux = &alc861vd_capture_source,
|
||||
.unsol_event = alc861vd_lenovo_unsol_event,
|
||||
.setup = alc861vd_lenovo_setup,
|
||||
.init_hook = alc861vd_lenovo_init_hook,
|
||||
},
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* Common codes for Realtek codec quirks
|
||||
* included by patch_realtek.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* configuration template - to be copied to the spec instance
|
||||
*/
|
||||
struct alc_config_preset {
|
||||
const struct snd_kcontrol_new *mixers[5]; /* should be identical size
|
||||
* with spec
|
||||
*/
|
||||
const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
|
||||
const struct hda_verb *init_verbs[5];
|
||||
unsigned int num_dacs;
|
||||
const hda_nid_t *dac_nids;
|
||||
hda_nid_t dig_out_nid; /* optional */
|
||||
hda_nid_t hp_nid; /* optional */
|
||||
const hda_nid_t *slave_dig_outs;
|
||||
unsigned int num_adc_nids;
|
||||
const hda_nid_t *adc_nids;
|
||||
const hda_nid_t *capsrc_nids;
|
||||
hda_nid_t dig_in_nid;
|
||||
unsigned int num_channel_mode;
|
||||
const struct hda_channel_mode *channel_mode;
|
||||
int need_dac_fix;
|
||||
int const_channel_count;
|
||||
unsigned int num_mux_defs;
|
||||
const struct hda_input_mux *input_mux;
|
||||
void (*unsol_event)(struct hda_codec *, unsigned int);
|
||||
void (*setup)(struct hda_codec *);
|
||||
void (*init_hook)(struct hda_codec *);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
const struct hda_amp_list *loopbacks;
|
||||
void (*power_hook)(struct hda_codec *codec);
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* channel mode setting
|
||||
*/
|
||||
static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct alc_spec *spec = codec->spec;
|
||||
return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
|
||||
spec->num_channel_mode);
|
||||
}
|
||||
|
||||
static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct alc_spec *spec = codec->spec;
|
||||
return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
|
||||
spec->num_channel_mode,
|
||||
spec->ext_channel_count);
|
||||
}
|
||||
|
||||
static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct alc_spec *spec = codec->spec;
|
||||
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
|
||||
spec->num_channel_mode,
|
||||
&spec->ext_channel_count);
|
||||
if (err >= 0 && !spec->const_channel_count) {
|
||||
spec->multiout.max_channels = spec->ext_channel_count;
|
||||
if (spec->need_dac_fix)
|
||||
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Control the mode of pin widget settings via the mixer. "pc" is used
|
||||
* instead of "%" to avoid consequences of accidentally treating the % as
|
||||
* being part of a format specifier. Maximum allowed length of a value is
|
||||
* 63 characters plus NULL terminator.
|
||||
*
|
||||
* Note: some retasking pin complexes seem to ignore requests for input
|
||||
* states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
|
||||
* are requested. Therefore order this list so that this behaviour will not
|
||||
* cause problems when mixer clients move through the enum sequentially.
|
||||
* NIDs 0x0f and 0x10 have been observed to have this behaviour as of
|
||||
* March 2006.
|
||||
*/
|
||||
static const char * const alc_pin_mode_names[] = {
|
||||
"Mic 50pc bias", "Mic 80pc bias",
|
||||
"Line in", "Line out", "Headphone out",
|
||||
};
|
||||
static const unsigned char alc_pin_mode_values[] = {
|
||||
PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
|
||||
};
|
||||
/* The control can present all 5 options, or it can limit the options based
|
||||
* in the pin being assumed to be exclusively an input or an output pin. In
|
||||
* addition, "input" pins may or may not process the mic bias option
|
||||
* depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
|
||||
* accept requests for bias as of chip versions up to March 2006) and/or
|
||||
* wiring in the computer.
|
||||
*/
|
||||
#define ALC_PIN_DIR_IN 0x00
|
||||
#define ALC_PIN_DIR_OUT 0x01
|
||||
#define ALC_PIN_DIR_INOUT 0x02
|
||||
#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
|
||||
#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
|
||||
|
||||
/* Info about the pin modes supported by the different pin direction modes.
|
||||
* For each direction the minimum and maximum values are given.
|
||||
*/
|
||||
static const signed char alc_pin_mode_dir_info[5][2] = {
|
||||
{ 0, 2 }, /* ALC_PIN_DIR_IN */
|
||||
{ 3, 4 }, /* ALC_PIN_DIR_OUT */
|
||||
{ 0, 4 }, /* ALC_PIN_DIR_INOUT */
|
||||
{ 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
|
||||
{ 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
|
||||
};
|
||||
#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
|
||||
#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
|
||||
#define alc_pin_mode_n_items(_dir) \
|
||||
(alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
|
||||
|
||||
static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
unsigned int item_num = uinfo->value.enumerated.item;
|
||||
unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
|
||||
|
||||
if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
|
||||
item_num = alc_pin_mode_min(dir);
|
||||
strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
unsigned int i;
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
|
||||
long *valp = ucontrol->value.integer.value;
|
||||
unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL,
|
||||
0x00);
|
||||
|
||||
/* Find enumerated value for current pinctl setting */
|
||||
i = alc_pin_mode_min(dir);
|
||||
while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
|
||||
i++;
|
||||
*valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
signed int change;
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
|
||||
long val = *ucontrol->value.integer.value;
|
||||
unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL,
|
||||
0x00);
|
||||
|
||||
if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
|
||||
val = alc_pin_mode_min(dir);
|
||||
|
||||
change = pinctl != alc_pin_mode_values[val];
|
||||
if (change) {
|
||||
/* Set pin mode to that requested */
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
alc_pin_mode_values[val]);
|
||||
|
||||
/* Also enable the retasking pin's input/output as required
|
||||
* for the requested pin mode. Enum values of 2 or less are
|
||||
* input modes.
|
||||
*
|
||||
* Dynamically switching the input/output buffers probably
|
||||
* reduces noise slightly (particularly on input) so we'll
|
||||
* do it. However, having both input and output buffers
|
||||
* enabled simultaneously doesn't seem to be problematic if
|
||||
* this turns out to be necessary in the future.
|
||||
*/
|
||||
if (val <= 2) {
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, HDA_AMP_MUTE);
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
|
||||
HDA_AMP_MUTE, 0);
|
||||
} else {
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
|
||||
HDA_AMP_MUTE, HDA_AMP_MUTE);
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, 0);
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
#define ALC_PIN_MODE(xname, nid, dir) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
|
||||
.info = alc_pin_mode_info, \
|
||||
.get = alc_pin_mode_get, \
|
||||
.put = alc_pin_mode_put, \
|
||||
.private_value = nid | (dir<<16) }
|
||||
|
||||
/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
|
||||
* together using a mask with more than one bit set. This control is
|
||||
* currently used only by the ALC260 test model. At this stage they are not
|
||||
* needed for any "production" models.
|
||||
*/
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define alc_gpio_data_info snd_ctl_boolean_mono_info
|
||||
|
||||
static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
long *valp = ucontrol->value.integer.value;
|
||||
unsigned int val = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_DATA, 0x00);
|
||||
|
||||
*valp = (val & mask) != 0;
|
||||
return 0;
|
||||
}
|
||||
static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
signed int change;
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
long val = *ucontrol->value.integer.value;
|
||||
unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_DATA,
|
||||
0x00);
|
||||
|
||||
/* Set/unset the masked GPIO bit(s) as needed */
|
||||
change = (val == 0 ? 0 : mask) != (gpio_data & mask);
|
||||
if (val == 0)
|
||||
gpio_data &= ~mask;
|
||||
else
|
||||
gpio_data |= mask;
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_GPIO_DATA, gpio_data);
|
||||
|
||||
return change;
|
||||
}
|
||||
#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
|
||||
.info = alc_gpio_data_info, \
|
||||
.get = alc_gpio_data_get, \
|
||||
.put = alc_gpio_data_put, \
|
||||
.private_value = nid | (mask<<16) }
|
||||
#endif /* CONFIG_SND_DEBUG */
|
||||
|
||||
/* A switch control to allow the enabling of the digital IO pins on the
|
||||
* ALC260. This is incredibly simplistic; the intention of this control is
|
||||
* to provide something in the test model allowing digital outputs to be
|
||||
* identified if present. If models are found which can utilise these
|
||||
* outputs a more complete mixer control can be devised for those models if
|
||||
* necessary.
|
||||
*/
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
|
||||
|
||||
static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
long *valp = ucontrol->value.integer.value;
|
||||
unsigned int val = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_DIGI_CONVERT_1, 0x00);
|
||||
|
||||
*valp = (val & mask) != 0;
|
||||
return 0;
|
||||
}
|
||||
static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
signed int change;
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
long val = *ucontrol->value.integer.value;
|
||||
unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_DIGI_CONVERT_1,
|
||||
0x00);
|
||||
|
||||
/* Set/unset the masked control bit(s) as needed */
|
||||
change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
|
||||
if (val==0)
|
||||
ctrl_data &= ~mask;
|
||||
else
|
||||
ctrl_data |= mask;
|
||||
snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
|
||||
ctrl_data);
|
||||
|
||||
return change;
|
||||
}
|
||||
#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
|
||||
.info = alc_spdif_ctrl_info, \
|
||||
.get = alc_spdif_ctrl_get, \
|
||||
.put = alc_spdif_ctrl_put, \
|
||||
.private_value = nid | (mask<<16) }
|
||||
#endif /* CONFIG_SND_DEBUG */
|
||||
|
||||
/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
|
||||
* Again, this is only used in the ALC26x test models to help identify when
|
||||
* the EAPD line must be asserted for features to work.
|
||||
*/
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
|
||||
|
||||
static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
long *valp = ucontrol->value.integer.value;
|
||||
unsigned int val = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_EAPD_BTLENABLE, 0x00);
|
||||
|
||||
*valp = (val & mask) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int change;
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value & 0xffff;
|
||||
unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
long val = *ucontrol->value.integer.value;
|
||||
unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_EAPD_BTLENABLE,
|
||||
0x00);
|
||||
|
||||
/* Set/unset the masked control bit(s) as needed */
|
||||
change = (!val ? 0 : mask) != (ctrl_data & mask);
|
||||
if (!val)
|
||||
ctrl_data &= ~mask;
|
||||
else
|
||||
ctrl_data |= mask;
|
||||
snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
||||
ctrl_data);
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
|
||||
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
|
||||
.info = alc_eapd_ctrl_info, \
|
||||
.get = alc_eapd_ctrl_get, \
|
||||
.put = alc_eapd_ctrl_put, \
|
||||
.private_value = nid | (mask<<16) }
|
||||
#endif /* CONFIG_SND_DEBUG */
|
||||
|
||||
static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
|
||||
if (!cfg->line_outs) {
|
||||
while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
|
||||
cfg->line_out_pins[cfg->line_outs])
|
||||
cfg->line_outs++;
|
||||
}
|
||||
if (!cfg->speaker_outs) {
|
||||
while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
|
||||
cfg->speaker_pins[cfg->speaker_outs])
|
||||
cfg->speaker_outs++;
|
||||
}
|
||||
if (!cfg->hp_outs) {
|
||||
while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
|
||||
cfg->hp_pins[cfg->hp_outs])
|
||||
cfg->hp_outs++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set up from the preset table
|
||||
*/
|
||||
static void setup_preset(struct hda_codec *codec,
|
||||
const struct alc_config_preset *preset)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
|
||||
add_mixer(spec, preset->mixers[i]);
|
||||
spec->cap_mixer = preset->cap_mixer;
|
||||
for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
|
||||
i++)
|
||||
add_verb(spec, preset->init_verbs[i]);
|
||||
|
||||
spec->channel_mode = preset->channel_mode;
|
||||
spec->num_channel_mode = preset->num_channel_mode;
|
||||
spec->need_dac_fix = preset->need_dac_fix;
|
||||
spec->const_channel_count = preset->const_channel_count;
|
||||
|
||||
if (preset->const_channel_count)
|
||||
spec->multiout.max_channels = preset->const_channel_count;
|
||||
else
|
||||
spec->multiout.max_channels = spec->channel_mode[0].channels;
|
||||
spec->ext_channel_count = spec->channel_mode[0].channels;
|
||||
|
||||
spec->multiout.num_dacs = preset->num_dacs;
|
||||
spec->multiout.dac_nids = preset->dac_nids;
|
||||
spec->multiout.dig_out_nid = preset->dig_out_nid;
|
||||
spec->multiout.slave_dig_outs = preset->slave_dig_outs;
|
||||
spec->multiout.hp_nid = preset->hp_nid;
|
||||
|
||||
spec->num_mux_defs = preset->num_mux_defs;
|
||||
if (!spec->num_mux_defs)
|
||||
spec->num_mux_defs = 1;
|
||||
spec->input_mux = preset->input_mux;
|
||||
|
||||
spec->num_adc_nids = preset->num_adc_nids;
|
||||
spec->adc_nids = preset->adc_nids;
|
||||
spec->capsrc_nids = preset->capsrc_nids;
|
||||
spec->dig_in_nid = preset->dig_in_nid;
|
||||
|
||||
spec->unsol_event = preset->unsol_event;
|
||||
spec->init_hook = preset->init_hook;
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->power_hook = preset->power_hook;
|
||||
spec->loopback.amplist = preset->loopbacks;
|
||||
#endif
|
||||
|
||||
if (preset->setup)
|
||||
preset->setup(codec);
|
||||
|
||||
alc_fixup_autocfg_pin_nums(codec);
|
||||
}
|
||||
|
||||
|
||||
/* auto-toggle front mic */
|
||||
static void alc88x_simple_mic_automute(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
unsigned char bits;
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x18);
|
||||
bits = present ? HDA_AMP_MUTE : 0;
|
||||
snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
|
@ -243,7 +243,8 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
|
|||
{
|
||||
unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
|
||||
unsigned int res;
|
||||
codec_exec_verb(codec, cmd, &res);
|
||||
if (codec_exec_verb(codec, cmd, &res))
|
||||
return -1;
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_read);
|
||||
|
@ -307,14 +308,65 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
|
||||
|
||||
static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
|
||||
static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
|
||||
hda_nid_t *src, int len);
|
||||
/* look up the cached results */
|
||||
static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
|
||||
{
|
||||
int i, len;
|
||||
for (i = 0; i < array->used; ) {
|
||||
hda_nid_t *p = snd_array_elem(array, i);
|
||||
if (nid == *p)
|
||||
return p;
|
||||
len = p[1];
|
||||
i += len + 2;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_get_connections - get connection list
|
||||
* snd_hda_get_conn_list - get connection list
|
||||
* @codec: the HDA codec
|
||||
* @nid: NID to parse
|
||||
* @listp: the pointer to store NID list
|
||||
*
|
||||
* Parses the connection list of the given widget and stores the list
|
||||
* of NIDs.
|
||||
*
|
||||
* Returns the number of connections, or a negative error code.
|
||||
*/
|
||||
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
|
||||
const hda_nid_t **listp)
|
||||
{
|
||||
struct snd_array *array = &codec->conn_lists;
|
||||
int len, err;
|
||||
hda_nid_t list[HDA_MAX_CONNECTIONS];
|
||||
hda_nid_t *p;
|
||||
bool added = false;
|
||||
|
||||
again:
|
||||
/* if the connection-list is already cached, read it */
|
||||
p = lookup_conn_list(array, nid);
|
||||
if (p) {
|
||||
if (listp)
|
||||
*listp = p + 2;
|
||||
return p[1];
|
||||
}
|
||||
if (snd_BUG_ON(added))
|
||||
return -EINVAL;
|
||||
|
||||
/* read the connection and add to the cache */
|
||||
len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
|
||||
if (len < 0)
|
||||
return len;
|
||||
err = snd_hda_override_conn_list(codec, nid, len, list);
|
||||
if (err < 0)
|
||||
return err;
|
||||
added = true;
|
||||
goto again;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
|
||||
|
||||
/**
|
||||
* snd_hda_get_connections - copy connection list
|
||||
* @codec: the HDA codec
|
||||
* @nid: NID to parse
|
||||
* @conn_list: connection list array
|
||||
|
@ -328,42 +380,35 @@ static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
|
|||
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns)
|
||||
{
|
||||
struct snd_array *array = &codec->conn_lists;
|
||||
int i, len, old_used;
|
||||
hda_nid_t list[HDA_MAX_CONNECTIONS];
|
||||
const hda_nid_t *list;
|
||||
int len = snd_hda_get_conn_list(codec, nid, &list);
|
||||
|
||||
/* look up the cached results */
|
||||
for (i = 0; i < array->used; ) {
|
||||
hda_nid_t *p = snd_array_elem(array, i);
|
||||
len = p[1];
|
||||
if (nid == *p)
|
||||
return copy_conn_list(nid, conn_list, max_conns,
|
||||
p + 2, len);
|
||||
i += len + 2;
|
||||
}
|
||||
|
||||
len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
|
||||
if (len < 0)
|
||||
if (len <= 0)
|
||||
return len;
|
||||
|
||||
/* add to the cache */
|
||||
old_used = array->used;
|
||||
if (!add_conn_list(array, nid) || !add_conn_list(array, len))
|
||||
goto error_add;
|
||||
for (i = 0; i < len; i++)
|
||||
if (!add_conn_list(array, list[i]))
|
||||
goto error_add;
|
||||
|
||||
return copy_conn_list(nid, conn_list, max_conns, list, len);
|
||||
|
||||
error_add:
|
||||
array->used = old_used;
|
||||
return -ENOMEM;
|
||||
if (len > max_conns) {
|
||||
snd_printk(KERN_ERR "hda_codec: "
|
||||
"Too many connections %d for NID 0x%x\n",
|
||||
len, nid);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(conn_list, list, len * sizeof(hda_nid_t));
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_connections);
|
||||
|
||||
static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns)
|
||||
/**
|
||||
* snd_hda_get_raw_connections - copy connection list without cache
|
||||
* @codec: the HDA codec
|
||||
* @nid: NID to parse
|
||||
* @conn_list: connection list array
|
||||
* @max_conns: max. number of connections to store
|
||||
*
|
||||
* Like snd_hda_get_connections(), copy the connection list but without
|
||||
* checking through the connection-list cache.
|
||||
* Currently called only from hda_proc.c, so not exported.
|
||||
*/
|
||||
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns)
|
||||
{
|
||||
unsigned int parm;
|
||||
int i, conn_len, conns;
|
||||
|
@ -376,11 +421,8 @@ static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
|||
|
||||
wcaps = get_wcaps(codec, nid);
|
||||
if (!(wcaps & AC_WCAP_CONN_LIST) &&
|
||||
get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
|
||||
snd_printk(KERN_WARNING "hda_codec: "
|
||||
"connection list not available for 0x%x\n", nid);
|
||||
return -EINVAL;
|
||||
}
|
||||
get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
|
||||
return 0;
|
||||
|
||||
parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
|
||||
if (parm & AC_CLIST_LONG) {
|
||||
|
@ -470,18 +512,77 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
|
||||
hda_nid_t *src, int len)
|
||||
/**
|
||||
* snd_hda_override_conn_list - add/modify the connection-list to cache
|
||||
* @codec: the HDA codec
|
||||
* @nid: NID to parse
|
||||
* @len: number of connection list entries
|
||||
* @list: the list of connection entries
|
||||
*
|
||||
* Add or modify the given connection-list to the cache. If the corresponding
|
||||
* cache already exists, invalidate it and append a new one.
|
||||
*
|
||||
* Returns zero or a negative error code.
|
||||
*/
|
||||
int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
|
||||
const hda_nid_t *list)
|
||||
{
|
||||
if (len > max_dst) {
|
||||
snd_printk(KERN_ERR "hda_codec: "
|
||||
"Too many connections %d for NID 0x%x\n",
|
||||
len, nid);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(dst, src, len * sizeof(hda_nid_t));
|
||||
return len;
|
||||
struct snd_array *array = &codec->conn_lists;
|
||||
hda_nid_t *p;
|
||||
int i, old_used;
|
||||
|
||||
p = lookup_conn_list(array, nid);
|
||||
if (p)
|
||||
*p = -1; /* invalidate the old entry */
|
||||
|
||||
old_used = array->used;
|
||||
if (!add_conn_list(array, nid) || !add_conn_list(array, len))
|
||||
goto error_add;
|
||||
for (i = 0; i < len; i++)
|
||||
if (!add_conn_list(array, list[i]))
|
||||
goto error_add;
|
||||
return 0;
|
||||
|
||||
error_add:
|
||||
array->used = old_used;
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
|
||||
|
||||
/**
|
||||
* snd_hda_get_conn_index - get the connection index of the given NID
|
||||
* @codec: the HDA codec
|
||||
* @mux: NID containing the list
|
||||
* @nid: NID to select
|
||||
* @recursive: 1 when searching NID recursively, otherwise 0
|
||||
*
|
||||
* Parses the connection list of the widget @mux and checks whether the
|
||||
* widget @nid is present. If it is, return the connection index.
|
||||
* Otherwise it returns -1.
|
||||
*/
|
||||
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid, int recursive)
|
||||
{
|
||||
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
|
||||
int i, nums;
|
||||
|
||||
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
|
||||
for (i = 0; i < nums; i++)
|
||||
if (conn[i] == nid)
|
||||
return i;
|
||||
if (!recursive)
|
||||
return -1;
|
||||
if (recursive > 5) {
|
||||
snd_printd("hda_codec: too deep connection for 0x%x\n", nid);
|
||||
return -1;
|
||||
}
|
||||
recursive++;
|
||||
for (i = 0; i < nums; i++)
|
||||
if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
|
||||
|
||||
/**
|
||||
* snd_hda_queue_unsol_event - add an unsolicited event to queue
|
||||
|
@ -1083,6 +1184,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
|||
snd_array_free(&codec->mixers);
|
||||
snd_array_free(&codec->nids);
|
||||
snd_array_free(&codec->conn_lists);
|
||||
snd_array_free(&codec->spdif_out);
|
||||
codec->bus->caddr_tbl[codec->addr] = NULL;
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
|
@ -1144,6 +1246,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
|
|||
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
|
||||
snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
|
||||
snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
|
||||
snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
|
||||
if (codec->bus->modelname) {
|
||||
codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
|
||||
if (!codec->modelname) {
|
||||
|
@ -2555,11 +2658,13 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
int idx = kcontrol->private_value;
|
||||
struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
||||
|
||||
ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;
|
||||
ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;
|
||||
ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;
|
||||
ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;
|
||||
ucontrol->value.iec958.status[0] = spdif->status & 0xff;
|
||||
ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
|
||||
ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
|
||||
ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2644,23 +2749,23 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value;
|
||||
int idx = kcontrol->private_value;
|
||||
struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
||||
hda_nid_t nid = spdif->nid;
|
||||
unsigned short val;
|
||||
int change;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
codec->spdif_status = ucontrol->value.iec958.status[0] |
|
||||
spdif->status = ucontrol->value.iec958.status[0] |
|
||||
((unsigned int)ucontrol->value.iec958.status[1] << 8) |
|
||||
((unsigned int)ucontrol->value.iec958.status[2] << 16) |
|
||||
((unsigned int)ucontrol->value.iec958.status[3] << 24);
|
||||
val = convert_from_spdif_status(codec->spdif_status);
|
||||
val |= codec->spdif_ctls & 1;
|
||||
change = codec->spdif_ctls != val;
|
||||
codec->spdif_ctls = val;
|
||||
|
||||
if (change)
|
||||
val = convert_from_spdif_status(spdif->status);
|
||||
val |= spdif->ctls & 1;
|
||||
change = spdif->ctls != val;
|
||||
spdif->ctls = val;
|
||||
if (change && nid != (u16)-1)
|
||||
set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
|
||||
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
return change;
|
||||
}
|
||||
|
@ -2671,33 +2776,42 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
int idx = kcontrol->private_value;
|
||||
struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
||||
|
||||
ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE;
|
||||
ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid,
|
||||
int dig1, int dig2)
|
||||
{
|
||||
set_dig_out_convert(codec, nid, dig1, dig2);
|
||||
/* unmute amp switch (if any) */
|
||||
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
|
||||
(dig1 & AC_DIG1_ENABLE))
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, 0);
|
||||
}
|
||||
|
||||
static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = kcontrol->private_value;
|
||||
int idx = kcontrol->private_value;
|
||||
struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
||||
hda_nid_t nid = spdif->nid;
|
||||
unsigned short val;
|
||||
int change;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
val = codec->spdif_ctls & ~AC_DIG1_ENABLE;
|
||||
val = spdif->ctls & ~AC_DIG1_ENABLE;
|
||||
if (ucontrol->value.integer.value[0])
|
||||
val |= AC_DIG1_ENABLE;
|
||||
change = codec->spdif_ctls != val;
|
||||
if (change) {
|
||||
codec->spdif_ctls = val;
|
||||
set_dig_out_convert(codec, nid, val & 0xff, -1);
|
||||
/* unmute amp switch (if any) */
|
||||
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
|
||||
(val & AC_DIG1_ENABLE))
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, 0);
|
||||
}
|
||||
change = spdif->ctls != val;
|
||||
spdif->ctls = val;
|
||||
if (change && nid != (u16)-1)
|
||||
set_spdif_ctls(codec, nid, val & 0xff, -1);
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
return change;
|
||||
}
|
||||
|
@ -2744,36 +2858,79 @@ static struct snd_kcontrol_new dig_mixes[] = {
|
|||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
|
||||
int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
|
||||
hda_nid_t associated_nid,
|
||||
hda_nid_t cvt_nid)
|
||||
{
|
||||
int err;
|
||||
struct snd_kcontrol *kctl;
|
||||
struct snd_kcontrol_new *dig_mix;
|
||||
int idx;
|
||||
struct hda_spdif_out *spdif;
|
||||
|
||||
idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
|
||||
if (idx < 0) {
|
||||
printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
spdif = snd_array_new(&codec->spdif_out);
|
||||
for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
|
||||
kctl = snd_ctl_new1(dig_mix, codec);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
kctl->id.index = idx;
|
||||
kctl->private_value = nid;
|
||||
err = snd_hda_ctl_add(codec, nid, kctl);
|
||||
kctl->private_value = codec->spdif_out.used - 1;
|
||||
err = snd_hda_ctl_add(codec, associated_nid, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
codec->spdif_ctls =
|
||||
snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_DIGI_CONVERT_1, 0);
|
||||
codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
|
||||
spdif->nid = cvt_nid;
|
||||
spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0,
|
||||
AC_VERB_GET_DIGI_CONVERT_1, 0);
|
||||
spdif->status = convert_to_spdif_status(spdif->ctls);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
|
||||
|
||||
struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < codec->spdif_out.used; i++) {
|
||||
struct hda_spdif_out *spdif =
|
||||
snd_array_elem(&codec->spdif_out, i);
|
||||
if (spdif->nid == nid)
|
||||
return spdif;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
|
||||
|
||||
void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
|
||||
{
|
||||
struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
spdif->nid = (u16)-1;
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
|
||||
|
||||
void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
|
||||
{
|
||||
struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
||||
unsigned short val;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
if (spdif->nid != nid) {
|
||||
spdif->nid = nid;
|
||||
val = spdif->ctls;
|
||||
set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
|
||||
}
|
||||
mutex_unlock(&codec->spdif_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign);
|
||||
|
||||
/*
|
||||
* SPDIF sharing with analog output
|
||||
*/
|
||||
|
@ -3356,7 +3513,7 @@ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
|
|||
*
|
||||
* Returns 0 if successful, otherwise a negative error code.
|
||||
*/
|
||||
static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||
int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||
u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
|
||||
{
|
||||
unsigned int i, val, wcaps;
|
||||
|
@ -3448,6 +3605,7 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm);
|
||||
|
||||
/**
|
||||
* snd_hda_is_supported_format - Check the validity of the format
|
||||
|
@ -4177,10 +4335,12 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
|
|||
static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int stream_tag, unsigned int format)
|
||||
{
|
||||
struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid);
|
||||
|
||||
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
|
||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||
if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
|
||||
set_dig_out_convert(codec, nid,
|
||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
|
||||
spdif->ctls & ~AC_DIG1_ENABLE & 0xff,
|
||||
-1);
|
||||
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
|
||||
if (codec->slave_dig_outs) {
|
||||
|
@ -4190,9 +4350,9 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
format);
|
||||
}
|
||||
/* turn on again (if needed) */
|
||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||
if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
|
||||
set_dig_out_convert(codec, nid,
|
||||
codec->spdif_ctls & 0xff, -1);
|
||||
spdif->ctls & 0xff, -1);
|
||||
}
|
||||
|
||||
static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
|
||||
|
@ -4348,6 +4508,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
|||
{
|
||||
const hda_nid_t *nids = mout->dac_nids;
|
||||
int chs = substream->runtime->channels;
|
||||
struct hda_spdif_out *spdif =
|
||||
snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
|
||||
int i;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
|
@ -4356,7 +4518,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
|||
if (chs == 2 &&
|
||||
snd_hda_is_supported_format(codec, mout->dig_out_nid,
|
||||
format) &&
|
||||
!(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
|
||||
!(spdif->status & IEC958_AES0_NONAUDIO)) {
|
||||
mout->dig_out_used = HDA_DIG_ANALOG_DUP;
|
||||
setup_dig_out_stream(codec, mout->dig_out_nid,
|
||||
stream_tag, format);
|
||||
|
@ -4528,7 +4690,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
unsigned int wid_caps = get_wcaps(codec, nid);
|
||||
unsigned int wid_type = get_wcaps_type(wid_caps);
|
||||
unsigned int def_conf;
|
||||
short assoc, loc;
|
||||
short assoc, loc, conn, dev;
|
||||
|
||||
/* read all default configuration for pin complex */
|
||||
if (wid_type != AC_WID_PIN)
|
||||
|
@ -4538,10 +4700,19 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
continue;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
|
||||
conn = get_defcfg_connect(def_conf);
|
||||
if (conn == AC_JACK_PORT_NONE)
|
||||
continue;
|
||||
loc = get_defcfg_location(def_conf);
|
||||
switch (get_defcfg_device(def_conf)) {
|
||||
dev = get_defcfg_device(def_conf);
|
||||
|
||||
/* workaround for buggy BIOS setups */
|
||||
if (dev == AC_JACK_LINE_OUT) {
|
||||
if (conn == AC_JACK_PORT_FIXED)
|
||||
dev = AC_JACK_SPEAKER;
|
||||
}
|
||||
|
||||
switch (dev) {
|
||||
case AC_JACK_LINE_OUT:
|
||||
seq = get_defcfg_sequence(def_conf);
|
||||
assoc = get_defcfg_association(def_conf);
|
||||
|
@ -4957,17 +5128,15 @@ void *snd_array_new(struct snd_array *array)
|
|||
{
|
||||
if (array->used >= array->alloced) {
|
||||
int num = array->alloced + array->alloc_align;
|
||||
int size = (num + 1) * array->elem_size;
|
||||
int oldsize = array->alloced * array->elem_size;
|
||||
void *nlist;
|
||||
if (snd_BUG_ON(num >= 4096))
|
||||
return NULL;
|
||||
nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL);
|
||||
nlist = krealloc(array->list, size, GFP_KERNEL);
|
||||
if (!nlist)
|
||||
return NULL;
|
||||
if (array->list) {
|
||||
memcpy(nlist, array->list,
|
||||
array->elem_size * array->alloced);
|
||||
kfree(array->list);
|
||||
}
|
||||
memset(nlist + oldsize, 0, size - oldsize);
|
||||
array->list = nlist;
|
||||
array->alloced = num;
|
||||
}
|
||||
|
|
|
@ -829,8 +829,7 @@ struct hda_codec {
|
|||
|
||||
struct mutex spdif_mutex;
|
||||
struct mutex control_mutex;
|
||||
unsigned int spdif_status; /* IEC958 status bits */
|
||||
unsigned short spdif_ctls; /* SPDIF control bits */
|
||||
struct snd_array spdif_out;
|
||||
unsigned int spdif_in_enable; /* SPDIF input enable? */
|
||||
const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
|
||||
struct snd_array init_pins; /* initial (BIOS) pin configurations */
|
||||
|
@ -904,6 +903,16 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
|
|||
hda_nid_t *start_id);
|
||||
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
|
||||
const hda_nid_t **listp);
|
||||
int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
|
||||
const hda_nid_t *list);
|
||||
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid, int recursive);
|
||||
int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||
u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
|
||||
|
||||
struct hda_verb {
|
||||
hda_nid_t nid;
|
||||
|
@ -947,6 +956,17 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
|
|||
hda_nid_t nid, unsigned int cfg); /* for hwdep */
|
||||
void snd_hda_shutup_pins(struct hda_codec *codec);
|
||||
|
||||
/* SPDIF controls */
|
||||
struct hda_spdif_out {
|
||||
hda_nid_t nid; /* Converter nid values relate to */
|
||||
unsigned int status; /* IEC958 status bits */
|
||||
unsigned short ctls; /* SPDIF control bits */
|
||||
};
|
||||
struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
|
||||
hda_nid_t nid);
|
||||
void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx);
|
||||
void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
|
||||
|
||||
/*
|
||||
* Mixer
|
||||
*/
|
||||
|
@ -997,17 +1017,15 @@ int snd_hda_suspend(struct hda_bus *bus);
|
|||
int snd_hda_resume(struct hda_bus *bus);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static inline
|
||||
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (codec->patch_ops.check_power_status)
|
||||
return codec->patch_ops.check_power_status(codec, nid);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define hda_call_check_power_status(codec, nid) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* get widget information
|
||||
|
|
|
@ -580,43 +580,45 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
|
|||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
/* update PCM info based on ELD */
|
||||
void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
|
||||
struct hda_pcm_stream *codec_pars)
|
||||
void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
|
||||
struct hda_pcm_stream *hinfo)
|
||||
{
|
||||
u32 rates;
|
||||
u64 formats;
|
||||
unsigned int maxbps;
|
||||
unsigned int channels_max;
|
||||
int i;
|
||||
|
||||
/* assume basic audio support (the basic audio flag is not in ELD;
|
||||
* however, all audio capable sinks are required to support basic
|
||||
* audio) */
|
||||
pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
|
||||
pcm->formats = SNDRV_PCM_FMTBIT_S16_LE;
|
||||
pcm->maxbps = 16;
|
||||
pcm->channels_max = 2;
|
||||
rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000;
|
||||
formats = SNDRV_PCM_FMTBIT_S16_LE;
|
||||
maxbps = 16;
|
||||
channels_max = 2;
|
||||
for (i = 0; i < eld->sad_count; i++) {
|
||||
struct cea_sad *a = &eld->sad[i];
|
||||
pcm->rates |= a->rates;
|
||||
if (a->channels > pcm->channels_max)
|
||||
pcm->channels_max = a->channels;
|
||||
rates |= a->rates;
|
||||
if (a->channels > channels_max)
|
||||
channels_max = a->channels;
|
||||
if (a->format == AUDIO_CODING_TYPE_LPCM) {
|
||||
if (a->sample_bits & AC_SUPPCM_BITS_20) {
|
||||
pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
|
||||
if (pcm->maxbps < 20)
|
||||
pcm->maxbps = 20;
|
||||
formats |= SNDRV_PCM_FMTBIT_S32_LE;
|
||||
if (maxbps < 20)
|
||||
maxbps = 20;
|
||||
}
|
||||
if (a->sample_bits & AC_SUPPCM_BITS_24) {
|
||||
pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
|
||||
if (pcm->maxbps < 24)
|
||||
pcm->maxbps = 24;
|
||||
formats |= SNDRV_PCM_FMTBIT_S32_LE;
|
||||
if (maxbps < 24)
|
||||
maxbps = 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!codec_pars)
|
||||
return;
|
||||
|
||||
/* restrict the parameters by the values the codec provides */
|
||||
pcm->rates &= codec_pars->rates;
|
||||
pcm->formats &= codec_pars->formats;
|
||||
pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
|
||||
pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
|
||||
hinfo->rates &= rates;
|
||||
hinfo->formats &= formats;
|
||||
hinfo->maxbps = min(hinfo->maxbps, maxbps);
|
||||
hinfo->channels_max = min(hinfo->channels_max, channels_max);
|
||||
}
|
||||
|
|
|
@ -177,7 +177,8 @@ MODULE_DESCRIPTION("Intel HDA driver");
|
|||
#define ICH6_REG_INTCTL 0x20
|
||||
#define ICH6_REG_INTSTS 0x24
|
||||
#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
|
||||
#define ICH6_REG_SYNC 0x34
|
||||
#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */
|
||||
#define ICH6_REG_SSYNC 0x38
|
||||
#define ICH6_REG_CORBLBASE 0x40
|
||||
#define ICH6_REG_CORBUBASE 0x44
|
||||
#define ICH6_REG_CORBWP 0x48
|
||||
|
@ -479,6 +480,7 @@ enum {
|
|||
#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */
|
||||
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
|
||||
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
|
||||
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
|
||||
|
||||
/* quirks for ATI SB / AMD Hudson */
|
||||
#define AZX_DCAPS_PRESET_ATI_SB \
|
||||
|
@ -1706,13 +1708,16 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int bufsize, period_bytes, format_val, stream_tag;
|
||||
int err;
|
||||
struct hda_spdif_out *spdif =
|
||||
snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
|
||||
unsigned short ctls = spdif ? spdif->ctls : 0;
|
||||
|
||||
azx_stream_reset(chip, azx_dev);
|
||||
format_val = snd_hda_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
hinfo->maxbps,
|
||||
apcm->codec->spdif_ctls);
|
||||
ctls);
|
||||
if (!format_val) {
|
||||
snd_printk(KERN_ERR SFX
|
||||
"invalid format_val, rate=%d, ch=%d, format=%d\n",
|
||||
|
@ -1792,7 +1797,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
spin_lock(&chip->reg_lock);
|
||||
if (nsync > 1) {
|
||||
/* first, set SYNC bits of corresponding streams */
|
||||
azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
|
||||
if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
|
||||
azx_writel(chip, OLD_SSYNC,
|
||||
azx_readl(chip, OLD_SSYNC) | sbits);
|
||||
else
|
||||
azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
|
||||
}
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s->pcm->card != substream->pcm->card)
|
||||
|
@ -1848,7 +1857,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
if (nsync > 1) {
|
||||
spin_lock(&chip->reg_lock);
|
||||
/* reset SYNC bits */
|
||||
azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
|
||||
if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
|
||||
azx_writel(chip, OLD_SSYNC,
|
||||
azx_readl(chip, OLD_SSYNC) & ~sbits);
|
||||
else
|
||||
azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1863,7 +1876,7 @@ static unsigned int azx_via_get_position(struct azx *chip,
|
|||
unsigned int fifo_size;
|
||||
|
||||
link_pos = azx_sd_readl(azx_dev, SD_LPIB);
|
||||
if (azx_dev->index >= 4) {
|
||||
if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
/* Playback, no problem using link position */
|
||||
return link_pos;
|
||||
}
|
||||
|
@ -1927,6 +1940,17 @@ static unsigned int azx_get_position(struct azx *chip,
|
|||
default:
|
||||
/* use the position buffer */
|
||||
pos = le32_to_cpu(*azx_dev->posbuf);
|
||||
if (chip->position_fix[stream] == POS_FIX_AUTO) {
|
||||
if (!pos || pos == (u32)-1) {
|
||||
printk(KERN_WARNING
|
||||
"hda-intel: Invalid position buffer, "
|
||||
"using LPIB read method instead.\n");
|
||||
chip->position_fix[stream] = POS_FIX_LPIB;
|
||||
pos = azx_sd_readl(azx_dev, SD_LPIB);
|
||||
} else
|
||||
chip->position_fix[stream] = POS_FIX_POSBUF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos >= azx_dev->bufsize)
|
||||
|
@ -1964,16 +1988,6 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
|
|||
|
||||
stream = azx_dev->substream->stream;
|
||||
pos = azx_get_position(chip, azx_dev);
|
||||
if (chip->position_fix[stream] == POS_FIX_AUTO) {
|
||||
if (!pos) {
|
||||
printk(KERN_WARNING
|
||||
"hda-intel: Invalid position buffer, "
|
||||
"using LPIB read method instead.\n");
|
||||
chip->position_fix[stream] = POS_FIX_LPIB;
|
||||
pos = azx_get_position(chip, azx_dev);
|
||||
} else
|
||||
chip->position_fix[stream] = POS_FIX_POSBUF;
|
||||
}
|
||||
|
||||
if (WARN_ONCE(!azx_dev->period_bytes,
|
||||
"hda-intel: zero azx_dev->period_bytes"))
|
||||
|
@ -2061,6 +2075,8 @@ static void azx_pcm_free(struct snd_pcm *pcm)
|
|||
}
|
||||
}
|
||||
|
||||
#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
|
||||
|
||||
static int
|
||||
azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
||||
struct hda_pcm *cpcm)
|
||||
|
@ -2069,6 +2085,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
|||
struct snd_pcm *pcm;
|
||||
struct azx_pcm *apcm;
|
||||
int pcm_dev = cpcm->device;
|
||||
unsigned int size;
|
||||
int s, err;
|
||||
|
||||
if (pcm_dev >= HDA_MAX_PCMS) {
|
||||
|
@ -2104,9 +2121,12 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
|||
snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
|
||||
}
|
||||
/* buffer pre-allocation */
|
||||
size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
|
||||
if (size > MAX_PREALLOC_SIZE)
|
||||
size = MAX_PREALLOC_SIZE;
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
|
||||
snd_dma_pci_data(chip->pci),
|
||||
1024 * 64, 32 * 1024 * 1024);
|
||||
size, MAX_PREALLOC_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2149,7 +2169,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
|
|||
{
|
||||
if (request_irq(chip->pci->irq, azx_interrupt,
|
||||
chip->msi ? 0 : IRQF_SHARED,
|
||||
"hda_intel", chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
|
||||
"disabling device\n", chip->pci->irq);
|
||||
if (do_disconnect)
|
||||
|
@ -2347,28 +2367,20 @@ static int azx_dev_free(struct snd_device *device)
|
|||
* white/black-listing for position_fix
|
||||
*/
|
||||
static struct snd_pci_quirk position_fix_list[] __devinitdata = {
|
||||
SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -2815,6 +2827,22 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
|||
/* SCH */
|
||||
{ PCI_DEVICE(0x8086, 0x811b),
|
||||
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
|
||||
{ PCI_DEVICE(0x8086, 0x2668),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH6 */
|
||||
{ PCI_DEVICE(0x8086, 0x27d8),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH7 */
|
||||
{ PCI_DEVICE(0x8086, 0x269a),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ESB2 */
|
||||
{ PCI_DEVICE(0x8086, 0x284b),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH8 */
|
||||
{ PCI_DEVICE(0x8086, 0x293e),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */
|
||||
{ PCI_DEVICE(0x8086, 0x293f),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */
|
||||
{ PCI_DEVICE(0x8086, 0x3a3e),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */
|
||||
{ PCI_DEVICE(0x8086, 0x3a6e),
|
||||
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */
|
||||
/* Generic Intel */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
|
@ -2908,7 +2936,7 @@ MODULE_DEVICE_TABLE(pci, azx_ids);
|
|||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver driver = {
|
||||
.name = "HDA Intel",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = azx_ids,
|
||||
.probe = azx_probe,
|
||||
.remove = __devexit_p(azx_remove),
|
||||
|
|
|
@ -212,7 +212,9 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
/*
|
||||
* SPDIF I/O
|
||||
*/
|
||||
int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid);
|
||||
int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
|
||||
hda_nid_t associated_nid,
|
||||
hda_nid_t cvt_nid);
|
||||
int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
/*
|
||||
|
@ -563,7 +565,6 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
|||
* power-management
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
void snd_hda_schedule_power_save(struct hda_codec *codec);
|
||||
|
||||
struct hda_amp_list {
|
||||
|
@ -580,7 +581,6 @@ struct hda_loopback_check {
|
|||
int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
||||
struct hda_loopback_check *check,
|
||||
hda_nid_t nid);
|
||||
#endif /* CONFIG_SND_HDA_POWER_SAVE */
|
||||
|
||||
/*
|
||||
* AMP control callbacks
|
||||
|
@ -639,8 +639,8 @@ struct hdmi_eld {
|
|||
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
|
||||
int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
|
||||
void snd_hdmi_show_eld(struct hdmi_eld *eld);
|
||||
void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
|
||||
struct hda_pcm_stream *codec_pars);
|
||||
void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
|
||||
struct hda_pcm_stream *hinfo);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
|
||||
|
|
|
@ -636,7 +636,7 @@ static void print_codec_info(struct snd_info_entry *entry,
|
|||
wid_caps |= AC_WCAP_CONN_LIST;
|
||||
|
||||
if (wid_caps & AC_WCAP_CONN_LIST)
|
||||
conn_len = snd_hda_get_connections(codec, nid, conn,
|
||||
conn_len = snd_hda_get_raw_connections(codec, nid, conn,
|
||||
HDA_MAX_CONNECTIONS);
|
||||
|
||||
if (wid_caps & AC_WCAP_IN_AMP) {
|
||||
|
|
|
@ -213,7 +213,9 @@ static int ad198x_build_controls(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
if (spec->multiout.dig_out_nid) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
||||
err = snd_hda_create_spdif_out_ctls(codec,
|
||||
spec->multiout.dig_out_nid,
|
||||
spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_hda_create_spdif_share_sw(codec,
|
||||
|
@ -1920,7 +1922,8 @@ static int patch_ad1981(struct hda_codec *codec)
|
|||
spec->mixers[0] = ad1981_hp_mixers;
|
||||
spec->num_init_verbs = 2;
|
||||
spec->init_verbs[1] = ad1981_hp_init_verbs;
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
if (!is_jack_available(codec, 0x0a))
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
spec->input_mux = &ad1981_hp_capture_source;
|
||||
|
||||
codec->patch_ops.init = ad1981_hp_init;
|
||||
|
|
|
@ -240,7 +240,8 @@ static int ca0110_build_controls(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
if (spec->dig_out) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out);
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
|
||||
spec->dig_out);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -346,21 +346,15 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
|
|||
|
||||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
hda_nid_t pins[2];
|
||||
unsigned int type;
|
||||
int j, nums;
|
||||
int idx;
|
||||
type = get_wcaps_type(get_wcaps(codec, nid));
|
||||
if (type != AC_WID_AUD_IN)
|
||||
continue;
|
||||
nums = snd_hda_get_connections(codec, nid, pins,
|
||||
ARRAY_SIZE(pins));
|
||||
if (nums <= 0)
|
||||
continue;
|
||||
for (j = 0; j < nums; j++) {
|
||||
if (pins[j] == pin) {
|
||||
*idxp = j;
|
||||
return nid;
|
||||
}
|
||||
idx = snd_hda_get_conn_index(codec, nid, pin, 0);
|
||||
if (idx >= 0) {
|
||||
*idxp = idx;
|
||||
return nid;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -821,7 +815,8 @@ static int build_digital_output(struct hda_codec *codec)
|
|||
if (!spec->multiout.dig_out_nid)
|
||||
return 0;
|
||||
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid,
|
||||
spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
|
||||
|
|
|
@ -327,7 +327,9 @@ static int cmi9880_build_controls(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
if (spec->multiout.dig_out_nid) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
||||
err = snd_hda_create_spdif_out_ctls(codec,
|
||||
spec->multiout.dig_out_nid,
|
||||
spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_hda_create_spdif_share_sw(codec,
|
||||
|
@ -396,12 +398,11 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
|
|||
{
|
||||
struct cmi_spec *spec = codec->spec;
|
||||
hda_nid_t nid;
|
||||
int i, j, k, len;
|
||||
int i, j, k;
|
||||
|
||||
/* clear the table, only one c-media dac assumed here */
|
||||
memset(spec->multi_init, 0, sizeof(spec->multi_init));
|
||||
for (j = 0, i = 0; i < cfg->line_outs; i++) {
|
||||
hda_nid_t conn[4];
|
||||
nid = cfg->line_out_pins[i];
|
||||
/* set as output */
|
||||
spec->multi_init[j].nid = nid;
|
||||
|
@ -414,12 +415,10 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
|
|||
spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
|
||||
spec->multi_init[j].param = 0;
|
||||
/* find the index in connect list */
|
||||
len = snd_hda_get_connections(codec, nid, conn, 4);
|
||||
for (k = 0; k < len; k++)
|
||||
if (conn[k] == spec->dac_nids[i]) {
|
||||
spec->multi_init[j].param = k;
|
||||
break;
|
||||
}
|
||||
k = snd_hda_get_conn_index(codec, nid,
|
||||
spec->dac_nids[i], 0);
|
||||
if (k >= 0)
|
||||
spec->multi_init[j].param = k;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,10 @@ struct conexant_spec {
|
|||
unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
|
||||
|
||||
unsigned int beep_amp;
|
||||
|
||||
/* extra EAPD pins */
|
||||
unsigned int num_eapds;
|
||||
hda_nid_t eapds[4];
|
||||
};
|
||||
|
||||
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
|
@ -510,6 +514,7 @@ static int conexant_build_controls(struct hda_codec *codec)
|
|||
}
|
||||
if (spec->multiout.dig_out_nid) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec,
|
||||
spec->multiout.dig_out_nid,
|
||||
spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -1123,10 +1128,8 @@ static int patch_cxt5045(struct hda_codec *codec)
|
|||
board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
|
||||
cxt5045_models,
|
||||
cxt5045_cfg_tbl);
|
||||
#if 0 /* use the old method just for safety */
|
||||
if (board_config < 0)
|
||||
board_config = CXT5045_AUTO;
|
||||
#endif
|
||||
board_config = CXT5045_AUTO; /* model=auto as default */
|
||||
if (board_config == CXT5045_AUTO)
|
||||
return patch_conexant_auto(codec);
|
||||
|
||||
|
@ -1564,10 +1567,8 @@ static int patch_cxt5047(struct hda_codec *codec)
|
|||
board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
|
||||
cxt5047_models,
|
||||
cxt5047_cfg_tbl);
|
||||
#if 0 /* not enabled as default, as BIOS often broken for this codec */
|
||||
if (board_config < 0)
|
||||
board_config = CXT5047_AUTO;
|
||||
#endif
|
||||
board_config = CXT5047_AUTO; /* model=auto as default */
|
||||
if (board_config == CXT5047_AUTO)
|
||||
return patch_conexant_auto(codec);
|
||||
|
||||
|
@ -1993,10 +1994,8 @@ static int patch_cxt5051(struct hda_codec *codec)
|
|||
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
|
||||
cxt5051_models,
|
||||
cxt5051_cfg_tbl);
|
||||
#if 0 /* use the old method just for safety */
|
||||
if (board_config < 0)
|
||||
board_config = CXT5051_AUTO;
|
||||
#endif
|
||||
board_config = CXT5051_AUTO; /* model=auto as default */
|
||||
if (board_config == CXT5051_AUTO)
|
||||
return patch_conexant_auto(codec);
|
||||
|
||||
|
@ -3114,10 +3113,8 @@ static int patch_cxt5066(struct hda_codec *codec)
|
|||
|
||||
board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
|
||||
cxt5066_models, cxt5066_cfg_tbl);
|
||||
#if 0 /* use the old method just for safety */
|
||||
if (board_config < 0)
|
||||
board_config = CXT5066_AUTO;
|
||||
#endif
|
||||
board_config = CXT5066_AUTO; /* model=auto as default */
|
||||
if (board_config == CXT5066_AUTO)
|
||||
return patch_conexant_auto(codec);
|
||||
|
||||
|
@ -3308,19 +3305,8 @@ static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
|
|||
|
||||
static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
|
||||
|
||||
/* get the connection index of @nid in the widget @mux */
|
||||
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
|
||||
int i, nums;
|
||||
|
||||
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
|
||||
for (i = 0; i < nums; i++)
|
||||
if (conn[i] == nid)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
#define get_connection_index(codec, mux, nid)\
|
||||
snd_hda_get_conn_index(codec, mux, nid, 0)
|
||||
|
||||
/* get an unassigned DAC from the given list.
|
||||
* Return the nid if found and reduce the DAC list, or return zero if
|
||||
|
@ -3919,6 +3905,38 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
|
|||
#define cx_auto_parse_beep(codec)
|
||||
#endif
|
||||
|
||||
static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nums; i++)
|
||||
if (list[i] == nid)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* parse extra-EAPD that aren't assigned to any pins */
|
||||
static void cx_auto_parse_eapd(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t nid, end_nid;
|
||||
|
||||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++) {
|
||||
if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
|
||||
continue;
|
||||
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
|
||||
continue;
|
||||
if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
|
||||
found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
|
||||
found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
|
||||
continue;
|
||||
spec->eapds[spec->num_eapds++] = nid;
|
||||
if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int cx_auto_parse_auto_config(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
|
@ -3932,6 +3950,7 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec)
|
|||
cx_auto_parse_input(codec);
|
||||
cx_auto_parse_digital(codec);
|
||||
cx_auto_parse_beep(codec);
|
||||
cx_auto_parse_eapd(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4019,6 +4038,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
cx_auto_update_speakers(codec);
|
||||
/* turn on/off extra EAPDs, too */
|
||||
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
|
||||
}
|
||||
|
||||
static void cx_auto_init_input(struct hda_codec *codec)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1112,7 +1112,9 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
if (spec->multiout.dig_out_nid) {
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
||||
err = snd_hda_create_spdif_out_ctls(codec,
|
||||
spec->multiout.dig_out_nid,
|
||||
spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_hda_create_spdif_share_sw(codec,
|
||||
|
@ -3406,30 +3408,9 @@ static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
|
||||
int i, nums;
|
||||
|
||||
if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST))
|
||||
return -1;
|
||||
|
||||
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
|
||||
for (i = 0; i < nums; i++)
|
||||
if (conn[i] == nid)
|
||||
return i;
|
||||
|
||||
for (i = 0; i < nums; i++) {
|
||||
unsigned int wid_caps = get_wcaps(codec, conn[i]);
|
||||
unsigned int wid_type = get_wcaps_type(wid_caps);
|
||||
|
||||
if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX)
|
||||
if (get_connection_index(codec, conn[i], nid) >= 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* look for NID recursively */
|
||||
#define get_connection_index(codec, mux, nid) \
|
||||
snd_hda_get_conn_index(codec, mux, nid, 1)
|
||||
|
||||
/* create a volume assigned to the given pin (only if supported) */
|
||||
/* return 1 if the volume control is created */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2607,7 +2607,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
|
|||
ice->profi_port = pci_resource_start(pci, 3);
|
||||
|
||||
if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED,
|
||||
"ICE1712", ice)) {
|
||||
KBUILD_MODNAME, ice)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_ice1712_free(ice);
|
||||
return -EIO;
|
||||
|
@ -2802,7 +2802,7 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ICE1712",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_ice1712_ids,
|
||||
.probe = snd_ice1712_probe,
|
||||
.remove = __devexit_p(snd_ice1712_remove),
|
||||
|
|
|
@ -2509,7 +2509,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
|
|||
ice->profi_port = pci_resource_start(pci, 1);
|
||||
|
||||
if (request_irq(pci->irq, snd_vt1724_interrupt,
|
||||
IRQF_SHARED, "ICE1724", ice)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, ice)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_vt1724_free(ice);
|
||||
return -EIO;
|
||||
|
@ -2802,7 +2802,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
|
|||
#endif
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "ICE1724",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_vt1724_ids,
|
||||
.probe = snd_vt1724_probe,
|
||||
.remove = __devexit_p(snd_vt1724_remove),
|
||||
|
|
|
@ -1882,6 +1882,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
|
|||
.name = "Dell Inspiron 6000",
|
||||
.type = AC97_TUNE_HP_MUTE_LED /* cf. Malone #41015 */
|
||||
},
|
||||
{
|
||||
.subvendor = 0x1028,
|
||||
.subdevice = 0x0189,
|
||||
.name = "Dell Inspiron 9300",
|
||||
.type = AC97_TUNE_HP_MUTE_LED
|
||||
},
|
||||
{
|
||||
.subvendor = 0x1028,
|
||||
.subdevice = 0x0191,
|
||||
|
@ -2647,7 +2653,7 @@ static int intel8x0_resume(struct pci_dev *pci)
|
|||
pci_set_master(pci);
|
||||
snd_intel8x0_chip_init(chip, 0);
|
||||
if (request_irq(pci->irq, snd_intel8x0_interrupt,
|
||||
IRQF_SHARED, card->shortname, chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
|
||||
"disabling device\n", pci->irq);
|
||||
snd_card_disconnect(card);
|
||||
|
@ -3106,7 +3112,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
|
|||
|
||||
/* request irq after initializaing int_sta_mask, etc */
|
||||
if (request_irq(pci->irq, snd_intel8x0_interrupt,
|
||||
IRQF_SHARED, card->shortname, chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_intel8x0_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -3266,7 +3272,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "Intel ICH",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_intel8x0_ids,
|
||||
.probe = snd_intel8x0_probe,
|
||||
.remove = __devexit_p(snd_intel8x0_remove),
|
||||
|
|
|
@ -1047,7 +1047,7 @@ static int intel8x0m_resume(struct pci_dev *pci)
|
|||
}
|
||||
pci_set_master(pci);
|
||||
if (request_irq(pci->irq, snd_intel8x0m_interrupt,
|
||||
IRQF_SHARED, card->shortname, chip)) {
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
|
||||
"disabling device\n", pci->irq);
|
||||
snd_card_disconnect(card);
|
||||
|
@ -1174,7 +1174,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
|
|||
|
||||
port_inited:
|
||||
if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
|
||||
card->shortname, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
|
||||
snd_intel8x0m_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -1325,7 +1325,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "Intel ICH Modem",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_intel8x0m_ids,
|
||||
.probe = snd_intel8x0m_probe,
|
||||
.remove = __devexit_p(snd_intel8x0m_remove),
|
||||
|
|
|
@ -2241,7 +2241,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
|
|||
|
||||
err = request_irq(pci->irq, snd_korg1212_interrupt,
|
||||
IRQF_SHARED,
|
||||
"korg1212", korg1212);
|
||||
KBUILD_MODNAME, korg1212);
|
||||
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq);
|
||||
|
@ -2477,7 +2477,7 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci)
|
|||
}
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "korg1212",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_korg1212_ids,
|
||||
.probe = snd_korg1212_probe,
|
||||
.remove = __devexit_p(snd_korg1212_remove),
|
||||
|
|
|
@ -648,7 +648,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
|
|||
goto errout;
|
||||
|
||||
if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
|
||||
DRVNAME, chip)) {
|
||||
KBUILD_MODNAME, chip)) {
|
||||
printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
|
||||
err = -EBUSY;
|
||||
goto errout;
|
||||
|
@ -771,7 +771,7 @@ MODULE_DEVICE_TABLE(pci, lola_ids);
|
|||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver driver = {
|
||||
.name = DRVNAME,
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = lola_ids,
|
||||
.probe = lola_probe,
|
||||
.remove = __devexit_p(lola_remove),
|
||||
|
|
|
@ -480,7 +480,7 @@ struct lola {
|
|||
|
||||
/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */
|
||||
#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res) ((res >> 2) & 0x1f)
|
||||
#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res) ((res >> 7) & 0x1f)
|
||||
#define LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(res) ((res >> 7) & 0x1f)
|
||||
|
||||
int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
|
||||
unsigned int data, unsigned int extdata);
|
||||
|
|
|
@ -144,40 +144,61 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
|
|||
chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
|
||||
chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
|
||||
|
||||
/* mixer matrix can have unused areas between PhysIn and
|
||||
/* mixer matrix may have unused areas between PhysIn and
|
||||
* Play or Record and PhysOut zones
|
||||
*/
|
||||
chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
|
||||
LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
|
||||
chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
|
||||
LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val);
|
||||
LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(val);
|
||||
|
||||
/* example : MixerMatrix of LoLa881
|
||||
* 0-------8------16-------8------16
|
||||
* | | | | |
|
||||
* | INPUT | | INPUT | |
|
||||
* | -> |unused | -> |unused |
|
||||
* | RECORD| | OUTPUT| |
|
||||
* | | | | |
|
||||
* 8--------------------------------
|
||||
* | | | | |
|
||||
* | | | | |
|
||||
* |unused |unused |unused |unused |
|
||||
* | | | | |
|
||||
* | | | | |
|
||||
* 16-------------------------------
|
||||
* | | | | |
|
||||
* | PLAY | | PLAY | |
|
||||
* | -> |unused | -> |unused |
|
||||
* | RECORD| | OUTPUT| |
|
||||
* | | | | |
|
||||
* 8--------------------------------
|
||||
* | | | | |
|
||||
* | | | | |
|
||||
* |unused |unused |unused |unused |
|
||||
* | | | | |
|
||||
* | | | | |
|
||||
* 16-------------------------------
|
||||
/* example : MixerMatrix of LoLa881 (LoLa16161 uses unused zones)
|
||||
* +-+ 0-------8------16-------8------16
|
||||
* | | | | | | |
|
||||
* |s| | INPUT | | INPUT | |
|
||||
* | |->| -> |unused | -> |unused |
|
||||
* |r| |CAPTURE| | OUTPUT| |
|
||||
* | | | MIX | | MIX | |
|
||||
* |c| 8--------------------------------
|
||||
* | | | | | | |
|
||||
* | | | | | | |
|
||||
* |g| |unused |unused |unused |unused |
|
||||
* | | | | | | |
|
||||
* |a| | | | | |
|
||||
* | | 16-------------------------------
|
||||
* |i| | | | | |
|
||||
* | | | PLAYBK| | PLAYBK| |
|
||||
* |n|->| -> |unused | -> |unused |
|
||||
* | | |CAPTURE| | OUTPUT| |
|
||||
* | | | MIX | | MIX | |
|
||||
* |a| 8--------------------------------
|
||||
* |r| | | | | |
|
||||
* |r| | | | | |
|
||||
* |a| |unused |unused |unused |unused |
|
||||
* |y| | | | | |
|
||||
* | | | | | | |
|
||||
* +++ 16--|---------------|------------
|
||||
* +---V---------------V-----------+
|
||||
* | dest_mix_gain_enable array |
|
||||
* +-------------------------------+
|
||||
*/
|
||||
/* example : MixerMatrix of LoLa280
|
||||
* +-+ 0-------8-2
|
||||
* | | | | |
|
||||
* |s| | INPUT | | INPUT
|
||||
* |r|->| -> | | ->
|
||||
* |c| |CAPTURE| | <- OUTPUT
|
||||
* | | | MIX | | MIX
|
||||
* |g| 8----------
|
||||
* |a| | | |
|
||||
* |i| | PLAYBK| | PLAYBACK
|
||||
* |n|->| -> | | ->
|
||||
* | | |CAPTURE| | <- OUTPUT
|
||||
* |a| | MIX | | MIX
|
||||
* |r| 8---|----|-
|
||||
* |r| +---V----V-------------------+
|
||||
* |a| | dest_mix_gain_enable array |
|
||||
* |y| +----------------------------+
|
||||
*/
|
||||
if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
|
||||
chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
|
||||
|
@ -192,6 +213,9 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
|
|||
(((1U << chip->mixer.dest_phys_outs) - 1)
|
||||
<< chip->mixer.dest_phys_out_ofs);
|
||||
|
||||
snd_printdd("Mixer src_mask=%x, dest_mask=%x\n",
|
||||
chip->mixer.src_mask, chip->mixer.dest_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -202,12 +226,19 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
|
|||
|
||||
if (!(chip->mixer.src_mask & (1 << id)))
|
||||
return -EINVAL;
|
||||
writew(gain, &chip->mixer.array->src_gain[id]);
|
||||
oldval = val = readl(&chip->mixer.array->src_gain_enable);
|
||||
if (on)
|
||||
val |= (1 << id);
|
||||
else
|
||||
val &= ~(1 << id);
|
||||
/* test if values unchanged */
|
||||
if ((val == oldval) &&
|
||||
(gain == readw(&chip->mixer.array->src_gain[id])))
|
||||
return 0;
|
||||
|
||||
snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
|
||||
id, gain, val);
|
||||
writew(gain, &chip->mixer.array->src_gain[id]);
|
||||
writel(val, &chip->mixer.array->src_gain_enable);
|
||||
lola_codec_flush(chip);
|
||||
/* inform micro-controller about the new source gain */
|
||||
|
@ -269,6 +300,7 @@ static int lola_mixer_set_mapping_gain(struct lola *chip,
|
|||
src, dest);
|
||||
}
|
||||
|
||||
#if 0 /* not used */
|
||||
static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
|
||||
unsigned int mask, unsigned short *gains)
|
||||
{
|
||||
|
@ -289,6 +321,7 @@ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
|
|||
return lola_codec_write(chip, chip->mixer.nid,
|
||||
LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
|
||||
}
|
||||
#endif /* not used */
|
||||
|
||||
/*
|
||||
*/
|
||||
|
@ -376,6 +409,8 @@ static int set_analog_volume(struct lola *chip, int dir,
|
|||
return 0;
|
||||
if (external_call)
|
||||
lola_codec_flush(chip);
|
||||
snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n",
|
||||
dir, idx, val);
|
||||
err = lola_codec_write(chip, pin->nid,
|
||||
LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
|
||||
if (err < 0)
|
||||
|
@ -427,23 +462,40 @@ static int init_mixer_values(struct lola *chip)
|
|||
{
|
||||
int i;
|
||||
|
||||
/* all src on */
|
||||
/* all sample rate converters on */
|
||||
lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
|
||||
|
||||
/* clear all matrix */
|
||||
/* clear all mixer matrix settings */
|
||||
memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
|
||||
/* set src gain to 0dB */
|
||||
/* inform firmware about all updated matrix columns - capture part */
|
||||
for (i = 0; i < chip->mixer.dest_stream_ins; i++)
|
||||
lola_codec_write(chip, chip->mixer.nid,
|
||||
LOLA_VERB_SET_DESTINATION_GAIN,
|
||||
i, 0);
|
||||
/* inform firmware about all updated matrix columns - output part */
|
||||
for (i = 0; i < chip->mixer.dest_phys_outs; i++)
|
||||
lola_codec_write(chip, chip->mixer.nid,
|
||||
LOLA_VERB_SET_DESTINATION_GAIN,
|
||||
chip->mixer.dest_phys_out_ofs + i, 0);
|
||||
|
||||
/* set all digital input source (master) gains to 0dB */
|
||||
for (i = 0; i < chip->mixer.src_phys_ins; i++)
|
||||
lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */
|
||||
|
||||
/* set all digital playback source (master) gains to 0dB */
|
||||
for (i = 0; i < chip->mixer.src_stream_outs; i++)
|
||||
lola_mixer_set_src_gain(chip,
|
||||
i + chip->mixer.src_stream_out_ofs,
|
||||
336, true); /* 0dB */
|
||||
/* set 1:1 dest gain */
|
||||
/* set gain value 0dB diagonally in matrix - part INPUT -> CAPTURE */
|
||||
for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
|
||||
int src = i % chip->mixer.src_phys_ins;
|
||||
lola_mixer_set_mapping_gain(chip, src, i, 336, true);
|
||||
}
|
||||
/* set gain value 0dB diagonally in matrix , part PLAYBACK -> OUTPUT
|
||||
* (LoLa280 : playback channel 0,2,4,6 linked to output channel 0)
|
||||
* (LoLa280 : playback channel 1,3,5,7 linked to output channel 1)
|
||||
*/
|
||||
for (i = 0; i < chip->mixer.src_stream_outs; i++) {
|
||||
int src = chip->mixer.src_stream_out_ofs + i;
|
||||
int dst = chip->mixer.dest_phys_out_ofs +
|
||||
|
@ -693,6 +745,7 @@ static int __devinit create_src_gain_mixer(struct lola *chip,
|
|||
snd_ctl_new1(&lola_src_gain_mixer, chip));
|
||||
}
|
||||
|
||||
#if 0 /* not used */
|
||||
/*
|
||||
* destination gain (matrix-like) mixer
|
||||
*/
|
||||
|
@ -781,6 +834,7 @@ static int __devinit create_dest_gain_mixer(struct lola *chip,
|
|||
return snd_ctl_add(chip->card,
|
||||
snd_ctl_new1(&lola_dest_gain_mixer, chip));
|
||||
}
|
||||
#endif /* not used */
|
||||
|
||||
/*
|
||||
*/
|
||||
|
@ -798,14 +852,16 @@ int __devinit lola_create_mixer(struct lola *chip)
|
|||
if (err < 0)
|
||||
return err;
|
||||
err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
|
||||
"Line Source Gain Volume");
|
||||
"Digital Capture Volume");
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
|
||||
chip->mixer.src_stream_out_ofs,
|
||||
"Stream Source Gain Volume");
|
||||
"Digital Playback Volume");
|
||||
if (err < 0)
|
||||
return err;
|
||||
#if 0
|
||||
/* FIXME: buggy mixer matrix handling */
|
||||
err = create_dest_gain_mixer(chip,
|
||||
chip->mixer.src_phys_ins, 0,
|
||||
chip->mixer.dest_stream_ins, 0,
|
||||
|
@ -834,6 +890,6 @@ int __devinit lola_create_mixer(struct lola *chip)
|
|||
"Stream Playback Volume");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
#endif /* FIXME */
|
||||
return init_mixer_values(chip);
|
||||
}
|
||||
|
|
|
@ -762,7 +762,6 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
|
|||
static int __devinit lx_init_dsp(struct lx6464es *chip)
|
||||
{
|
||||
int err;
|
||||
u8 mac_address[6];
|
||||
int i;
|
||||
|
||||
snd_printdd("->lx_init_dsp\n");
|
||||
|
@ -787,11 +786,11 @@ static int __devinit lx_init_dsp(struct lx6464es *chip)
|
|||
/** \todo the mac address should be ready by not, but it isn't,
|
||||
* so we wait for it */
|
||||
for (i = 0; i != 1000; ++i) {
|
||||
err = lx_dsp_get_mac(chip, mac_address);
|
||||
err = lx_dsp_get_mac(chip);
|
||||
if (err)
|
||||
return err;
|
||||
if (mac_address[0] || mac_address[1] || mac_address[2] ||
|
||||
mac_address[3] || mac_address[4] || mac_address[5])
|
||||
if (chip->mac_address[0] || chip->mac_address[1] || chip->mac_address[2] ||
|
||||
chip->mac_address[3] || chip->mac_address[4] || chip->mac_address[5])
|
||||
goto mac_ready;
|
||||
msleep(1);
|
||||
}
|
||||
|
@ -800,8 +799,8 @@ static int __devinit lx_init_dsp(struct lx6464es *chip)
|
|||
mac_ready:
|
||||
snd_printd(LXP "mac address ready read after: %dms\n", i);
|
||||
snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
|
||||
mac_address[0], mac_address[1], mac_address[2],
|
||||
mac_address[3], mac_address[4], mac_address[5]);
|
||||
chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
|
||||
chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
|
||||
|
||||
err = lx_init_get_version_features(chip);
|
||||
if (err)
|
||||
|
@ -1031,7 +1030,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card,
|
|||
chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
|
||||
|
||||
err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
|
||||
card_name, chip);
|
||||
KBUILD_MODNAME, chip);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
|
||||
goto request_irq_failed;
|
||||
|
@ -1108,8 +1107,14 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci,
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
strcpy(card->driver, "lx6464es");
|
||||
strcpy(card->shortname, "Digigram LX6464ES");
|
||||
strcpy(card->driver, "LX6464ES");
|
||||
sprintf(card->id, "LX6464ES_%02X%02X%02X",
|
||||
chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
|
||||
|
||||
sprintf(card->shortname, "LX6464ES %02X.%02X.%02X.%02X.%02X.%02X",
|
||||
chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
|
||||
chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
|
||||
|
||||
sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i",
|
||||
card->shortname, chip->port_plx,
|
||||
chip->port_dsp_bar, chip->irq);
|
||||
|
@ -1137,7 +1142,7 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
|
|||
|
||||
|
||||
static struct pci_driver driver = {
|
||||
.name = "Digigram LX6464ES",
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = snd_lx6464es_ids,
|
||||
.probe = snd_lx6464es_probe,
|
||||
.remove = __devexit_p(snd_lx6464es_remove),
|
||||
|
|
|
@ -69,6 +69,8 @@ struct lx6464es {
|
|||
struct pci_dev *pci;
|
||||
int irq;
|
||||
|
||||
u8 mac_address[6];
|
||||
|
||||
spinlock_t lock; /* interrupt spinlock */
|
||||
struct mutex setup_mutex; /* mutex used in hw_params, open
|
||||
* and close */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue