Merge branch 'topic/hda-patch' into topic/hda
This commit is contained in:
@@ -768,6 +768,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||||||
bdl_pos_adj - Specifies the DMA IRQ timing delay in samples.
|
bdl_pos_adj - Specifies the DMA IRQ timing delay in samples.
|
||||||
Passing -1 will make the driver to choose the appropriate
|
Passing -1 will make the driver to choose the appropriate
|
||||||
value based on the controller chip.
|
value based on the controller chip.
|
||||||
|
patch - Specifies the early "patch" files to modify the HD-audio
|
||||||
|
setup before initializing the codecs. This option is
|
||||||
|
available only when CONFIG_SND_HDA_PATCH_LOADER=y is set.
|
||||||
|
See HD-Audio.txt for details.
|
||||||
|
|
||||||
[Single (global) options]
|
[Single (global) options]
|
||||||
single_cmd - Use single immediate commands to communicate with
|
single_cmd - Use single immediate commands to communicate with
|
||||||
|
@@ -403,6 +403,66 @@ re-configure based on that state, run like below:
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Early Patching
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a
|
||||||
|
firmware file for modifying the HD-audio setup before initializing the
|
||||||
|
codec. This can work basically like the reconfiguration via sysfs in
|
||||||
|
the above, but it does it before the first codec configuration.
|
||||||
|
|
||||||
|
A patch file is a plain text file which looks like below:
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[codec]
|
||||||
|
0x12345678 0xabcd1234 2
|
||||||
|
|
||||||
|
[model]
|
||||||
|
auto
|
||||||
|
|
||||||
|
[pincfg]
|
||||||
|
0x12 0x411111f0
|
||||||
|
|
||||||
|
[verb]
|
||||||
|
0x20 0x500 0x03
|
||||||
|
0x20 0x400 0xff
|
||||||
|
|
||||||
|
[hint]
|
||||||
|
hp_detect = yes
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The file needs to have a line `[codec]`. The next line should contain
|
||||||
|
three numbers indicating the codec vendor-id (0x12345678 in the
|
||||||
|
example), the codec subsystem-id (0xabcd1234) and the address (2) of
|
||||||
|
the codec. The rest patch entries are applied to this specified codec
|
||||||
|
until another codec entry is given.
|
||||||
|
|
||||||
|
The `[model]` line allows to change the model name of the each codec.
|
||||||
|
In the example above, it will be changed to model=auto.
|
||||||
|
Note that this overrides the module option.
|
||||||
|
|
||||||
|
After the `[pincfg]` line, the contents are parsed as the initial
|
||||||
|
default pin-configurations just like `user_pin_configs` sysfs above.
|
||||||
|
The values can be shown in user_pin_configs sysfs file, too.
|
||||||
|
|
||||||
|
Similarly, the lines after `[verb]` are parsed as `init_verbs`
|
||||||
|
sysfs entries, and the lines after `[hint]` are parsed as `hints`
|
||||||
|
sysfs entries, respectively.
|
||||||
|
|
||||||
|
The hd-audio driver reads the file via request_firmware(). Thus,
|
||||||
|
a patch file has to be located on the appropriate firmware path,
|
||||||
|
typically, /lib/firmware. For example, when you pass the option
|
||||||
|
`patch=hda-init.fw`, the file /lib/firmware/hda-init-fw must be
|
||||||
|
present.
|
||||||
|
|
||||||
|
The patch module option is specific to each card instance, and you
|
||||||
|
need to give one file name for each instance, separated by commas.
|
||||||
|
For example, if you have two cards, one for an on-board analog and one
|
||||||
|
for an HDMI video board, you may pass patch option like below:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
options snd-hda-intel patch=on-board-patch,hdmi-patch
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
Power-Saving
|
Power-Saving
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
The power-saving is a kind of auto-suspend of the device. When the
|
The power-saving is a kind of auto-suspend of the device. When the
|
||||||
|
@@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK
|
|||||||
Say Y here to enable the jack plugging notification via
|
Say Y here to enable the jack plugging notification via
|
||||||
input layer.
|
input layer.
|
||||||
|
|
||||||
|
config SND_HDA_PATCH_LOADER
|
||||||
|
bool "Support initialization patch loading for HD-audio"
|
||||||
|
depends on EXPERIMENTAL
|
||||||
|
select FW_LOADER
|
||||||
|
select SND_HDA_HWDEP
|
||||||
|
select SND_HDA_RECONFIG
|
||||||
|
help
|
||||||
|
Say Y here to allow the HD-audio driver to load a pseudo
|
||||||
|
firmware file ("patch") for overriding the BIOS setup at
|
||||||
|
start up. The "patch" file can be specified via patch module
|
||||||
|
option, such as patch=hda-init.
|
||||||
|
|
||||||
|
This option turns on hwdep and reconfig features automatically.
|
||||||
|
|
||||||
config SND_HDA_CODEC_REALTEK
|
config SND_HDA_CODEC_REALTEK
|
||||||
bool "Build Realtek HD-audio codec support"
|
bool "Build Realtek HD-audio codec support"
|
||||||
default y
|
default y
|
||||||
|
@@ -885,7 +885,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|||||||
* Returns 0 if successful, or a negative error code.
|
* Returns 0 if successful, or a negative error code.
|
||||||
*/
|
*/
|
||||||
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
||||||
int do_init, struct hda_codec **codecp)
|
struct hda_codec **codecp)
|
||||||
{
|
{
|
||||||
struct hda_codec *codec;
|
struct hda_codec *codec;
|
||||||
char component[31];
|
char component[31];
|
||||||
@@ -978,11 +978,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
|
|||||||
codec->afg ? codec->afg : codec->mfg,
|
codec->afg ? codec->afg : codec->mfg,
|
||||||
AC_PWRST_D0);
|
AC_PWRST_D0);
|
||||||
|
|
||||||
if (do_init) {
|
|
||||||
err = snd_hda_codec_configure(codec);
|
|
||||||
if (err < 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
snd_hda_codec_proc_new(codec);
|
snd_hda_codec_proc_new(codec);
|
||||||
|
|
||||||
snd_hda_create_hwdep(codec);
|
snd_hda_create_hwdep(codec);
|
||||||
@@ -1036,6 +1031,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
|
|||||||
err = init_unsol_queue(codec->bus);
|
err = init_unsol_queue(codec->bus);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_hda_codec_setup_stream - set up the codec for streaming
|
* snd_hda_codec_setup_stream - set up the codec for streaming
|
||||||
|
@@ -830,7 +830,8 @@ enum {
|
|||||||
int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
|
int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
|
||||||
struct hda_bus **busp);
|
struct hda_bus **busp);
|
||||||
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
||||||
int do_init, struct hda_codec **codecp);
|
struct hda_codec **codecp);
|
||||||
|
int snd_hda_codec_configure(struct hda_codec *codec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* low level functions
|
* low level functions
|
||||||
@@ -938,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {}
|
|||||||
#define snd_hda_codec_needs_resume(codec) 1
|
#define snd_hda_codec_needs_resume(codec) 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||||
|
/*
|
||||||
|
* patch firmware
|
||||||
|
*/
|
||||||
|
int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Codec modularization
|
* Codec modularization
|
||||||
*/
|
*/
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include "hda_codec.h"
|
#include "hda_codec.h"
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
@@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev,
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t init_verbs_store(struct device *dev,
|
static int parse_init_verbs(struct hda_codec *codec, const char *buf)
|
||||||
struct device_attribute *attr,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
{
|
||||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
|
||||||
struct hda_codec *codec = hwdep->private_data;
|
|
||||||
struct hda_verb *v;
|
struct hda_verb *v;
|
||||||
int nid, verb, param;
|
int nid, verb, param;
|
||||||
|
|
||||||
@@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev,
|
|||||||
v->nid = nid;
|
v->nid = nid;
|
||||||
v->verb = verb;
|
v->verb = verb;
|
||||||
v->param = param;
|
v->param = param;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t init_verbs_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||||
|
struct hda_codec *codec = hwdep->private_data;
|
||||||
|
int err = parse_init_verbs(codec, buf);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str)
|
|||||||
|
|
||||||
#define MAX_HINTS 1024
|
#define MAX_HINTS 1024
|
||||||
|
|
||||||
static ssize_t hints_store(struct device *dev,
|
static int parse_hints(struct hda_codec *codec, const char *buf)
|
||||||
struct device_attribute *attr,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
{
|
||||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
|
||||||
struct hda_codec *codec = hwdep->private_data;
|
|
||||||
char *key, *val;
|
char *key, *val;
|
||||||
struct hda_hint *hint;
|
struct hda_hint *hint;
|
||||||
|
|
||||||
while (isspace(*buf))
|
while (isspace(*buf))
|
||||||
buf++;
|
buf++;
|
||||||
if (!*buf || *buf == '#' || *buf == '\n')
|
if (!*buf || *buf == '#' || *buf == '\n')
|
||||||
return count;
|
return 0;
|
||||||
if (*buf == '=')
|
if (*buf == '=')
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
key = kstrndup_noeol(buf, 1024);
|
key = kstrndup_noeol(buf, 1024);
|
||||||
@@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev,
|
|||||||
kfree(hint->key);
|
kfree(hint->key);
|
||||||
hint->key = key;
|
hint->key = key;
|
||||||
hint->val = val;
|
hint->val = val;
|
||||||
return count;
|
return 0;
|
||||||
}
|
}
|
||||||
/* allocate a new hint entry */
|
/* allocate a new hint entry */
|
||||||
if (codec->hints.used >= MAX_HINTS)
|
if (codec->hints.used >= MAX_HINTS)
|
||||||
@@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev,
|
|||||||
}
|
}
|
||||||
hint->key = key;
|
hint->key = key;
|
||||||
hint->val = val;
|
hint->val = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t hints_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||||
|
struct hda_codec *codec = hwdep->private_data;
|
||||||
|
int err = parse_hints(codec, buf);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev,
|
|||||||
|
|
||||||
#define MAX_PIN_CONFIGS 32
|
#define MAX_PIN_CONFIGS 32
|
||||||
|
|
||||||
|
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
|
||||||
|
{
|
||||||
|
int nid, cfg;
|
||||||
|
|
||||||
|
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!nid)
|
||||||
|
return -EINVAL;
|
||||||
|
return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t user_pin_configs_store(struct device *dev,
|
static ssize_t user_pin_configs_store(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||||
struct hda_codec *codec = hwdep->private_data;
|
struct hda_codec *codec = hwdep->private_data;
|
||||||
int nid, cfg;
|
int err = parse_user_pin_configs(codec, buf);
|
||||||
int err;
|
|
||||||
|
|
||||||
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!nid)
|
|
||||||
return -EINVAL;
|
|
||||||
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
return count;
|
return count;
|
||||||
@@ -553,3 +574,180 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
|||||||
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
|
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
|
||||||
|
|
||||||
#endif /* CONFIG_SND_HDA_RECONFIG */
|
#endif /* CONFIG_SND_HDA_RECONFIG */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||||
|
|
||||||
|
/* parser mode */
|
||||||
|
enum {
|
||||||
|
LINE_MODE_NONE,
|
||||||
|
LINE_MODE_CODEC,
|
||||||
|
LINE_MODE_MODEL,
|
||||||
|
LINE_MODE_PINCFG,
|
||||||
|
LINE_MODE_VERB,
|
||||||
|
LINE_MODE_HINT,
|
||||||
|
NUM_LINE_MODES,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int strmatch(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
return strnicmp(a, b, strlen(b)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the contents after the line "[codec]"
|
||||||
|
* accept only the line with three numbers, and assign the current codec
|
||||||
|
*/
|
||||||
|
static void parse_codec_mode(char *buf, struct hda_bus *bus,
|
||||||
|
struct hda_codec **codecp)
|
||||||
|
{
|
||||||
|
unsigned int vendorid, subid, caddr;
|
||||||
|
struct hda_codec *codec;
|
||||||
|
|
||||||
|
*codecp = NULL;
|
||||||
|
if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
|
||||||
|
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||||
|
if (codec->addr == caddr) {
|
||||||
|
*codecp = codec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the contents after the other command tags, [pincfg], [verb],
|
||||||
|
* [hint] and [model]
|
||||||
|
* just pass to the sysfs helper (only when any codec was specified)
|
||||||
|
*/
|
||||||
|
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
|
||||||
|
struct hda_codec **codecp)
|
||||||
|
{
|
||||||
|
if (!*codecp)
|
||||||
|
return;
|
||||||
|
parse_user_pin_configs(*codecp, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_verb_mode(char *buf, struct hda_bus *bus,
|
||||||
|
struct hda_codec **codecp)
|
||||||
|
{
|
||||||
|
if (!*codecp)
|
||||||
|
return;
|
||||||
|
parse_init_verbs(*codecp, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_hint_mode(char *buf, struct hda_bus *bus,
|
||||||
|
struct hda_codec **codecp)
|
||||||
|
{
|
||||||
|
if (!*codecp)
|
||||||
|
return;
|
||||||
|
parse_hints(*codecp, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_model_mode(char *buf, struct hda_bus *bus,
|
||||||
|
struct hda_codec **codecp)
|
||||||
|
{
|
||||||
|
if (!*codecp)
|
||||||
|
return;
|
||||||
|
kfree((*codecp)->modelname);
|
||||||
|
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hda_patch_item {
|
||||||
|
const char *tag;
|
||||||
|
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
|
||||||
|
[LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
|
||||||
|
[LINE_MODE_MODEL] = { "[model]", parse_model_mode },
|
||||||
|
[LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
|
||||||
|
[LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
|
||||||
|
[LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* check the line starting with '[' -- change the parser mode accodingly */
|
||||||
|
static int parse_line_mode(char *buf, struct hda_bus *bus)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
|
||||||
|
if (!patch_items[i].tag)
|
||||||
|
continue;
|
||||||
|
if (strmatch(buf, patch_items[i].tag))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return LINE_MODE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy one line from the buffer in fw, and update the fields in fw
|
||||||
|
* return zero if it reaches to the end of the buffer, or non-zero
|
||||||
|
* if successfully copied a line
|
||||||
|
*
|
||||||
|
* the spaces at the beginning and the end of the line are stripped
|
||||||
|
*/
|
||||||
|
static int get_line_from_fw(char *buf, int size, struct firmware *fw)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
const char *p = fw->data;
|
||||||
|
while (isspace(*p) && fw->size) {
|
||||||
|
p++;
|
||||||
|
fw->size--;
|
||||||
|
}
|
||||||
|
if (!fw->size)
|
||||||
|
return 0;
|
||||||
|
if (size < fw->size)
|
||||||
|
size = fw->size;
|
||||||
|
|
||||||
|
for (len = 0; len < fw->size; len++) {
|
||||||
|
if (!*p)
|
||||||
|
break;
|
||||||
|
if (*p == '\n') {
|
||||||
|
p++;
|
||||||
|
len++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len < size)
|
||||||
|
*buf++ = *p++;
|
||||||
|
}
|
||||||
|
*buf = 0;
|
||||||
|
fw->size -= len;
|
||||||
|
fw->data = p;
|
||||||
|
remove_trail_spaces(buf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load a "patch" firmware file and parse it
|
||||||
|
*/
|
||||||
|
int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const struct firmware *fw;
|
||||||
|
struct firmware tmp;
|
||||||
|
char buf[128];
|
||||||
|
struct hda_codec *codec;
|
||||||
|
int line_mode;
|
||||||
|
struct device *dev = bus->card->dev;
|
||||||
|
|
||||||
|
if (snd_BUG_ON(!dev))
|
||||||
|
return -ENODEV;
|
||||||
|
err = request_firmware(&fw, patch, dev);
|
||||||
|
if (err < 0) {
|
||||||
|
printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
|
||||||
|
patch);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = *fw;
|
||||||
|
line_mode = LINE_MODE_NONE;
|
||||||
|
codec = NULL;
|
||||||
|
while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
|
||||||
|
if (!*buf || *buf == '#' || *buf == '\n')
|
||||||
|
continue;
|
||||||
|
if (*buf == '[')
|
||||||
|
line_mode = parse_line_mode(buf, bus);
|
||||||
|
else if (patch_items[line_mode].parser)
|
||||||
|
patch_items[line_mode].parser(buf, bus, &codec);
|
||||||
|
}
|
||||||
|
release_firmware(fw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_HDA(snd_hda_load_patch);
|
||||||
|
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
|
||||||
|
@@ -61,6 +61,9 @@ static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
|
|||||||
static int probe_only[SNDRV_CARDS];
|
static int probe_only[SNDRV_CARDS];
|
||||||
static int single_cmd;
|
static int single_cmd;
|
||||||
static int enable_msi;
|
static int enable_msi;
|
||||||
|
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||||
|
static char *patch[SNDRV_CARDS];
|
||||||
|
#endif
|
||||||
|
|
||||||
module_param_array(index, int, NULL, 0444);
|
module_param_array(index, int, NULL, 0444);
|
||||||
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
||||||
@@ -84,6 +87,10 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
|
|||||||
"(for debugging only).");
|
"(for debugging only).");
|
||||||
module_param(enable_msi, int, 0444);
|
module_param(enable_msi, int, 0444);
|
||||||
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
|
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
|
||||||
|
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||||
|
module_param_array(patch, charp, NULL, 0444);
|
||||||
|
MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||||
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||||
@@ -1286,8 +1293,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
|
|||||||
[AZX_DRIVER_TERA] = 1,
|
[AZX_DRIVER_TERA] = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
static int __devinit azx_codec_create(struct azx *chip, const char *model)
|
||||||
int no_init)
|
|
||||||
{
|
{
|
||||||
struct hda_bus_template bus_temp;
|
struct hda_bus_template bus_temp;
|
||||||
int c, codecs, err;
|
int c, codecs, err;
|
||||||
@@ -1346,7 +1352,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|||||||
for (c = 0; c < max_slots; c++) {
|
for (c = 0; c < max_slots; c++) {
|
||||||
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
||||||
struct hda_codec *codec;
|
struct hda_codec *codec;
|
||||||
err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
|
err = snd_hda_codec_new(chip->bus, c, &codec);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
continue;
|
continue;
|
||||||
codecs++;
|
codecs++;
|
||||||
@@ -1356,7 +1362,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|||||||
snd_printk(KERN_ERR SFX "no codecs initialized\n");
|
snd_printk(KERN_ERR SFX "no codecs initialized\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configure each codec instance */
|
||||||
|
static int __devinit azx_codec_configure(struct azx *chip)
|
||||||
|
{
|
||||||
|
struct hda_codec *codec;
|
||||||
|
list_for_each_entry(codec, &chip->bus->codec_list, list) {
|
||||||
|
snd_hda_codec_configure(codec);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2460,15 +2475,32 @@ static int __devinit azx_probe(struct pci_dev *pci,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set this here since it's referred in snd_hda_load_patch() */
|
||||||
|
snd_card_set_dev(card, &pci->dev);
|
||||||
|
|
||||||
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
|
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
card->private_data = chip;
|
card->private_data = chip;
|
||||||
|
|
||||||
/* create codec instances */
|
/* create codec instances */
|
||||||
err = azx_codec_create(chip, model[dev], probe_only[dev]);
|
err = azx_codec_create(chip, model[dev]);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||||
|
if (patch[dev]) {
|
||||||
|
snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
|
||||||
|
patch[dev]);
|
||||||
|
err = snd_hda_load_patch(chip->bus, patch[dev]);
|
||||||
|
if (err < 0)
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!probe_only[dev]) {
|
||||||
|
err = azx_codec_configure(chip);
|
||||||
|
if (err < 0)
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
/* create PCM streams */
|
/* create PCM streams */
|
||||||
err = snd_hda_build_pcms(chip->bus);
|
err = snd_hda_build_pcms(chip->bus);
|
||||||
@@ -2480,8 +2512,6 @@ static int __devinit azx_probe(struct pci_dev *pci,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
snd_card_set_dev(card, &pci->dev);
|
|
||||||
|
|
||||||
err = snd_card_register(card);
|
err = snd_card_register(card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
@@ -99,7 +99,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
|||||||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||||
unsigned int *tlv, const char **slaves);
|
unsigned int *tlv, const char **slaves);
|
||||||
int snd_hda_codec_reset(struct hda_codec *codec);
|
int snd_hda_codec_reset(struct hda_codec *codec);
|
||||||
int snd_hda_codec_configure(struct hda_codec *codec);
|
|
||||||
|
|
||||||
/* amp value bits */
|
/* amp value bits */
|
||||||
#define HDA_AMP_MUTE 0x80
|
#define HDA_AMP_MUTE 0x80
|
||||||
|
Reference in New Issue
Block a user