* Separated widget parsing and debug output a bit better.

* More generic supported parameter support, respect the
  AUDIO_CAP_AMPLIFIER_OVERRIDE, and AUDIO_CAP_FORMAT_OVERRIDE bits.
* More cleanups.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24360 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-03-11 17:19:55 +00:00
parent 4eb3560949
commit 17959555c2
3 changed files with 320 additions and 194 deletions
@@ -4,6 +4,7 @@
* *
* Authors: * Authors:
* Ithamar Adema, ithamar AT unet DOT nl * Ithamar Adema, ithamar AT unet DOT nl
* Axel Dörfler, [email protected]
*/ */
#ifndef _HDA_H_ #ifndef _HDA_H_
#define _HDA_H_ #define _HDA_H_
@@ -87,6 +88,8 @@ struct hda_stream {
}; };
struct hda_widget { struct hda_widget {
uint32 node_id;
uint32 num_inputs; uint32 num_inputs;
int32 active_input; int32 active_input;
uint32 inputs[MAX_INPUTS]; uint32 inputs[MAX_INPUTS];
@@ -95,6 +98,12 @@ struct hda_widget {
hda_widget_type type; hda_widget_type type;
uint32 pm; uint32 pm;
struct {
uint32 audio;
uint32 output_amplifier;
uint32 input_amplifier;
} capabilities;
union { union {
struct { struct {
uint32 formats; uint32 formats;
@@ -134,6 +143,9 @@ struct hda_audio_group {
uint32 supported_rates; uint32 supported_rates;
uint32 supported_pm; uint32 supported_pm;
uint32 input_amplifier_capabilities;
uint32 output_amplifier_capabilities;
hda_widget* widgets; hda_widget* widgets;
}; };
+234 -148
View File
@@ -4,6 +4,7 @@
* *
* Authors: * Authors:
* Ithamar Adema, ithamar AT unet DOT nl * Ithamar Adema, ithamar AT unet DOT nl
* Axel Dörfler, [email protected]
*/ */
@@ -33,22 +34,132 @@ static const char* kJackColor[] = {
}; };
static const char*
get_widget_type_name(hda_widget_type type)
{
switch (type) {
case WT_AUDIO_OUTPUT:
return "Audio Output";
case WT_AUDIO_INPUT:
return "Audio Input";
case WT_AUDIO_MIXER:
return "Audio Mixer";
case WT_AUDIO_SELECTOR:
return "Audio Selector";
case WT_PIN_COMPLEX:
return "Pin Complex";
case WT_POWER:
return "Power";
case WT_VOLUME_KNOB:
return "Volume Knob";
case WT_BEEP_GENERATOR:
return "Beep Generator";
case WT_VENDOR_DEFINED:
return "Vendor Defined";
default:
return "Unknown";
}
}
static void
dump_widget_audio_capabilities(uint32 capabilities)
{
const struct {
uint32 flag;
const char* name;
} kFlags[] = {
{AUDIO_CAP_LEFT_RIGHT_SWAP, "L-R Swap"},
{AUDIO_CAP_POWER_CONTROL, "Power"},
{AUDIO_CAP_DIGITAL, "Digital"},
{AUDIO_CAP_CONNECTION_LIST, "Conn. List"},
{AUDIO_CAP_UNSOLICITED_RESPONSES, "Unsol. Responses"},
{AUDIO_CAP_PROCESSING_CONTROLS, "Proc Widget"},
{AUDIO_CAP_STRIPE, "Stripe"},
{AUDIO_CAP_FORMAT_OVERRIDE, "Format Override"},
{AUDIO_CAP_AMPLIFIER_OVERRIDE, "Amplifier Override"},
{AUDIO_CAP_OUTPUT_AMPLIFIER, "Out Amplifier"},
{AUDIO_CAP_INPUT_AMPLIFIER, "In Amplifier"},
{AUDIO_CAP_STEREO, "Stereo"},
};
char buffer[256];
int offset = 0;
for (uint32 j = 0; j < sizeof(kFlags) / sizeof(kFlags[0]); j++) {
if (capabilities & kFlags[j].flag)
offset += sprintf(buffer + offset, "[%s] ", kFlags[j].name);
}
if (offset != 0)
dprintf("\t%s\n", buffer);
}
static void
dump_widget_inputs(hda_widget& widget)
{
// dump connections
char buffer[256];
int offset = 0;
for (uint32 i = 0; i < widget.num_inputs; i++) {
int32 input = widget.inputs[i];
if ((int32)i != widget.active_input)
offset += sprintf(buffer + offset, "%ld ", input);
else
offset += sprintf(buffer + offset, "<%ld> ", input);
}
if (offset != 0)
dprintf("\tConnections: %s\n", buffer);
}
static void
dump_widget_amplifier_capabilities(hda_widget& widget, bool input)
{
uint32 capabilities;
if (input)
capabilities = widget.capabilities.input_amplifier;
else
capabilities = widget.capabilities.output_amplifier;
if (capabilities == 0)
return;
dprintf("\t%s Amp: %sstep size: %ld dB, # steps: %ld, offset to 0 dB: "
"%ld\n", input ? "In" : "Out",
(capabilities & AMP_CAP_MUTE) != 0 ? "supports mute, " : "",
(((capabilities & AMP_CAP_STEP_SIZE_MASK)
>> AMP_CAP_STEP_SIZE_SHIFT) + 1) / 4,
(capabilities & AMP_CAP_NUM_STEPS_MASK) >> AMP_CAP_NUM_STEPS_SHIFT,
capabilities & AMP_CAP_OFFSET_MASK);
}
// #pragma mark -
static status_t static status_t
hda_widget_get_pm_support(hda_codec* codec, uint32 nodeID, uint32* pm) hda_get_pm_support(hda_codec* codec, uint32 nodeID, uint32* pm)
{ {
corb_t verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER, corb_t verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER,
PID_POWERSTATE_SUPPORT); PID_POWERSTATE_SUPPORT);
status_t rc; status_t rc;
uint32 resp; uint32 response;
if ((rc = hda_send_verbs(codec, &verb, &resp, 1)) == B_OK) {
*pm = 0;
if ((rc = hda_send_verbs(codec, &verb, &response, 1)) == B_OK) {
*pm = response & 0xf;
#if 0
/* FIXME: Define constants for powermanagement modes */ /* FIXME: Define constants for powermanagement modes */
if (resp & (1 << 0)) ; if (resp & (1 << 0)) ;
if (resp & (1 << 1)) ; if (resp & (1 << 1)) ;
if (resp & (1 << 2)) ; if (resp & (1 << 2)) ;
if (resp & (1 << 3)) ; if (resp & (1 << 3)) ;
#endif
} }
return rc; return rc;
@@ -56,7 +167,7 @@ hda_widget_get_pm_support(hda_codec* codec, uint32 nodeID, uint32* pm)
static status_t static status_t
hda_widget_get_stream_support(hda_codec* codec, uint32 nodeID, uint32* formats, hda_get_stream_support(hda_codec* codec, uint32 nodeID, uint32* formats,
uint32* rates) uint32* rates)
{ {
corb_t verbs[2]; corb_t verbs[2];
@@ -121,36 +232,85 @@ hda_widget_get_stream_support(hda_codec* codec, uint32 nodeID, uint32* formats,
} }
// #pragma mark - widget functions
static status_t static status_t
hda_widget_get_amplifier_capabilities(hda_codec* codec, uint32 nodeID) hda_widget_get_pm_support(hda_audio_group* audioGroup, hda_widget* widget)
{ {
status_t rc; return hda_get_pm_support(audioGroup->codec, widget->node_id,
&widget->pm);
}
static status_t
hda_widget_get_stream_support(hda_audio_group* audioGroup, hda_widget* widget)
{
if ((widget->capabilities.audio & AUDIO_CAP_FORMAT_OVERRIDE) == 0) {
// adopt capabilities of the audio group
widget->d.output.formats = audioGroup->supported_formats;
widget->d.output.rates = audioGroup->supported_rates;
return B_OK;
}
return hda_get_stream_support(audioGroup->codec, widget->node_id,
&widget->d.output.formats, &widget->d.output.rates);
}
static status_t
hda_widget_get_amplifier_capabilities(hda_audio_group* audioGroup,
hda_widget* widget)
{
uint32 response;
corb_t verb; corb_t verb;
uint32 resp;
verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER, if ((widget->capabilities.audio & AUDIO_CAP_OUTPUT_AMPLIFIER) != 0) {
PID_OUTPUT_AMPLIFIER_CAP); if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE) != 0) {
rc = hda_send_verbs(codec, &verb, &resp, 1); verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
if (rc == B_OK && resp != 0) { VID_GET_PARAMETER, PID_OUTPUT_AMPLIFIER_CAP);
dprintf("\tAMP: Mute: %s, step size: %ld, # steps: %ld, offset: %ld\n", status_t status = hda_send_verbs(audioGroup->codec, &verb,
(resp & (1 << 31)) ? "supported" : "N/A", &response, 1);
(resp >> 16) & 0x7F, if (status < B_OK)
(resp >> 8) & 0x7F, return status;
resp & 0x7F);
widget->capabilities.output_amplifier = response;
} else {
// adopt capabilities from the audio function group
widget->capabilities.output_amplifier
= audioGroup->output_amplifier_capabilities;
}
} }
return rc; if ((widget->capabilities.audio & AUDIO_CAP_INPUT_AMPLIFIER) != 0) {
if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE) != 0) {
verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
VID_GET_PARAMETER, PID_INPUT_AMPLIFIER_CAP);
status_t status = hda_send_verbs(audioGroup->codec, &verb,
&response, 1);
if (status < B_OK)
return status;
widget->capabilities.input_amplifier = response;
} else {
// adopt capabilities from the audio function group
widget->capabilities.input_amplifier
= audioGroup->input_amplifier_capabilities;
}
}
return B_OK;
} }
static status_t static status_t
hda_widget_get_connections(hda_codec* codec, uint32 nodeID, hda_widget* widget) hda_widget_get_connections(hda_audio_group* audioGroup, hda_widget* widget)
{ {
uint32 verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER, uint32 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
PID_CONNECTION_LIST_LENGTH); VID_GET_PARAMETER, PID_CONNECTION_LIST_LENGTH);
uint32 response; uint32 response;
if (hda_send_verbs(codec, &verb, &response, 1) != B_OK) if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) != B_OK)
return B_ERROR; return B_ERROR;
uint32 listEntries = response & 0x7f; uint32 listEntries = response & 0x7f;
@@ -162,8 +322,9 @@ hda_widget_get_connections(hda_codec* codec, uint32 nodeID, hda_widget* widget)
#if 1 #if 1
if (widget->num_inputs > 1) { if (widget->num_inputs > 1) {
// Get currently active connection // Get currently active connection
verb = MAKE_VERB(codec->addr, nodeID, VID_GET_CONNECTION_SELECT, 0); verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
if (hda_send_verbs(codec, &verb, &response, 1) == B_OK) VID_GET_CONNECTION_SELECT, 0);
if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) == B_OK)
widget->active_input = response & 0xff; widget->active_input = response & 0xff;
} }
#endif #endif
@@ -178,11 +339,12 @@ hda_widget_get_connections(hda_codec* codec, uint32 nodeID, hda_widget* widget)
if ((i % valuesPerEntry) == 0) { if ((i % valuesPerEntry) == 0) {
// We get 2 or 4 answers per call depending on if we're // We get 2 or 4 answers per call depending on if we're
// in short or long list mode // in short or long list mode
verb = MAKE_VERB(codec->addr, nodeID, verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
VID_GET_CONNECTION_LIST_ENTRY, i); VID_GET_CONNECTION_LIST_ENTRY, i);
if (hda_send_verbs(codec, &verb, &response, 1) != B_OK) { if (hda_send_verbs(audioGroup->codec, &verb, &response, 1)
!= B_OK) {
dprintf("hda: Error parsing inputs for widget %ld!\n", dprintf("hda: Error parsing inputs for widget %ld!\n",
nodeID); widget->node_id);
break; break;
} }
} }
@@ -214,36 +376,15 @@ hda_widget_get_connections(hda_codec* codec, uint32 nodeID, hda_widget* widget)
} }
widget->num_inputs = numInputs; widget->num_inputs = numInputs;
if (widget->num_inputs == 1)
widget->active_input = widget->inputs[0];
return B_OK; return B_OK;
} }
static const char* // #pragma mark - audio group functions
get_widget_type_name(hda_widget_type type)
{
switch (type) {
case WT_AUDIO_OUTPUT:
return "Audio Output";
case WT_AUDIO_INPUT:
return "Audio Input";
case WT_AUDIO_MIXER:
return "Audio Mixer";
case WT_AUDIO_SELECTOR:
return "Audio Selector";
case WT_PIN_COMPLEX:
return "Pin Complex";
case WT_POWER:
return "Power";
case WT_VOLUME_KNOB:
return "Volume Knob";
case WT_BEEP_GENERATOR:
return "Beep Generator";
case WT_VENDOR_DEFINED:
return "Vendor Defined";
default:
return "Unknown";
}
}
static status_t static status_t
@@ -252,9 +393,9 @@ hda_codec_parse_audio_group(hda_audio_group* audioGroup)
corb_t verbs[3]; corb_t verbs[3];
uint32 resp[3]; uint32 resp[3];
hda_widget_get_stream_support(audioGroup->codec, audioGroup->root_node_id, hda_get_stream_support(audioGroup->codec, audioGroup->root_node_id,
&audioGroup->supported_formats, &audioGroup->supported_rates); &audioGroup->supported_formats, &audioGroup->supported_rates);
hda_widget_get_pm_support(audioGroup->codec, audioGroup->root_node_id, hda_get_pm_support(audioGroup->codec, audioGroup->root_node_id,
&audioGroup->supported_pm); &audioGroup->supported_pm);
verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id, verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id,
@@ -291,134 +432,79 @@ hda_codec_parse_audio_group(hda_audio_group* audioGroup)
/* Iterate over all Widgets and collect info */ /* Iterate over all Widgets and collect info */
for (uint32 i = 0; i < audioGroup->widget_count; i++) { for (uint32 i = 0; i < audioGroup->widget_count; i++) {
uint32 widget = audioGroup->widget_start + i; hda_widget& widget = audioGroup->widgets[i];
uint32 nodeID = audioGroup->widget_start + i;
uint32 capabilities;
verbs[0] = MAKE_VERB(audioGroup->codec->addr, widget, VID_GET_PARAMETER, verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, VID_GET_PARAMETER,
PID_AUDIO_WIDGET_CAP); PID_AUDIO_WIDGET_CAP);
if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) != B_OK) if (hda_send_verbs(audioGroup->codec, verbs, &capabilities, 1) != B_OK)
return B_ERROR; return B_ERROR;
audioGroup->widgets[i].type = (hda_widget_type)(resp[0] >> 20); widget.type = (hda_widget_type)((capabilities & AUDIO_CAP_TYPE_MASK)
audioGroup->widgets[i].active_input = -1; >> AUDIO_CAP_TYPE_SHIFT);
widget.active_input = -1;
dprintf("%ld: %s\n", widget, widget.capabilities.audio = capabilities;
get_widget_type_name(audioGroup->widgets[i].type)); widget.node_id = nodeID;
char buf[256];
int off = 0;
buf[0] = '\0';
if (resp[0] & (1 << 11))
off += sprintf(buf + off, "[L-R Swap] ");
if (resp[0] & (1 << 10)) {
corb_t verb;
uint32 resp;
off += sprintf(buf + off, "[Power] ");
if ((capabilities & AUDIO_CAP_POWER_CONTROL) != 0) {
/* We support power; switch us on! */ /* We support power; switch us on! */
verb = MAKE_VERB(audioGroup->codec->addr, widget, verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
VID_SET_POWER_STATE, 0); VID_SET_POWER_STATE, 0);
hda_send_verbs(audioGroup->codec, &verb, &resp, 1); hda_send_verbs(audioGroup->codec, verbs, NULL, 1);
snooze(1000);
}
if ((capabilities & (AUDIO_CAP_INPUT_AMPLIFIER
| AUDIO_CAP_OUTPUT_AMPLIFIER)) != 0) {
hda_widget_get_amplifier_capabilities(audioGroup, &widget);
} }
if (resp[0] & (1 << 9)) dprintf("%ld: %s\n", nodeID, get_widget_type_name(widget.type));
off += sprintf(buf + off, "[Digital] ");
if (resp[0] & (1 << 7))
off += sprintf(buf + off, "[Unsol Capable] ");
if (resp[0] & (1 << 6))
off += sprintf(buf + off, "[Proc Widget] ");
if (resp[0] & (1 << 5))
off += sprintf(buf + off, "[Stripe] ");
if (resp[0] & (1 << 4))
off += sprintf(buf + off, "[Format Override] ");
if (resp[0] & (1 << 3))
off += sprintf(buf + off, "[Amp Param Override] ");
if (resp[0] & (1 << 2))
off += sprintf(buf + off, "[Out Amp] ");
if (resp[0] & (1 << 1))
off += sprintf(buf + off, "[In Amp] ");
if (resp[0] & (1 << 0))
off += sprintf(buf + off, "[Stereo] ");
switch (audioGroup->widgets[i].type) { switch (widget.type) {
case WT_AUDIO_OUTPUT: case WT_AUDIO_OUTPUT:
hda_widget_get_stream_support(audioGroup->codec, widget,
&audioGroup->widgets[i].d.input.formats,
&audioGroup->widgets[i].d.input.rates);
hda_widget_get_amplifier_capabilities(audioGroup->codec, widget);
break;
case WT_AUDIO_INPUT: case WT_AUDIO_INPUT:
hda_widget_get_stream_support(audioGroup->codec, widget, hda_widget_get_stream_support(audioGroup, &widget);
&audioGroup->widgets[i].d.input.formats,
&audioGroup->widgets[i].d.input.rates);
hda_widget_get_amplifier_capabilities(audioGroup->codec, widget);
break;
case WT_AUDIO_MIXER:
hda_widget_get_amplifier_capabilities(audioGroup->codec, widget);
break;
case WT_AUDIO_SELECTOR:
hda_widget_get_amplifier_capabilities(audioGroup->codec, widget);
break; break;
case WT_PIN_COMPLEX: case WT_PIN_COMPLEX:
verbs[0] = MAKE_VERB(audioGroup->codec->addr, widget, verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
VID_GET_PARAMETER, PID_PIN_CAP); VID_GET_PARAMETER, PID_PIN_CAP);
if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) {
audioGroup->widgets[i].d.pin.input = resp[0] & (1 << 5); widget.d.pin.input = resp[0] & (1 << 5);
audioGroup->widgets[i].d.pin.output = resp[0] & (1 << 4); widget.d.pin.output = resp[0] & (1 << 4);
dprintf("\t%s%s\n", dprintf("\t%s%s\n", widget.d.pin.input ? "[Input] " : "",
audioGroup->widgets[i].d.pin.input ? "[Input] " : "", widget.d.pin.output ? "[Output]" : "");
audioGroup->widgets[i].d.pin.output ? "[Output]" : "");
} else { } else {
dprintf("%s: Error getting Pin Complex IO\n", __func__); dprintf("%s: Error getting Pin Complex IO\n", __func__);
} }
verbs[0] = MAKE_VERB(audioGroup->codec->addr, widget, verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
VID_GET_CONFIGURATION_DEFAULT, 0); VID_GET_CONFIGURATION_DEFAULT, 0);
if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) {
audioGroup->widgets[i].d.pin.device = (pin_dev_type) widget.d.pin.device = (pin_dev_type)
((resp[0] >> 20) & 0xf); ((resp[0] >> 20) & 0xf);
dprintf("\t%s, %s, %s, %s\n", dprintf("\t%s, %s, %s, %s\n",
kPortConnector[resp[0] >> 30], kPortConnector[resp[0] >> 30],
kDefaultDevice[audioGroup->widgets[i].d.pin.device], kDefaultDevice[widget.d.pin.device],
kConnectionType[(resp[0] >> 16) & 0xF], kConnectionType[(resp[0] >> 16) & 0xF],
kJackColor[(resp[0] >> 12) & 0xF]); kJackColor[(resp[0] >> 12) & 0xF]);
} }
hda_widget_get_amplifier_capabilities(audioGroup->codec, widget);
break; break;
default: default:
break; break;
} }
if (off) hda_widget_get_pm_support(audioGroup, &widget);
dprintf("\t%s\n", buf); hda_widget_get_connections(audioGroup, &widget);
hda_widget_get_pm_support(audioGroup->codec, widget, dump_widget_audio_capabilities(capabilities);
&audioGroup->widgets[i].pm); dump_widget_amplifier_capabilities(widget, true);
hda_widget_get_connections(audioGroup->codec, widget, dump_widget_amplifier_capabilities(widget, false);
&audioGroup->widgets[i]); dump_widget_inputs(widget);
// dump connections
buf[0] = '\0';
off = 0;
for (uint32 inputIndex = 0; inputIndex
< audioGroup->widgets[i].num_inputs; inputIndex++) {
int32 input = audioGroup->widgets[i].inputs[inputIndex];
if ((int32)inputIndex != audioGroup->widgets[i].active_input)
off += sprintf(buf + off, "%ld ", input);
else
off += sprintf(buf + off, "(%ld) ", input);
}
if (off != 0)
dprintf("\tConnections: %s\n", buf);
} }
return B_OK; return B_OK;
@@ -4,6 +4,7 @@
* *
* Authors: * Authors:
* Ithamar Adema, ithamar AT unet DOT nl * Ithamar Adema, ithamar AT unet DOT nl
* Axel Dörfler, [email protected]
*/ */
#ifndef HDA_CODEC_H #ifndef HDA_CODEC_H
#define HDA_CODEC_H #define HDA_CODEC_H
@@ -135,6 +136,33 @@ enum pin_dev_type {
#define PID_OUTPUT_AMPLIFIER_CAP 0x12 #define PID_OUTPUT_AMPLIFIER_CAP 0x12
#define PID_VOLUME_KNOB_CAP 0x13 #define PID_VOLUME_KNOB_CAP 0x13
/* Audio widget capabilities */
#define AUDIO_CAP_DELAY_MASK 0x000f0000
#define AUDIO_CAP_DELAY_SHIFT 16
#define AUDIO_CAP_TYPE_MASK 0x00f00000
#define AUDIO_CAP_TYPE_SHIFT 20
#define AUDIO_CAP_STEREO (1L << 0)
#define AUDIO_CAP_INPUT_AMPLIFIER (1L << 1)
#define AUDIO_CAP_OUTPUT_AMPLIFIER (1L << 2)
#define AUDIO_CAP_AMPLIFIER_OVERRIDE (1L << 3)
#define AUDIO_CAP_FORMAT_OVERRIDE (1L << 4)
#define AUDIO_CAP_STRIPE (1L << 5)
#define AUDIO_CAP_PROCESSING_CONTROLS (1L << 6)
#define AUDIO_CAP_UNSOLICITED_RESPONSES (1L << 7)
#define AUDIO_CAP_CONNECTION_LIST (1L << 8)
#define AUDIO_CAP_DIGITAL (1L << 9)
#define AUDIO_CAP_POWER_CONTROL (1L << 10)
#define AUDIO_CAP_LEFT_RIGHT_SWAP (1L << 11)
/* Amplifier capabilities */
#define AMP_CAP_MUTE 0xf0000000
#define AMP_CAP_STEP_SIZE_MASK 0x007f0000
#define AMP_CAP_STEP_SIZE_SHIFT 16
#define AMP_CAP_NUM_STEPS_MASK 0x00007f00
#define AMP_CAP_NUM_STEPS_SHIFT 8
#define AMP_CAP_OFFSET_MASK 0x0000007f
/* PCM support */ /* PCM support */
#define PCM_8_BIT (1L << 16) #define PCM_8_BIT (1L << 16)
#define PCM_16_BIT (1L << 17) #define PCM_16_BIT (1L << 17)