forked from Minki/linux
ALSA: hda - Allow override more fields via patch loader
Allow the override of vendor-id, subsystem-id, revision-id and chip name via patch loading. Updated the document, too. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
ccc5df058d
commit
b09f3e78ee
@ -452,6 +452,33 @@ Similarly, the lines after `[verb]` are parsed as `init_verbs`
|
|||||||
sysfs entries, and the lines after `[hint]` are parsed as `hints`
|
sysfs entries, and the lines after `[hint]` are parsed as `hints`
|
||||||
sysfs entries, respectively.
|
sysfs entries, respectively.
|
||||||
|
|
||||||
|
Another example to override the codec vendor id from 0x12345678 to
|
||||||
|
0xdeadbeef is like below:
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[codec]
|
||||||
|
0x12345678 0xabcd1234 2
|
||||||
|
|
||||||
|
[vendor_id]
|
||||||
|
0xdeadbeef
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
In the similar way, you can override the codec subsystem_id via
|
||||||
|
`[subsystem_id]`, the revision id via `[revision_id]` line.
|
||||||
|
Also, the codec chip name can be rewritten via `[chip_name]` line.
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
[codec]
|
||||||
|
0x12345678 0xabcd1234 2
|
||||||
|
|
||||||
|
[subsystem_id]
|
||||||
|
0xffff1111
|
||||||
|
|
||||||
|
[revision_id]
|
||||||
|
0x10
|
||||||
|
|
||||||
|
[chip_name]
|
||||||
|
My-own NEWS-0002
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
The hd-audio driver reads the file via request_firmware(). Thus,
|
The hd-audio driver reads the file via request_firmware(). Thus,
|
||||||
a patch file has to be located on the appropriate firmware path,
|
a patch file has to be located on the appropriate firmware path,
|
||||||
typically, /lib/firmware. For example, when you pass the option
|
typically, /lib/firmware. For example, when you pass the option
|
||||||
|
@ -625,6 +625,10 @@ enum {
|
|||||||
LINE_MODE_PINCFG,
|
LINE_MODE_PINCFG,
|
||||||
LINE_MODE_VERB,
|
LINE_MODE_VERB,
|
||||||
LINE_MODE_HINT,
|
LINE_MODE_HINT,
|
||||||
|
LINE_MODE_VENDOR_ID,
|
||||||
|
LINE_MODE_SUBSYSTEM_ID,
|
||||||
|
LINE_MODE_REVISION_ID,
|
||||||
|
LINE_MODE_CHIP_NAME,
|
||||||
NUM_LINE_MODES,
|
NUM_LINE_MODES,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -654,53 +658,71 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* parse the contents after the other command tags, [pincfg], [verb],
|
/* parse the contents after the other command tags, [pincfg], [verb],
|
||||||
* [hint] and [model]
|
* [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
|
||||||
* just pass to the sysfs helper (only when any codec was specified)
|
* just pass to the sysfs helper (only when any codec was specified)
|
||||||
*/
|
*/
|
||||||
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
|
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
|
||||||
struct hda_codec **codecp)
|
struct hda_codec **codecp)
|
||||||
{
|
{
|
||||||
if (!*codecp)
|
|
||||||
return;
|
|
||||||
parse_user_pin_configs(*codecp, buf);
|
parse_user_pin_configs(*codecp, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_verb_mode(char *buf, struct hda_bus *bus,
|
static void parse_verb_mode(char *buf, struct hda_bus *bus,
|
||||||
struct hda_codec **codecp)
|
struct hda_codec **codecp)
|
||||||
{
|
{
|
||||||
if (!*codecp)
|
|
||||||
return;
|
|
||||||
parse_init_verbs(*codecp, buf);
|
parse_init_verbs(*codecp, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_hint_mode(char *buf, struct hda_bus *bus,
|
static void parse_hint_mode(char *buf, struct hda_bus *bus,
|
||||||
struct hda_codec **codecp)
|
struct hda_codec **codecp)
|
||||||
{
|
{
|
||||||
if (!*codecp)
|
|
||||||
return;
|
|
||||||
parse_hints(*codecp, buf);
|
parse_hints(*codecp, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_model_mode(char *buf, struct hda_bus *bus,
|
static void parse_model_mode(char *buf, struct hda_bus *bus,
|
||||||
struct hda_codec **codecp)
|
struct hda_codec **codecp)
|
||||||
{
|
{
|
||||||
if (!*codecp)
|
|
||||||
return;
|
|
||||||
kfree((*codecp)->modelname);
|
kfree((*codecp)->modelname);
|
||||||
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
|
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
|
||||||
|
struct hda_codec **codecp)
|
||||||
|
{
|
||||||
|
kfree((*codecp)->chip_name);
|
||||||
|
(*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_PARSE_ID_MODE(name) \
|
||||||
|
static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
|
||||||
|
struct hda_codec **codecp) \
|
||||||
|
{ \
|
||||||
|
unsigned long val; \
|
||||||
|
if (!strict_strtoul(buf, 0, &val)) \
|
||||||
|
(*codecp)->name = val; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_PARSE_ID_MODE(vendor_id);
|
||||||
|
DEFINE_PARSE_ID_MODE(subsystem_id);
|
||||||
|
DEFINE_PARSE_ID_MODE(revision_id);
|
||||||
|
|
||||||
|
|
||||||
struct hda_patch_item {
|
struct hda_patch_item {
|
||||||
const char *tag;
|
const char *tag;
|
||||||
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
|
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
|
||||||
|
int need_codec;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
|
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
|
||||||
[LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
|
[LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 },
|
||||||
[LINE_MODE_MODEL] = { "[model]", parse_model_mode },
|
[LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 },
|
||||||
[LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
|
[LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 },
|
||||||
[LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
|
[LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 },
|
||||||
[LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
|
[LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 },
|
||||||
|
[LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 },
|
||||||
|
[LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 },
|
||||||
|
[LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 },
|
||||||
|
[LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* check the line starting with '[' -- change the parser mode accodingly */
|
/* check the line starting with '[' -- change the parser mode accodingly */
|
||||||
@ -783,7 +805,8 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
|
|||||||
continue;
|
continue;
|
||||||
if (*buf == '[')
|
if (*buf == '[')
|
||||||
line_mode = parse_line_mode(buf, bus);
|
line_mode = parse_line_mode(buf, bus);
|
||||||
else if (patch_items[line_mode].parser)
|
else if (patch_items[line_mode].parser &&
|
||||||
|
(codec || !patch_items[line_mode].need_codec))
|
||||||
patch_items[line_mode].parser(buf, bus, &codec);
|
patch_items[line_mode].parser(buf, bus, &codec);
|
||||||
}
|
}
|
||||||
release_firmware(fw);
|
release_firmware(fw);
|
||||||
|
Loading…
Reference in New Issue
Block a user