diff options
Diffstat (limited to 'sound/pci')
36 files changed, 1798 insertions, 447 deletions
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 6cf1de8042e8..0e247cb90ecc 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -763,9 +763,9 @@ static void snd_als4000_configure(struct snd_sb *chip) /* SPECS_PAGE: 39 */ for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i) snd_als4k_gcr_write(chip, i, 0); - + /* enable burst mode to prevent dropouts during high PCI bus usage */ snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL, - snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL)); + (snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04); spin_unlock_irq(&chip->reg_lock); } diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 1db586af4f9c..c80b0b863c54 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -460,6 +460,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); int err; u16 format; + int width; unsigned int bytes_per_sec; print_hwparams(params); @@ -512,9 +513,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, dpcm->hpi_buffer_attached); } bytes_per_sec = params_rate(params) * params_channels(params); - bytes_per_sec *= snd_pcm_format_width(params_format(params)); + width = snd_pcm_format_width(params_format(params)); + bytes_per_sec *= width; bytes_per_sec /= 8; - if (bytes_per_sec <= 0) + if (width < 0 || bytes_per_sec == 0) return -EINVAL; dpcm->bytes_per_sec = bytes_per_sec; @@ -1383,7 +1385,7 @@ static char *asihpi_src_names[] = compile_time_assert( (ARRAY_SIZE(asihpi_src_names) == - (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)), + (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)), assert_src_names_size); #if ASI_STYLE_NAMES @@ -1414,7 +1416,7 @@ static char *asihpi_dst_names[] = compile_time_assert( (ARRAY_SIZE(asihpi_dst_names) == - (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)), + (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)), assert_dst_names_size); static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl, @@ -2171,7 +2173,7 @@ static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol, &src_node_type, &src_node_index); sprintf(uinfo->value.enumerated.name, "%s %d", - asihpi_src_names[src_node_type - HPI_SOURCENODE_BASE], + asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE], src_node_index); return 0; } @@ -2603,8 +2605,8 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) } - hpi_ctl.src_node_type -= HPI_SOURCENODE_BASE; - hpi_ctl.dst_node_type -= HPI_DESTNODE_BASE; + hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE; + hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE; /* ASI50xx in SSX mode has multiple meters on the same node. Use subindex to create distinct ALSA controls diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h index 0173bbe62b67..23399d02f666 100644 --- a/sound/pci/asihpi/hpi.h +++ b/sound/pci/asihpi/hpi.h @@ -50,7 +50,8 @@ i.e 3.05.02 is a development version #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, 3, 25) +#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 4, 1) +#define HPI_VER_STRING "4.04.01" /* Library version as documented in hpi-api-versions.txt */ #define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0) @@ -203,8 +204,6 @@ enum HPI_SOURCENODES { exists on a destination node can be searched for using a source node value of either 0, or HPI_SOURCENODE_NONE */ HPI_SOURCENODE_NONE = 100, - /** \deprecated Use HPI_SOURCENODE_NONE instead. */ - HPI_SOURCENODE_BASE = 100, /** Out Stream (Play) node. */ HPI_SOURCENODE_OSTREAM = 101, /** Line in node - could be analog, AES/EBU or network. */ @@ -235,8 +234,6 @@ enum HPI_DESTNODES { exists on a source node can be searched for using a destination node value of either 0, or HPI_DESTNODE_NONE */ HPI_DESTNODE_NONE = 200, - /** \deprecated Use HPI_DESTNODE_NONE instead. */ - HPI_DESTNODE_BASE = 200, /** In Stream (Record) node. */ HPI_DESTNODE_ISTREAM = 201, HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ @@ -432,7 +429,18 @@ Property 2 - adapter can do stream grouping (supports SSX2) Property 1 - adapter can do samplerate conversion (MRX) Property 2 - adapter can do timestretch (TSX) */ - HPI_ADAPTER_PROPERTY_CAPS2 = 269 + HPI_ADAPTER_PROPERTY_CAPS2 = 269, + +/** Readonly adapter sync header connection count. +*/ + HPI_ADAPTER_PROPERTY_SYNC_HEADER_CONNECTIONS = 270, +/** Readonly supports SSX2 property. +Indicates the adapter supports SSX2 in some mode setting. The +return value is true (1) or false (0). If the current adapter +mode is MONO SSX2 is disabled, even though this property will +return true. +*/ + HPI_ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271 }; /** Adapter mode commands @@ -813,8 +821,6 @@ enum HPI_SAMPLECLOCK_SOURCES { /** The sampleclock output is derived from its local samplerate generator. The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */ HPI_SAMPLECLOCK_SOURCE_LOCAL = 1, -/** \deprecated Use HPI_SAMPLECLOCK_SOURCE_LOCAL instead */ - HPI_SAMPLECLOCK_SOURCE_ADAPTER = 1, /** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/ HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2, /** From external wordclock connector */ @@ -825,10 +831,6 @@ enum HPI_SAMPLECLOCK_SOURCES { HPI_SAMPLECLOCK_SOURCE_SMPTE = 5, /** One of the aesebu inputs */ HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6, -/** \deprecated The first aesebu input with a valid signal -Superseded by separate Auto enable flag -*/ - HPI_SAMPLECLOCK_SOURCE_AESEBU_AUTO = 7, /** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */ HPI_SAMPLECLOCK_SOURCE_NETWORK = 8, /** From previous adjacent module (ASI2416 only)*/ @@ -1015,8 +1017,6 @@ enum HPI_ERROR_CODES { HPI_ERROR_CONTROL_DISABLED = 404, /** I2C transaction failed due to a missing ACK. */ HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405, - /** Control attribute is valid, but not supported by this hardware. */ - HPI_ERROR_UNSUPPORTED_CONTROL_ATTRIBUTE = 406, /** Control is busy, or coming out of reset and cannot be accessed at this time. */ HPI_ERROR_CONTROL_NOT_READY = 407, @@ -1827,13 +1827,41 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys, Compressor Expander control *******************************/ -u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, - u16 attack, u16 decay, short ratio100, short threshold0_01dB, - short makeup_gain0_01dB); +u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 on); + +u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 *pon); + +u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys, + u32 h_control, short makeup_gain0_01dB); + +u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys, + u32 h_control, short *pn_makeup_gain0_01dB); + +u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys + *ph_subsys, u32 h_control, u32 index, u32 attack); + +u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys + *ph_subsys, u32 h_control, u32 index, u32 *pw_attack); + +u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, u32 decay); + +u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, u32 *pw_decay); + +u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, short threshold0_01dB); + +u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, short *pn_threshold0_01dB); + +u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, u32 ratio100); -u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, - u16 *pw_attack, u16 *pw_decay, short *pw_ratio100, - short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB); +u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, u32 *pw_ratio100); /******************************* Cobranet HMI control diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 12dab5e4892c..f7e374ec4414 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -687,6 +687,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, switch (pao->pci.subsys_device_id) { case 0x5100: case 0x5110: /* ASI5100 revB or higher with C6711D */ + case 0x5200: /* ASI5200 PC_ie version of ASI5100 */ case 0x6100: case 0x6200: boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200); @@ -1133,6 +1134,12 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, subsys_device_id) == HPI_ADAPTER_FAMILY_ASI(0x5100)) mask = 0x00000000L; + /* ASI5200 uses AX6 code, */ + /* but has no PLD r/w register to test */ + if (HPI_ADAPTER_FAMILY_ASI(pao->pci. + subsys_device_id) == + HPI_ADAPTER_FAMILY_ASI(0x5200)) + mask = 0x00000000L; break; case HPI_ADAPTER_FAMILY_ASI(0x8800): /* ASI8800 has 16bit path to FPGA */ diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 3b4413448226..22c5fc625533 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c @@ -941,8 +941,7 @@ static void outstream_host_buffer_free(struct hpi_adapter_obj *pao, } -static u32 outstream_get_space_available(struct hpi_hostbuffer_status - *status) +static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status) { return status->size_in_bytes - (status->host_index - status->dSP_index); @@ -987,6 +986,10 @@ static void outstream_write(struct hpi_adapter_obj *pao, /* write it */ phm->function = HPI_OSTREAM_WRITE; hw_message(pao, phm, phr); + + if (phr->error) + return; + /* update status information that the DSP would typically * update (and will update next time the DSP * buffer update task reads data from the host BBM buffer) diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index fdd0ce02aa68..16f502d459de 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -104,9 +104,9 @@ typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *); #define STR_ROLE_FIELD_MAX 255U struct hpi_entity_str { - uint16_t size; - uint8_t type; - uint8_t role; + u16 size; + u8 type; + u8 role; }; #if defined(_MSC_VER) @@ -119,11 +119,11 @@ struct hpi_entity { #if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008)) /* DSP C6000 compiler v6.0.8 and lower do not support flexible array member */ - uint8_t value[]; + u8 value[]; #else /* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */ #define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE - uint8_t value[1]; + u8 value[1]; #endif }; @@ -142,12 +142,15 @@ enum HPI_BUSES { /******************************************* CONTROL ATTRIBUTES ****/ /* (in order of control type ID */ - /* This allows for 255 control types, 256 unique attributes each */ +/* This allows for 255 control types, 256 unique attributes each */ #define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai) /* Get the sub-index of the attribute for a control type */ #define HPI_CTL_ATTR_INDEX(i) (i&0xff) +/* Extract the control from the control attribute */ +#define HPI_CTL_ATTR_CONTROL(i) (i>>8) + /* Generic control attributes. */ /** Enable a control. @@ -311,8 +314,7 @@ Used for HPI_ChannelModeSet/Get() /* Microphone control attributes */ #define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1) -/** Equalizer control attributes -*/ +/** Equalizer control attributes */ /** Used to get number of filters in an EQ. (Can't set) */ #define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1) /** Set/get the filter by type, freq, Q, gain */ @@ -320,13 +322,15 @@ Used for HPI_ChannelModeSet/Get() /** Get the biquad coefficients */ #define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3) -#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1) +/* Note compander also uses HPI_GENERIC_ENABLE */ +#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1) +#define HPI_COMPANDER_MAKEUPGAIN HPI_CTL_ATTR(COMPANDER, 2) +#define HPI_COMPANDER_THRESHOLD HPI_CTL_ATTR(COMPANDER, 3) +#define HPI_COMPANDER_RATIO HPI_CTL_ATTR(COMPANDER, 4) +#define HPI_COMPANDER_ATTACK HPI_CTL_ATTR(COMPANDER, 5) +#define HPI_COMPANDER_DECAY HPI_CTL_ATTR(COMPANDER, 6) -/* Cobranet control attributes. - MUST be distinct from all other control attributes. - This is so that host side processing can easily identify a Cobranet control - and apply additional host side operations (like copying data) as required. -*/ +/* Cobranet control attributes. */ #define HPI_COBRANET_SET HPI_CTL_ATTR(COBRANET, 1) #define HPI_COBRANET_GET HPI_CTL_ATTR(COBRANET, 2) #define HPI_COBRANET_SET_DATA HPI_CTL_ATTR(COBRANET, 3) @@ -1512,11 +1516,11 @@ struct hpi_control_cache_single { struct hpi_control_cache_info i; union { struct { /* volume */ - u16 an_log[2]; + short an_log[2]; } v; struct { /* peak meter */ - u16 an_log_peak[2]; - u16 an_logRMS[2]; + short an_log_peak[2]; + short an_logRMS[2]; } p; struct { /* channel mode */ u16 mode; @@ -1526,7 +1530,7 @@ struct hpi_control_cache_single { u16 source_node_index; } x; struct { /* level/trim */ - u16 an_log[2]; + short an_log[2]; } l; struct { /* tuner - partial caching. some attributes go to the DSP. */ diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c index fcd64539d9ef..dda4f1c6f658 100644 --- a/sound/pci/asihpi/hpicmn.c +++ b/sound/pci/asihpi/hpicmn.c @@ -353,7 +353,12 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, phr->u.c.param1 = pC->u.t.band; else if ((phm->u.c.attribute == HPI_TUNER_LEVEL) && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE)) - phr->u.c.param1 = pC->u.t.level; + if (pC->u.t.level == HPI_ERROR_ILLEGAL_CACHE_VALUE) { + phr->u.c.param1 = 0; + phr->error = + HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; + } else + phr->u.c.param1 = pC->u.t.level; else found = 0; break; @@ -397,7 +402,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, if (pC->u.clk.source_index == HPI_ERROR_ILLEGAL_CACHE_VALUE) { phr->u.c.param1 = 0; - phr->error = HPI_ERROR_INVALID_OPERATION; + phr->error = + HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; } else phr->u.c.param1 = pC->u.clk.source_index; } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) diff --git a/sound/pci/asihpi/hpidebug.c b/sound/pci/asihpi/hpidebug.c index 4cd85a401b34..949836ec913a 100644 --- a/sound/pci/asihpi/hpidebug.c +++ b/sound/pci/asihpi/hpidebug.c @@ -111,7 +111,7 @@ make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS) &hpi_profile_strings,\ &hpi_control_strings, \ &hpi_asyncevent_strings \ -}; +} make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS) compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match); diff --git a/sound/pci/asihpi/hpidebug.h b/sound/pci/asihpi/hpidebug.h index 44dccadcc25b..a2f0952a99f0 100644 --- a/sound/pci/asihpi/hpidebug.h +++ b/sound/pci/asihpi/hpidebug.h @@ -356,7 +356,7 @@ compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27), "HPI_SOURCENODE_ADAPTER" \ } -compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) == +compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_NONE + 1) == (12), sourcenode_strings_match_defs); #define HPI_DESTNODE_STRINGS \ @@ -370,7 +370,7 @@ compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) == "HPI_DESTNODE_COBRANET", \ "HPI_DESTNODE_ANALOG" \ } -compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8), +compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_NONE + 1) == (8), destnode_strings_match_defs); #define HPI_CONTROL_CHANNEL_MODE_STRINGS \ diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c index 298eef3e20e9..1e92eb6dd509 100644 --- a/sound/pci/asihpi/hpifunc.c +++ b/sound/pci/asihpi/hpifunc.c @@ -96,8 +96,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR) static struct hpi_hsubsys gh_subsys; -struct hpi_hsubsys *hpi_subsys_create(void - ) +struct hpi_hsubsys *hpi_subsys_create(void) { struct hpi_message hm; struct hpi_response hr; @@ -302,6 +301,7 @@ u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_SET_MODE); hm.adapter_index = adapter_index; @@ -510,7 +510,7 @@ u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys, hm.adapter_index = adapter_index; hm.u.ax.debug_read.dsp_address = dsp_address; - if (*count_bytes > sizeof(hr.u.bytes)) + if (*count_bytes > (int)sizeof(hr.u.bytes)) *count_bytes = sizeof(hr.u.bytes); hm.u.ax.debug_read.count_bytes = *count_bytes; @@ -976,6 +976,7 @@ u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, HPI_OSTREAM_ANC_READ); u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); @@ -1581,6 +1582,7 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -1591,6 +1593,22 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys, return hr.error; } +static u16 hpi_control_log_set2(u32 h_control, u16 attrib, short sv0, + short sv1) +{ + struct hpi_message hm; + struct hpi_response hr; + + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, + HPI_CONTROL_SET_STATE); + u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); + hm.u.c.attribute = attrib; + hm.u.c.an_log_value[0] = sv0; + hm.u.c.an_log_value[1] = sv1; + hpi_send_recv(&hm, &hr); + return hr.error; +} + static u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, const u32 h_control, const u16 attrib, u32 param1, u32 param2, @@ -1598,6 +1616,7 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -1605,8 +1624,8 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, hm.u.c.param1 = param1; hm.u.c.param2 = param2; hpi_send_recv(&hm, &hr); - if (pparam1) - *pparam1 = hr.u.c.param1; + + *pparam1 = hr.u.c.param1; if (pparam2) *pparam2 = hr.u.c.param2; @@ -1617,10 +1636,23 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, hpi_control_param_get(s, h, a, 0, 0, p1, NULL) #define hpi_control_param2_get(s, h, a, p1, p2) \ hpi_control_param_get(s, h, a, 0, 0, p1, p2) -#define hpi_control_ex_param1_get(s, h, a, p1) \ - hpi_control_ex_param_get(s, h, a, 0, 0, p1, NULL) -#define hpi_control_ex_param2_get(s, h, a, p1, p2) \ - hpi_control_ex_param_get(s, h, a, 0, 0, p1, p2) + +static u16 hpi_control_log_get2(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u16 attrib, short *sv0, short *sv1) +{ + struct hpi_message hm; + struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, + HPI_CONTROL_GET_STATE); + u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); + hm.u.c.attribute = attrib; + + hpi_send_recv(&hm, &hr); + *sv0 = hr.u.c.an_log_value[0]; + if (sv1) + *sv1 = hr.u.c.an_log_value[1]; + return hr.error; +} static u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, @@ -1629,6 +1661,7 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_INFO); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -1643,9 +1676,8 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, return hr.error; } -static u16 hpi_control_get_string(const struct hpi_hsubsys *ph_subsys, - const u32 h_control, const u16 attribute, char *psz_string, - const u32 string_length) +static u16 hpi_control_get_string(const u32 h_control, const u16 attribute, + char *psz_string, const u32 string_length) { unsigned int sub_string_index = 0, j = 0; char c = 0; @@ -1916,6 +1948,7 @@ u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, HPI_CONTROL_SET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -1941,6 +1974,7 @@ u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -1980,6 +2014,7 @@ u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2006,6 +2041,7 @@ u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys, u32 byte_count; u32 iP; u16 error; + error = hpi_cobranet_hmi_read(ph_subsys, h_control, HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count, (u8 *)&iP); @@ -2082,6 +2118,7 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys, u32 byte_count; u16 error; u32 mAC; + error = hpi_cobranet_hmi_read(ph_subsys, h_control, HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count, (u8 *)&mAC); @@ -2103,53 +2140,111 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys, return error; } -u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, - u16 attack, u16 decay, short ratio100, short threshold0_01dB, - short makeup_gain0_01dB) +u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 enable) +{ + return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE, + enable, 0); +} + +u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 *enable) +{ + return hpi_control_param1_get(ph_subsys, h_control, + HPI_GENERIC_ENABLE, enable); +} + +u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys, + u32 h_control, short makeup_gain0_01dB) +{ + return hpi_control_log_set2(h_control, HPI_COMPANDER_MAKEUPGAIN, + makeup_gain0_01dB, 0); +} + +u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys, + u32 h_control, short *makeup_gain0_01dB) +{ + return hpi_control_log_get2(ph_subsys, h_control, + HPI_COMPANDER_MAKEUPGAIN, makeup_gain0_01dB, NULL); +} + +u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys + *ph_subsys, u32 h_control, unsigned int index, u32 attack) +{ + return hpi_control_param_set(ph_subsys, h_control, + HPI_COMPANDER_ATTACK, attack, index); +} + +u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys + *ph_subsys, u32 h_control, unsigned int index, u32 *attack) +{ + return hpi_control_param_get(ph_subsys, h_control, + HPI_COMPANDER_ATTACK, 0, index, attack, NULL); +} + +u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys, + u32 h_control, unsigned int index, u32 decay) +{ + return hpi_control_param_set(ph_subsys, h_control, + HPI_COMPANDER_DECAY, decay, index); +} + +u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys, + u32 h_control, unsigned int index, u32 *decay) +{ + return hpi_control_param_get(ph_subsys, h_control, + HPI_COMPANDER_DECAY, 0, index, decay, NULL); + +} + +u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys, + u32 h_control, unsigned int index, short threshold0_01dB) { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); - - hm.u.c.param1 = attack + ((u32)ratio100 << 16); - hm.u.c.param2 = (decay & 0xFFFFL); + hm.u.c.attribute = HPI_COMPANDER_THRESHOLD; + hm.u.c.param2 = index; hm.u.c.an_log_value[0] = threshold0_01dB; - hm.u.c.an_log_value[1] = makeup_gain0_01dB; - hm.u.c.attribute = HPI_COMPANDER_PARAMS; hpi_send_recv(&hm, &hr); return hr.error; } -u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, - u16 *pw_attack, u16 *pw_decay, short *pw_ratio100, - short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB) +u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys, + u32 h_control, unsigned int index, short *threshold0_01dB) { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); - hm.u.c.attribute = HPI_COMPANDER_PARAMS; + hm.u.c.attribute = HPI_COMPANDER_THRESHOLD; + hm.u.c.param2 = index; hpi_send_recv(&hm, &hr); + *threshold0_01dB = hr.u.c.an_log_value[0]; - if (pw_attack) - *pw_attack = (short)(hr.u.c.param1 & 0xFFFF); - if (pw_decay) - *pw_decay = (short)(hr.u.c.param2 & 0xFFFF); - if (pw_ratio100) - *pw_ratio100 = (short)(hr.u.c.param1 >> 16); + return hr.error; +} - if (pn_threshold0_01dB) - *pn_threshold0_01dB = hr.u.c.an_log_value[0]; - if (pn_makeup_gain0_01dB) - *pn_makeup_gain0_01dB = hr.u.c.an_log_value[1]; +u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, u32 ratio100) +{ + return hpi_control_param_set(ph_subsys, h_control, + HPI_COMPANDER_RATIO, ratio100, index); +} - return hr.error; +u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys, + u32 h_control, u32 index, u32 *ratio100) +{ + return hpi_control_param_get(ph_subsys, h_control, + HPI_COMPANDER_RATIO, 0, index, ratio100, NULL); } u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, @@ -2157,6 +2252,7 @@ u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2181,37 +2277,16 @@ u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, short an_gain0_01dB[HPI_MAX_CHANNELS] ) { - struct hpi_message hm; - struct hpi_response hr; - - hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, - HPI_CONTROL_SET_STATE); - u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); - memcpy(hm.u.c.an_log_value, an_gain0_01dB, - sizeof(short) * HPI_MAX_CHANNELS); - hm.u.c.attribute = HPI_LEVEL_GAIN; - - hpi_send_recv(&hm, &hr); - - return hr.error; + return hpi_control_log_set2(h_control, HPI_LEVEL_GAIN, + an_gain0_01dB[0], an_gain0_01dB[1]); } u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, short an_gain0_01dB[HPI_MAX_CHANNELS] ) { - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, - HPI_CONTROL_GET_STATE); - u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); - hm.u.c.attribute = HPI_LEVEL_GAIN; - - hpi_send_recv(&hm, &hr); - - memcpy(an_gain0_01dB, hr.u.c.an_log_value, - sizeof(short) * HPI_MAX_CHANNELS); - return hr.error; + return hpi_control_log_get2(ph_subsys, h_control, HPI_LEVEL_GAIN, + &an_gain0_01dB[0], &an_gain0_01dB[1]); } u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys, @@ -2413,6 +2488,7 @@ u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2439,6 +2515,7 @@ u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2460,6 +2537,7 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2623,8 +2701,8 @@ u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys, u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *state) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_TONEDETECTOR_STATE, 0, 0, (u32 *)state, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_TONEDETECTOR_STATE, state); } u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, @@ -2637,8 +2715,8 @@ u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *enable) { - return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE, - 0, 0, (u32 *)enable, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_GENERIC_ENABLE, enable); } u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, @@ -2651,8 +2729,8 @@ u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *event_enable) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_GENERIC_EVENT_ENABLE, event_enable); } u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, @@ -2665,15 +2743,15 @@ u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, int *threshold) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_TONEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_TONEDETECTOR_THRESHOLD, (u32 *)threshold); } u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *state) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_SILENCEDETECTOR_STATE, 0, 0, (u32 *)state, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_SILENCEDETECTOR_STATE, state); } u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, @@ -2686,50 +2764,50 @@ u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *enable) { - return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE, - 0, 0, (u32 *)enable, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_GENERIC_ENABLE, enable); } u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 event_enable) { return hpi_control_param_set(ph_subsys, h_control, - HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0); + HPI_GENERIC_EVENT_ENABLE, event_enable, 0); } u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *event_enable) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_GENERIC_EVENT_ENABLE, event_enable); } u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 delay) { return hpi_control_param_set(ph_subsys, h_control, - HPI_SILENCEDETECTOR_DELAY, (u32)delay, 0); + HPI_SILENCEDETECTOR_DELAY, delay, 0); } u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *delay) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_SILENCEDETECTOR_DELAY, 0, 0, (u32 *)delay, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_SILENCEDETECTOR_DELAY, delay); } u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, int threshold) { return hpi_control_param_set(ph_subsys, h_control, - HPI_SILENCEDETECTOR_THRESHOLD, (u32)threshold, 0); + HPI_SILENCEDETECTOR_THRESHOLD, threshold, 0); } u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, int *threshold) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_SILENCEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_SILENCEDETECTOR_THRESHOLD, (u32 *)threshold); } u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys, @@ -2822,6 +2900,7 @@ u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2838,6 +2917,7 @@ u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2894,14 +2974,14 @@ u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control, u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys, u32 h_control, char *psz_dsp_version, const u32 string_size) { - return hpi_control_get_string(ph_subsys, h_control, + return hpi_control_get_string(h_control, HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size); } u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys, u32 h_control, char *psz_sdk_version, const u32 string_size) { - return hpi_control_get_string(ph_subsys, h_control, + return hpi_control_get_string(h_control, HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size); } @@ -2942,15 +3022,15 @@ u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control, u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *pquality) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_TUNER_HDRADIO_SIGNAL_QUALITY, pquality); } u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *pblend) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_TUNER_HDRADIO_BLEND, pblend); } u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys, @@ -2965,6 +3045,7 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -2981,43 +3062,43 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control, u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys, u32 h_control, char *psz_string, const u32 data_length) { - return hpi_control_get_string(ph_subsys, h_control, - HPI_PAD_CHANNEL_NAME, psz_string, data_length); + return hpi_control_get_string(h_control, HPI_PAD_CHANNEL_NAME, + psz_string, data_length); } u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control, char *psz_string, const u32 data_length) { - return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_ARTIST, - psz_string, data_length); + return hpi_control_get_string(h_control, HPI_PAD_ARTIST, psz_string, + data_length); } u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control, char *psz_string, const u32 data_length) { - return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_TITLE, - psz_string, data_length); + return hpi_control_get_string(h_control, HPI_PAD_TITLE, psz_string, + data_length); } u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control, char *psz_string, const u32 data_length) { - return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_COMMENT, - psz_string, data_length); + return hpi_control_get_string(h_control, HPI_PAD_COMMENT, psz_string, + data_length); } u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *ppTY) { - return hpi_control_param_get(ph_subsys, h_control, - HPI_PAD_PROGRAM_TYPE, 0, 0, ppTY, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_PAD_PROGRAM_TYPE, ppTY); } u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control, u32 *ppI) { - return hpi_control_param_get(ph_subsys, h_control, HPI_PAD_PROGRAM_ID, - 0, 0, ppI, NULL); + return hpi_control_param1_get(ph_subsys, h_control, + HPI_PAD_PROGRAM_ID, ppI); } u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys, @@ -3031,36 +3112,16 @@ u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, short an_log_gain[HPI_MAX_CHANNELS] ) { - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, - HPI_CONTROL_SET_STATE); - u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); - memcpy(hm.u.c.an_log_value, an_log_gain, - sizeof(short) * HPI_MAX_CHANNELS); - hm.u.c.attribute = HPI_VOLUME_GAIN; - - hpi_send_recv(&hm, &hr); - - return hr.error; + return hpi_control_log_set2(h_control, HPI_VOLUME_GAIN, + an_log_gain[0], an_log_gain[1]); } u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, short an_log_gain[HPI_MAX_CHANNELS] ) { - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, - HPI_CONTROL_GET_STATE); - u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); - hm.u.c.attribute = HPI_VOLUME_GAIN; - - hpi_send_recv(&hm, &hr); - - memcpy(an_log_gain, hr.u.c.an_log_value, - sizeof(short) * HPI_MAX_CHANNELS); - return hr.error; + return hpi_control_log_get2(ph_subsys, h_control, HPI_VOLUME_GAIN, + &an_log_gain[0], &an_log_gain[1]); } u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, @@ -3068,6 +3129,7 @@ u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_GET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -3094,6 +3156,7 @@ u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys, { struct hpi_message hm; struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); @@ -3170,43 +3233,42 @@ static size_t entity_type_to_size[LAST_ENTITY_TYPE] = { 6 * sizeof(char), }; -inline size_t hpi_entity_size(struct hpi_entity *entity_ptr) +static inline size_t hpi_entity_size(struct hpi_entity *entity_ptr) { return entity_ptr->header.size; } -inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr) +static inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr) { return sizeof(entity_ptr->header); } -inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr) +static inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr) { return hpi_entity_size(entity_ptr) - hpi_entity_header_size(entity_ptr); } -inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr) +static inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr) { return hpi_entity_value_size(entity_ptr) / entity_type_to_size[entity_ptr->header.type]; } -inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity +static inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity *entity_ptr) { - return (void *)(((uint8_t *) entity_ptr) + - hpi_entity_size(entity_ptr)); + return (void *)(((u8 *)entity_ptr) + hpi_entity_size(entity_ptr)); } -inline u16 hpi_entity_check_type(const enum e_entity_type t) +static inline u16 hpi_entity_check_type(const enum e_entity_type t) { if (t >= 0 && t < STR_TYPE_FIELD_MAX) return 0; return HPI_ERROR_ENTITY_TYPE_INVALID; } -inline u16 hpi_entity_check_role(const enum e_entity_role r) +static inline u16 hpi_entity_check_role(const enum e_entity_role r) { if (r >= 0 && r < STR_ROLE_FIELD_MAX) return 0; @@ -3624,6 +3686,7 @@ u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async, u16 maximum_events, struct hpi_async_event *p_events, u16 *pw_number_returned) { + return 0; } diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index 2ee90dc3d897..f01ab964f602 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c @@ -741,7 +741,7 @@ static void HPIMSGX__reset(u16 adapter_index) hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_FIND_ADAPTERS, 0); memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr, - sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS)); + sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS)); for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) { diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 7396ac54e99f..62895a719fcb 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -121,11 +121,17 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg; /* Read the message and response pointers from user space. */ - get_user(puhm, &phpi_ioctl_data->phm); - get_user(puhr, &phpi_ioctl_data->phr); + if (get_user(puhm, &phpi_ioctl_data->phm) || + get_user(puhr, &phpi_ioctl_data->phr)) { + err = -EFAULT; + goto out; + } /* Now read the message size and data from user space. */ - get_user(hm->h.size, (u16 __user *)puhm); + if (get_user(hm->h.size, (u16 __user *)puhm)) { + err = -EFAULT; + goto out; + } if (hm->h.size > sizeof(*hm)) hm->h.size = sizeof(*hm); @@ -138,7 +144,10 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } - get_user(res_max_size, (u16 __user *)puhr); + if (get_user(res_max_size, (u16 __user *)puhr)) { + err = -EFAULT; + goto out; + } /* printk(KERN_INFO "user response size %d\n", res_max_size); */ if (res_max_size < sizeof(struct hpi_response_header)) { HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size); @@ -464,9 +473,7 @@ void __init asihpi_init(void) memset(adapters, 0, sizeof(adapters)); - printk(KERN_INFO "ASIHPI driver %d.%02d.%02d\n", - HPI_VER_MAJOR(HPI_VER), HPI_VER_MINOR(HPI_VER), - HPI_VER_RELEASE(HPI_VER)); + printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n"); hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_DRIVER_LOAD); diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 668a5ec04499..20763dd03fa0 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2250,6 +2250,8 @@ static int snd_echo_resume(struct pci_dev *pci) DE_INIT(("resume start\n")); pci_restore_state(pci); commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); + if (commpage_bak == NULL) + return -ENOMEM; commpage = chip->comm_page; memcpy(commpage_bak, commpage, sizeof(struct comm_page)); diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4203782d7cb7..aff8387c45cf 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -52,6 +52,7 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; static int enable_ir[SNDRV_CARDS]; static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ +static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); @@ -73,6 +74,8 @@ module_param_array(enable_ir, bool, NULL, 0444); MODULE_PARM_DESC(enable_ir, "Enable IR."); module_param_array(subsystem, uint, NULL, 0444); MODULE_PARM_DESC(subsystem, "Force card subsystem model."); +module_param_array(delay_pcm_irq, uint, NULL, 0444); +MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0)."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ @@ -127,6 +130,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, &emu)) < 0) goto error; card->private_data = emu; + emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) goto error; if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 55b83ef73c63..622bace148e3 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -332,7 +332,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, evoice->epcm->ccca_start_addr = start_addr + ccis; if (extra) { start_addr += ccis; - end_addr += ccis; + end_addr += ccis + emu->delay_pcm_irq; } if (stereo && !extra) { snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); @@ -360,7 +360,9 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); - snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); + snd_emu10k1_ptr_write(emu, PSST, voice, + (start_addr + (extra ? emu->delay_pcm_irq : 0)) | + (send_amount[2] << 24)); if (emu->card_capabilities->emu_model) pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ else @@ -732,6 +734,23 @@ static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_ snd_emu10k1_ptr_write(emu, IP, voice, 0); } +static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) +{ + unsigned int ptr, period_pos; + + /* try to sychronize the current position for the interrupt + source voice */ + period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt; + period_pos %= runtime->period_size; + ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number); + ptr &= ~0x00ffffff; + ptr |= epcm->ccca_start_addr + period_pos; + snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr); +} + static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -753,6 +772,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, /* follow thru */ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) + snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime); mix = &emu->pcm_mixer[substream->number]; snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); @@ -869,8 +890,9 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * #endif /* printk(KERN_DEBUG - "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", - ptr, runtime->buffer_size, runtime->period_size); + "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", + (long)ptr, (long)runtime->buffer_size, + (long)runtime->period_size); */ return ptr; } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index ffb1ddb8dc28..957a311514c8 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -310,8 +310,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!hdr)) return NULL; + idx = runtime->period_size >= runtime->buffer_size ? + (emu->delay_pcm_irq * 2) : 0; mutex_lock(&hdr->block_mutex); - blk = search_empty(emu, runtime->dma_bytes); + blk = search_empty(emu, runtime->dma_bytes + idx); if (blk == NULL) { mutex_unlock(&hdr->block_mutex); return NULL; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ba2098d20ccc..3827092cc1d2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -396,15 +396,18 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } for (n = prev_nid + 1; n <= val; n++) { if (conns >= max_conns) { - snd_printk(KERN_ERR - "Too many connections\n"); + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + conns, nid); return -EINVAL; } conn_list[conns++] = n; } } else { if (conns >= max_conns) { - snd_printk(KERN_ERR "Too many connections\n"); + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + conns, nid); return -EINVAL; } conn_list[conns++] = val; @@ -586,6 +589,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, bus->ops = temp->ops; mutex_init(&bus->cmd_mutex); + mutex_init(&bus->prepare_mutex); INIT_LIST_HEAD(&bus->codec_list); snprintf(bus->workq_name, sizeof(bus->workq_name), @@ -730,15 +734,17 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); for (i = 0; i < total_nodes; i++, nid++) { function_id = snd_hda_param_read(codec, nid, - AC_PAR_FUNCTION_TYPE) & 0xff; - switch (function_id) { + AC_PAR_FUNCTION_TYPE); + switch (function_id & 0xff) { case AC_GRP_AUDIO_FUNCTION: codec->afg = nid; - codec->function_id = function_id; + codec->afg_function_id = function_id & 0xff; + codec->afg_unsol = (function_id >> 8) & 1; break; case AC_GRP_MODEM_FUNCTION: codec->mfg = nid; - codec->function_id = function_id; + codec->mfg_function_id = function_id & 0xff; + codec->mfg_unsol = (function_id >> 8) & 1; break; default: break; @@ -966,6 +972,36 @@ static void restore_init_pincfgs(struct hda_codec *codec) } /* + * audio-converter setup caches + */ +struct hda_cvt_setup { + hda_nid_t nid; + u8 stream_tag; + u8 channel_id; + u16 format_id; + unsigned char active; /* cvt is currently used */ + unsigned char dirty; /* setups should be cleared */ +}; + +/* get or create a cache entry for the given audio converter NID */ +static struct hda_cvt_setup * +get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_cvt_setup *p; + int i; + + for (i = 0; i < codec->cvt_setups.used; i++) { + p = snd_array_elem(&codec->cvt_setups, i); + if (p->nid == nid) + return p; + } + p = snd_array_new(&codec->cvt_setups); + if (p) + p->nid = nid; + return p; +} + +/* * codec destructor */ static void snd_hda_codec_free(struct hda_codec *codec) @@ -1039,6 +1075,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); + snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { @@ -1176,37 +1213,126 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format) { + struct hda_codec *c; + struct hda_cvt_setup *p; + unsigned int oldval, newval; + int i; + if (!nid) return; snd_printdd("hda_codec_setup_stream: " "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", nid, stream_tag, channel_id, format); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, - (stream_tag << 4) | channel_id); - msleep(1); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); + p = get_hda_cvt_setup(codec, nid); + if (!p) + return; + /* update the stream-id if changed */ + if (p->stream_tag != stream_tag || p->channel_id != channel_id) { + oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + newval = (stream_tag << 4) | channel_id; + if (oldval != newval) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, + newval); + p->stream_tag = stream_tag; + p->channel_id = channel_id; + } + /* update the format-id if changed */ + if (p->format_id != format) { + oldval = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_STREAM_FORMAT, 0); + if (oldval != format) { + msleep(1); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_STREAM_FORMAT, + format); + } + p->format_id = format; + } + p->active = 1; + p->dirty = 0; + + /* make other inactive cvts with the same stream-tag dirty */ + list_for_each_entry(c, &codec->bus->codec_list, list) { + for (i = 0; i < c->cvt_setups.used; i++) { + p = snd_array_elem(&c->cvt_setups, i); + if (!p->active && p->stream_tag == stream_tag) + p->dirty = 1; + } + } } EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); +static void really_cleanup_stream(struct hda_codec *codec, + struct hda_cvt_setup *q); + /** - * snd_hda_codec_cleanup_stream - clean up the codec for closing + * __snd_hda_codec_cleanup_stream - clean up the codec for closing * @codec: the CODEC to clean up * @nid: the NID to clean up + * @do_now: really clean up the stream instead of clearing the active flag */ -void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) +void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, + int do_now) { + struct hda_cvt_setup *p; + if (!nid) return; snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); + p = get_hda_cvt_setup(codec, nid); + if (p) { + /* here we just clear the active flag when do_now isn't set; + * actual clean-ups will be done later in + * purify_inactive_streams() called from snd_hda_codec_prpapre() + */ + if (do_now) + really_cleanup_stream(codec, p); + else + p->active = 0; + } +} +EXPORT_SYMBOL_HDA(__snd_hda_codec_cleanup_stream); + +static void really_cleanup_stream(struct hda_codec *codec, + struct hda_cvt_setup *q) +{ + hda_nid_t nid = q->nid; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -#if 0 /* keep the format */ - msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); -#endif + memset(q, 0, sizeof(*q)); + q->nid = nid; +} + +/* clean up the all conflicting obsolete streams */ +static void purify_inactive_streams(struct hda_codec *codec) +{ + struct hda_codec *c; + int i; + + list_for_each_entry(c, &codec->bus->codec_list, list) { + for (i = 0; i < c->cvt_setups.used; i++) { + struct hda_cvt_setup *p; + p = snd_array_elem(&c->cvt_setups, i); + if (p->dirty) + really_cleanup_stream(c, p); + } + } +} + +/* clean up all streams; called from suspend */ +static void hda_cleanup_all_streams(struct hda_codec *codec) +{ + int i; + + for (i = 0; i < codec->cvt_setups.used; i++) { + struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i); + if (p->stream_tag) + really_cleanup_stream(codec, p); + } } -EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* * amp access functions @@ -1565,6 +1691,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ +static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, + unsigned int ofs) +{ + u32 caps = query_amp_caps(codec, nid, dir); + /* get num steps */ + caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; + if (ofs < caps) + caps -= ofs; + return caps; +} + /** * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer * @@ -1579,23 +1716,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, u8 chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); - u32 caps; - caps = query_amp_caps(codec, nid, dir); - /* num steps */ - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (!caps) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs); + if (!uinfo->value.integer.max) { printk(KERN_WARNING "hda_codec: " "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, kcontrol->id.name); return -EINVAL; } - if (ofs < caps) - caps -= ofs; - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = chs == 3 ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = caps; return 0; } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); @@ -1620,8 +1751,14 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, unsigned int ofs, unsigned int val) { + unsigned int maxval; + if (val > 0) val += ofs; + /* ofs = 0: raw max value */ + maxval = get_amp_max_value(codec, nid, dir, 0); + if (val > maxval) + val = maxval; return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val); } @@ -2912,6 +3049,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec) { if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec, PMSG_SUSPEND); + hda_cleanup_all_streams(codec); hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D3); @@ -2999,26 +3137,31 @@ struct hda_rate_tbl { unsigned int hda_fmt; }; +/* rate = base * mult / div */ +#define HDA_RATE(base, mult, div) \ + (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ + (((div) - 1) << AC_FMT_DIV_SHIFT)) + static struct hda_rate_tbl rate_bits[] = { /* rate in Hz, ALSA rate bitmask, HDA format value */ /* autodetected value used in snd_hda_query_supported_pcm */ - { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ - { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ - { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ - { 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */ - { 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */ - { 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */ - { 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */ - { 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */ - { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ - { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ - { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ + { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, + { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, + { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, + { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, + { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, + { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, + { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, + { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, + { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, + { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, + { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, #define AC_PAR_PCM_RATE_BITS 11 /* up to bits 10, 384kHZ isn't supported properly */ /* not autodetected value */ - { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */ + { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, { 0 } /* terminator */ }; @@ -3037,7 +3180,8 @@ static struct hda_rate_tbl rate_bits[] = { unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, unsigned int format, - unsigned int maxbps) + unsigned int maxbps, + unsigned short spdif_ctls) { int i; unsigned int val = 0; @@ -3060,20 +3204,20 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, switch (snd_pcm_format_width(format)) { case 8: - val |= 0x00; + val |= AC_FMT_BITS_8; break; case 16: - val |= 0x10; + val |= AC_FMT_BITS_16; break; case 20: case 24: case 32: if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) - val |= 0x40; + val |= AC_FMT_BITS_32; else if (maxbps >= 24) - val |= 0x30; + val |= AC_FMT_BITS_24; else - val |= 0x20; + val |= AC_FMT_BITS_20; break; default: snd_printdd("invalid format width %d\n", @@ -3081,6 +3225,9 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return 0; } + if (spdif_ctls & AC_DIG1_NONAUDIO) + val |= AC_FMT_TYPE_NON_PCM; + return val; } EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); @@ -3352,6 +3499,35 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } +/* + * codec prepare/cleanup entries + */ +int snd_hda_codec_prepare(struct hda_codec *codec, + struct hda_pcm_stream *hinfo, + unsigned int stream, + unsigned int format, + struct snd_pcm_substream *substream) +{ + int ret; + mutex_lock(&codec->bus->prepare_mutex); + ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); + if (ret >= 0) + purify_inactive_streams(codec); + mutex_unlock(&codec->bus->prepare_mutex); + return ret; +} +EXPORT_SYMBOL_HDA(snd_hda_codec_prepare); + +void snd_hda_codec_cleanup(struct hda_codec *codec, + struct hda_pcm_stream *hinfo, + struct snd_pcm_substream *substream) +{ + mutex_lock(&codec->bus->prepare_mutex); + hinfo->ops.cleanup(hinfo, codec, substream); + mutex_unlock(&codec->bus->prepare_mutex); +} +EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup); + /* global */ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5991d14e1ec0..62c702240108 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -224,6 +224,27 @@ enum { /* Input converter SDI select */ #define AC_SDI_SELECT (0xf<<0) +/* stream format id */ +#define AC_FMT_CHAN_SHIFT 0 +#define AC_FMT_CHAN_MASK (0x0f << 0) +#define AC_FMT_BITS_SHIFT 4 +#define AC_FMT_BITS_MASK (7 << 4) +#define AC_FMT_BITS_8 (0 << 4) +#define AC_FMT_BITS_16 (1 << 4) +#define AC_FMT_BITS_20 (2 << 4) +#define AC_FMT_BITS_24 (3 << 4) +#define AC_FMT_BITS_32 (4 << 4) +#define AC_FMT_DIV_SHIFT 8 +#define AC_FMT_DIV_MASK (7 << 8) +#define AC_FMT_MULT_SHIFT 11 +#define AC_FMT_MULT_MASK (7 << 11) +#define AC_FMT_BASE_SHIFT 14 +#define AC_FMT_BASE_48K (0 << 14) +#define AC_FMT_BASE_44K (1 << 14) +#define AC_FMT_TYPE_SHIFT 15 +#define AC_FMT_TYPE_PCM (0 << 15) +#define AC_FMT_TYPE_NON_PCM (1 << 15) + /* Unsolicited response control */ #define AC_UNSOL_TAG (0x3f<<0) #define AC_UNSOL_ENABLED (1<<7) @@ -364,6 +385,9 @@ enum { #define AC_DIG2_CC (0x7f<<0) /* Pin widget control - 8bit */ +#define AC_PINCTL_EPT (0x3<<0) +#define AC_PINCTL_EPT_NATIVE 0 +#define AC_PINCTL_EPT_HBR 3 #define AC_PINCTL_VREFEN (0x7<<0) #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ #define AC_PINCTL_VREF_50 1 /* 50% */ @@ -624,6 +648,7 @@ struct hda_bus { struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; struct mutex cmd_mutex; + struct mutex prepare_mutex; /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; @@ -760,7 +785,10 @@ struct hda_codec { hda_nid_t mfg; /* MFG node id */ /* ids */ - u32 function_id; + u8 afg_function_id; + u8 mfg_function_id; + u8 afg_unsol; + u8 mfg_unsol; u32 vendor_id; u32 subsystem_id; u32 revision_id; @@ -805,6 +833,7 @@ struct hda_codec { hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ struct snd_array driver_pins; /* pin configs set by codec parser */ + struct snd_array cvt_setups; /* audio convert setups */ #ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ @@ -921,14 +950,28 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); */ int snd_hda_build_pcms(struct hda_bus *bus); int snd_hda_codec_build_pcms(struct hda_codec *codec); + +int snd_hda_codec_prepare(struct hda_codec *codec, + struct hda_pcm_stream *hinfo, + unsigned int stream, + unsigned int format, + struct snd_pcm_substream *substream); +void snd_hda_codec_cleanup(struct hda_codec *codec, + struct hda_pcm_stream *hinfo, + struct snd_pcm_substream *substream); + void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format); -void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid); +void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, + int do_now); +#define snd_hda_codec_cleanup_stream(codec, nid) \ + __snd_hda_codec_cleanup_stream(codec, nid, 0) unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, unsigned int format, - unsigned int maxbps); + unsigned int maxbps, + unsigned short spdif_ctls); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index d8da18a9e98b..26c3ade73583 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -597,3 +597,52 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); #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) +{ + int i; + + pcm->rates = 0; + pcm->formats = 0; + pcm->maxbps = 0; + pcm->channels_min = -1; + pcm->channels_max = 0; + for (i = 0; i < eld->sad_count; i++) { + struct cea_sad *a = &eld->sad[i]; + pcm->rates |= a->rates; + if (a->channels < pcm->channels_min) + pcm->channels_min = a->channels; + if (a->channels > pcm->channels_max) + pcm->channels_max = a->channels; + if (a->format == AUDIO_CODING_TYPE_LPCM) { + if (a->sample_bits & AC_SUPPCM_BITS_16) { + pcm->formats |= SNDRV_PCM_FMTBIT_S16_LE; + if (pcm->maxbps < 16) + pcm->maxbps = 16; + } + if (a->sample_bits & AC_SUPPCM_BITS_20) { + pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; + if (pcm->maxbps < 20) + pcm->maxbps = 20; + } + if (a->sample_bits & AC_SUPPCM_BITS_24) { + pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; + if (pcm->maxbps < 24) + pcm->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_min = max(pcm->channels_min, codec_pars->channels_min); + pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); + pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); +} +EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index a1fc83753cc6..bf3ced51e0f8 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -649,7 +649,9 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus, *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) { + if (codec->vendor_id == vendorid && + codec->subsystem_id == subid && + codec->addr == caddr) { *codecp = codec; break; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1df25cf5ce38..1053fff4bd0a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1634,7 +1634,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) azx_dev->period_bytes = 0; azx_dev->format_val = 0; - hinfo->ops.cleanup(hinfo, apcm->codec, substream); + snd_hda_codec_cleanup(apcm->codec, hinfo, substream); return snd_pcm_lib_free_pages(substream); } @@ -1653,7 +1653,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) format_val = snd_hda_calc_stream_format(runtime->rate, runtime->channels, runtime->format, - hinfo->maxbps); + hinfo->maxbps, + apcm->codec->spdif_ctls); if (!format_val) { snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", @@ -1687,8 +1688,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) else azx_dev->fifo_size = 0; - return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, - azx_dev->format_val, substream); + return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag, + azx_dev->format_val, substream); } static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -1960,7 +1961,7 @@ static void azx_irq_pending_work(struct work_struct *work) spin_unlock_irq(&chip->reg_lock); if (!pending) return; - cond_resched(); + msleep(1); } } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7a97f126f6f7..28ab4aead48f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -604,6 +604,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); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index f97d35de66c4..f025200f2a62 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -557,7 +557,12 @@ static void print_codec_info(struct snd_info_entry *entry, else snd_iprintf(buffer, "Not Set\n"); snd_iprintf(buffer, "Address: %d\n", codec->addr); - snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); + if (codec->afg) + snd_iprintf(buffer, "AFG Function Id: 0x%x (unsol %u)\n", + codec->afg_function_id, codec->afg_unsol); + if (codec->mfg) + snd_iprintf(buffer, "MFG Function Id: 0x%x (unsol %u)\n", + codec->mfg_function_id, codec->mfg_unsol); snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id); snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index afbe314a5bf3..b697fd2a6f8b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3662,7 +3662,12 @@ static int patch_ad1984(struct hda_codec *codec) codec->patch_ops.build_pcms = ad1984_build_pcms; break; case AD1984_THINKPAD: - spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; + if (codec->subsystem_id == 0x17aa20fb) { + /* Thinpad X300 does not have the ability to do SPDIF, + or attach to docking station to use SPDIF */ + spec->multiout.dig_out_nid = 0; + } else + spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; spec->input_mux = &ad1984_thinkpad_capture_source; spec->mixers[0] = ad1984_thinkpad_mixers; spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 350ee8ac4153..4ef5efaaaef1 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -656,7 +656,7 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, return 0; if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { /* stream is running, let's swap the current ADC */ - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); spec->cur_adc = spec->adc_nid[idx]; snd_hda_codec_setup_stream(codec, spec->cur_adc, spec->cur_adc_stream_tag, 0, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 2bf2cb5da956..5cdb80edbd7f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -131,6 +131,8 @@ struct conexant_spec { unsigned int dc_enable; unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ + + unsigned int beep_amp; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -515,6 +517,15 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { {} }; +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/* additional beep mixers; the actual parameters are overwritten at build */ +static struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), + { } /* end */ +}; +#endif + static const char *slave_vols[] = { "Headphone Playback Volume", "Speaker Playback Volume", @@ -580,16 +591,52 @@ static int conexant_build_controls(struct hda_codec *codec) return err; } +#ifdef CONFIG_SND_HDA_INPUT_BEEP + /* create beep controls if needed */ + if (spec->beep_amp) { + struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } +#endif + + return 0; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int conexant_suspend(struct hda_codec *codec, pm_message_t state) +{ + snd_hda_shutup_pins(codec); return 0; } +#endif static struct hda_codec_ops conexant_patch_ops = { .build_controls = conexant_build_controls, .build_pcms = conexant_build_pcms, .init = conexant_init, .free = conexant_free, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .suspend = conexant_suspend, +#endif + .reboot_notify = snd_hda_shutup_pins, }; +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define set_beep_amp(spec, nid, idx, dir) \ + ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#endif + /* * EAPD control * the private value = nid | (invert << 8) @@ -1130,9 +1177,10 @@ static int patch_cxt5045(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5045_init_verbs; spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), - spec->channel_mode = cxt5045_modes, + spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); + spec->channel_mode = cxt5045_modes; + set_beep_amp(spec, 0x16, 0, 1); codec->patch_ops = conexant_patch_ops; @@ -1211,6 +1259,9 @@ static int patch_cxt5045(struct hda_codec *codec) break; } + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; } @@ -1632,6 +1683,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec) pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + /* on ideapad there is an aditional speaker (subwoofer) to mute */ + if (spec->ideapad) + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); } /* turn on/off EAPD (+ mute HP) as a master switch */ @@ -1677,7 +1733,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) new_adc = spec->adc_nids[spec->cur_adc_idx]; if (spec->cur_adc && spec->cur_adc != new_adc) { /* stream is running, let's swap the current ADC */ - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); spec->cur_adc = new_adc; snd_hda_codec_setup_stream(codec, new_adc, spec->cur_adc_stream_tag, 0, @@ -1888,6 +1944,13 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, #endif } +static struct hda_verb cxt5051_ideapad_init_verbs[] = { + /* Subwoofer */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; + /* initialize jack-sensing, too */ static int cxt5051_init(struct hda_codec *codec) { @@ -1917,6 +1980,7 @@ enum { CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ + CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ CXT5051_MODELS }; @@ -1927,6 +1991,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { [CXT5051_LENOVO_X200] = "lenovo-x200", [CXT5051_F700] = "hp-700", [CXT5051_TOSHIBA] = "toshiba", + [CXT5051_IDEAPAD] = "ideapad", }; static struct snd_pci_quirk cxt5051_cfg_tbl[] = { @@ -1938,6 +2003,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { CXT5051_LAPTOP), SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), {} }; @@ -1972,6 +2038,8 @@ static int patch_cxt5051(struct hda_codec *codec) spec->cur_adc = 0; spec->cur_adc_idx = 0; + set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); + codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, @@ -1989,6 +2057,10 @@ static int patch_cxt5051(struct hda_codec *codec) break; case CXT5051_LENOVO_X200: spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; + /* Thinkpad X301 does not have S/PDIF wired and no ability + to use a docking station. */ + if (codec->subsystem_id == 0x17aa211f) + spec->multiout.dig_out_nid = 0; break; case CXT5051_F700: spec->init_verbs[0] = cxt5051_f700_init_verbs; @@ -1999,8 +2071,16 @@ static int patch_cxt5051(struct hda_codec *codec) spec->mixers[0] = cxt5051_toshiba_mixers; spec->auto_mic = AUTO_MIC_PORTB; break; + case CXT5051_IDEAPAD: + spec->init_verbs[spec->num_init_verbs++] = + cxt5051_ideapad_init_verbs; + spec->ideapad = 1; + break; } + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; } @@ -2616,7 +2696,6 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { .put = cxt5066_mic_boost_mux_enum_put, .private_value = 0x23 | 0x100, }, - HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), {} }; @@ -2970,6 +3049,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), @@ -2977,8 +3057,11 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), {} }; @@ -3014,6 +3097,8 @@ static int patch_cxt5066(struct hda_codec *codec) spec->cur_adc = 0; spec->cur_adc_idx = 0; + set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); + board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, cxt5066_models, cxt5066_cfg_tbl); switch (board_config) { @@ -3062,7 +3147,6 @@ static int patch_cxt5066(struct hda_codec *codec) spec->port_d_mode = 0; spec->dell_vostro = 1; spec->mic_boost = 3; /* default 30dB gain */ - snd_hda_attach_beep_device(codec, 0x13); /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; @@ -3104,6 +3188,9 @@ static int patch_cxt5066(struct hda_codec *codec) break; } + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; } @@ -3121,6 +3208,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5066 }, { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", .patch = patch_cxt5066 }, + { .id = 0x14f15068, .name = "CX20584", + .patch = patch_cxt5066 }, { .id = 0x14f15069, .name = "CX20585", .patch = patch_cxt5066 }, {} /* terminator */ @@ -3131,6 +3220,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047"); MODULE_ALIAS("snd-hda-codec-id:14f15051"); MODULE_ALIAS("snd-hda-codec-id:14f15066"); MODULE_ALIAS("snd-hda-codec-id:14f15067"); +MODULE_ALIAS("snd-hda-codec-id:14f15068"); MODULE_ALIAS("snd-hda-codec-id:14f15069"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2fc53961054e..afd6022a96a7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -46,6 +46,7 @@ struct hdmi_spec { * export one pcm per pipe */ struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; + struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS]; /* * nvhdmi specific @@ -698,30 +699,93 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) * Callbacks */ -static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, +/* HBR should be Non-PCM, 8 channels */ +#define is_hbr_format(format) \ + ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) + +static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int format) { - int tag; - int fmt; + struct hdmi_spec *spec = codec->spec; + int pinctl; + int new_pinctl = 0; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR)) + continue; - tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; - fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); + pinctl = snd_hda_codec_read(codec, spec->pin[i], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + + new_pinctl = pinctl & ~AC_PINCTL_EPT; + if (is_hbr_format(format)) + new_pinctl |= AC_PINCTL_EPT_HBR; + else + new_pinctl |= AC_PINCTL_EPT_NATIVE; + + snd_printdd("hdmi_setup_stream: " + "NID=0x%x, %spinctl=0x%x\n", + spec->pin[i], + pinctl == new_pinctl ? "" : "new-", + new_pinctl); + + if (pinctl != new_pinctl) + snd_hda_codec_write(codec, spec->pin[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_pinctl); + } - snd_printdd("hdmi_setup_stream: " - "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", - nid, - tag == stream_tag ? "" : "new-", - stream_tag, - fmt == format ? "" : "new-", - format); + if (is_hbr_format(format) && !new_pinctl) { + snd_printdd("hdmi_setup_stream: HBR is not supported\n"); + return -EINVAL; + } - if (tag != stream_tag) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - stream_tag << 4); - if (fmt != format) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); + return 0; +} + +/* + * HDA PCM callbacks + */ +static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld; + struct hda_pcm_stream *codec_pars; + unsigned int idx; + + for (idx = 0; idx < spec->num_cvts; idx++) + if (hinfo->nid == spec->cvt[idx]) + break; + if (snd_BUG_ON(idx >= spec->num_cvts) || + snd_BUG_ON(idx >= spec->num_pins)) + return -EINVAL; + + /* save the PCM info the codec provides */ + codec_pars = &spec->codec_pcm_pars[idx]; + if (!codec_pars->rates) + *codec_pars = *hinfo; + + eld = &spec->sink_eld[idx]; + if (eld->sad_count > 0) { + hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); + if (hinfo->channels_min > hinfo->channels_max || + !hinfo->rates || !hinfo->formats) + return -ENODEV; + } else { + /* fallback to the codec default */ + hinfo->channels_min = codec_pars->channels_min; + hinfo->channels_max = codec_pars->channels_max; + hinfo->rates = codec_pars->rates; + hinfo->formats = codec_pars->formats; + hinfo->maxbps = codec_pars->maxbps; + } + return 0; } /* diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index b81d23e42ace..36a9b83a6174 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -66,23 +66,15 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); - return 0; -} - -static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; + return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } static struct hda_pcm_stream intel_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .ops = { + .open = hdmi_pcm_open, .prepare = intel_hdmi_playback_pcm_prepare, - .cleanup = intel_hdmi_playback_pcm_cleanup, }, }; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index b0652acee9b2..69b950d527c3 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -202,8 +202,7 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); - return 0; + return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, @@ -327,13 +326,6 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, return 0; } -static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -348,12 +340,9 @@ static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { .substreams = 1, .channels_min = 2, - .rates = SUPPORTED_RATES, - .maxbps = SUPPORTED_MAXBPS, - .formats = SUPPORTED_FORMATS, .ops = { + .open = hdmi_pcm_open, .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, - .cleanup = nvhdmi_playback_pcm_cleanup, }, }; @@ -541,26 +530,32 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "MCP77/78 HDMI", - .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0003, .name = "MCP77/78 HDMI", - .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0005, .name = "MCP77/78 HDMI", - .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0006, .name = "MCP77/78 HDMI", - .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0007, .name = "MCP79/7A HDMI", - .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de000a, .name = "GT220 HDMI", - .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000b, .name = "GT21x HDMI", - .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000c, .name = "MCP89 HDMI", - .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000d, .name = "GT240 HDMI", - .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, - { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, + { .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, {} /* terminator */ }; @@ -573,6 +568,21 @@ MODULE_ALIAS("snd-hda-codec-id:10de000a"); MODULE_ALIAS("snd-hda-codec-id:10de000b"); MODULE_ALIAS("snd-hda-codec-id:10de000c"); MODULE_ALIAS("snd-hda-codec-id:10de000d"); +MODULE_ALIAS("snd-hda-codec-id:10de0010"); +MODULE_ALIAS("snd-hda-codec-id:10de0011"); +MODULE_ALIAS("snd-hda-codec-id:10de0012"); +MODULE_ALIAS("snd-hda-codec-id:10de0013"); +MODULE_ALIAS("snd-hda-codec-id:10de0014"); +MODULE_ALIAS("snd-hda-codec-id:10de0018"); +MODULE_ALIAS("snd-hda-codec-id:10de0019"); +MODULE_ALIAS("snd-hda-codec-id:10de001a"); +MODULE_ALIAS("snd-hda-codec-id:10de001b"); +MODULE_ALIAS("snd-hda-codec-id:10de001c"); +MODULE_ALIAS("snd-hda-codec-id:10de0040"); +MODULE_ALIAS("snd-hda-codec-id:10de0041"); +MODULE_ALIAS("snd-hda-codec-id:10de0042"); +MODULE_ALIAS("snd-hda-codec-id:10de0043"); +MODULE_ALIAS("snd-hda-codec-id:10de0044"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_ALIAS("snd-hda-codec-id:10de8001"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 596ea2f12cf6..627bf9963368 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -137,6 +137,7 @@ enum { ALC269VB_DMIC, ALC269_FUJITSU, ALC269_LIFEBOOK, + ALC271_ACER, ALC269_AUTO, ALC269_MODEL_LAST /* last tag */ }; @@ -256,6 +257,13 @@ enum { ALC882_MODEL_LAST, }; +/* ALC680 models */ +enum { + ALC680_BASE, + ALC680_AUTO, + ALC680_MODEL_LAST, +}; + /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -326,6 +334,12 @@ struct alc_spec { hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ + /* capture setup for dynamic dual-adc switch */ + unsigned int cur_adc_idx; + hda_nid_t cur_adc; + unsigned int cur_adc_stream_tag; + unsigned int cur_adc_format; + /* capture source */ unsigned int num_mux_defs; const struct hda_input_mux *input_mux; @@ -367,6 +381,7 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ + unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ int init_amp; /* for virtual master */ @@ -833,9 +848,13 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, if (auto_pin_type <= AUTO_PIN_FRONT_MIC) { unsigned int pincap; + unsigned int oldval; + oldval = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); pincap = snd_hda_query_pin_caps(codec, nid); pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; - if (pincap & AC_PINCAP_VREF_80) + /* if the default pin setup is vref50, we give it priority */ + if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50) val = PIN_VREF80; else if (pincap & AC_PINCAP_VREF_50) val = PIN_VREF50; @@ -1003,6 +1022,29 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, return -1; } +/* switch the current ADC according to the jack state */ +static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int present; + hda_nid_t new_adc; + + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); + if (present) + spec->cur_adc_idx = 1; + else + spec->cur_adc_idx = 0; + new_adc = spec->adc_nids[spec->cur_adc_idx]; + if (spec->cur_adc && spec->cur_adc != new_adc) { + /* stream is running, let's swap the current ADC */ + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = new_adc; + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } +} + static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1017,6 +1059,11 @@ static void alc_mic_automute(struct hda_codec *codec) if (snd_BUG_ON(!spec->adc_nids)) return; + if (spec->dual_adc_switch) { + alc_dual_mic_adc_auto_switch(codec); + return; + } + cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; present = snd_hda_jack_detect(codec, spec->ext_mic.pin); @@ -1499,6 +1546,63 @@ static int alc_read_coef_idx(struct hda_codec *codec, return val; } +/* set right pin controls for digital I/O */ +static void alc_auto_init_digital(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + hda_nid_t pin; + + for (i = 0; i < spec->autocfg.dig_outs; i++) { + pin = spec->autocfg.dig_out_pins[i]; + if (pin) { + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + } + } + pin = spec->autocfg.dig_in_pin; + if (pin) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_IN); +} + +/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */ +static void alc_auto_parse_digital(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i, err; + hda_nid_t dig_nid; + + /* support multiple SPDIFs; the secondary is set up as a slave */ + for (i = 0; i < spec->autocfg.dig_outs; i++) { + err = snd_hda_get_connections(codec, + spec->autocfg.dig_out_pins[i], + &dig_nid, 1); + if (err < 0) + continue; + if (!i) { + spec->multiout.dig_out_nid = dig_nid; + spec->dig_out_type = spec->autocfg.dig_out_type[0]; + } else { + spec->multiout.slave_dig_outs = spec->slave_dig_outs; + if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + break; + spec->slave_dig_outs[i - 1] = dig_nid; + } + } + + if (spec->autocfg.dig_in_pin) { + hda_nid_t dig_nid; + err = snd_hda_get_connections(codec, + spec->autocfg.dig_in_pin, + &dig_nid, 1); + if (err > 0) + spec->dig_in_nid = dig_nid; + } +} + /* * ALC888 */ @@ -3607,6 +3711,41 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } +/* analog capture with dynamic dual-adc changes */ +static int dualmic_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; + spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); + return 0; +} + +static int dualmic_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 struct hda_pcm_stream dualmic_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = dualmic_capture_pcm_prepare, + .cleanup = dualmic_capture_pcm_cleanup + }, +}; /* */ @@ -4936,7 +5075,7 @@ static void alc880_auto_init_input_src(struct hda_codec *codec) static int alc880_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int i, err; + int err; static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -4967,25 +5106,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - /* check multiple SPDIF-out (for recent codecs) */ - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t dig_nid; - err = snd_hda_get_connections(codec, - spec->autocfg.dig_out_pins[i], - &dig_nid, 1); - if (err < 0) - continue; - if (!i) - spec->multiout.dig_out_nid = dig_nid; - else { - spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) - break; - spec->slave_dig_outs[i - 1] = dig_nid; - } - } - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = ALC880_DIGIN_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -5008,6 +5129,7 @@ static void alc880_auto_init(struct hda_codec *codec) alc880_auto_init_extra_out(codec); alc880_auto_init_analog_input(codec); alc880_auto_init_input_src(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -5045,6 +5167,39 @@ static void fixup_automic_adc(struct hda_codec *codec) spec->auto_mic = 0; /* disable auto-mic to be sure */ } +/* select or unmute the given capsrc route */ +static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, + int idx) +{ + if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { + snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, + HDA_AMP_MUTE, 0); + } else { + snd_hda_codec_write_cache(codec, cap, 0, + AC_VERB_SET_CONNECT_SEL, idx); + } +} + +/* set the default connection to that pin */ +static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t cap = spec->capsrc_nids ? + spec->capsrc_nids[i] : spec->adc_nids[i]; + int idx; + + idx = get_connection_index(codec, cap, pin); + if (idx < 0) + continue; + select_or_unmute_capsrc(codec, cap, idx); + return i; /* return the found index */ + } + return -1; /* not found */ +} + /* choose the ADC/MUX containing the input pin and initialize the setup */ static void fixup_single_adc(struct hda_codec *codec) { @@ -5061,33 +5216,24 @@ static void fixup_single_adc(struct hda_codec *codec) } if (!pin) return; - - /* set the default connection to that pin */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t cap = spec->capsrc_nids ? - spec->capsrc_nids[i] : spec->adc_nids[i]; - int idx; - - idx = get_connection_index(codec, cap, pin); - if (idx < 0) - continue; + i = init_capsrc_for_pin(codec, pin); + if (i >= 0) { /* use only this ADC */ if (spec->capsrc_nids) spec->capsrc_nids += i; spec->adc_nids += i; spec->num_adc_nids = 1; - /* select or unmute this route */ - if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { - snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, - HDA_AMP_MUTE, 0); - } else { - snd_hda_codec_write_cache(codec, cap, 0, - AC_VERB_SET_CONNECT_SEL, idx); - } - return; } } +/* initialize dual adcs */ +static void fixup_dual_adc_switch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + init_capsrc_for_pin(codec, spec->ext_mic.pin); + init_capsrc_for_pin(codec, spec->int_mic.pin); +} + static void set_capture_mixer(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -5101,7 +5247,10 @@ static void set_capture_mixer(struct hda_codec *codec) }; if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { int mux = 0; - if (spec->auto_mic) + int num_adcs = spec->num_adc_nids; + if (spec->dual_adc_switch) + fixup_dual_adc_switch(codec); + else if (spec->auto_mic) fixup_automic_adc(codec); else if (spec->input_mux) { if (spec->input_mux->num_items > 1) @@ -5109,7 +5258,9 @@ static void set_capture_mixer(struct hda_codec *codec) else if (spec->input_mux->num_items == 1) fixup_single_adc(codec); } - spec->cap_mixer = caps[mux][spec->num_adc_nids - 1]; + if (spec->dual_adc_switch) + num_adcs = 1; + spec->cap_mixer = caps[mux][num_adcs - 1]; } } @@ -5183,6 +5334,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, static struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; @@ -6624,6 +6776,7 @@ static void alc260_auto_init(struct hda_codec *codec) alc260_auto_init_multi_out(codec); alc260_auto_init_analog_input(codec); alc260_auto_init_input_src(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -6640,6 +6793,29 @@ static struct hda_amp_list alc260_loopbacks[] = { #endif /* + * Pin config fixes + */ +enum { + PINFIX_HP_DC5750, +}; + +static struct alc_pincfg alc260_hp_dc5750_pinfix[] = { + { 0x11, 0x90130110 }, /* speaker */ + { } +}; + +static const struct alc_fixup alc260_fixups[] = { + [PINFIX_HP_DC5750] = { + .pins = alc260_hp_dc5750_pinfix + }, +}; + +static struct snd_pci_quirk alc260_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), + {} +}; + +/* * ALC260 configurations */ static const char *alc260_models[ALC260_MODEL_LAST] = { @@ -6838,6 +7014,9 @@ static int patch_alc260(struct hda_codec *codec) board_config = ALC260_AUTO; } + if (board_config == ALC260_AUTO) + alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1); + if (board_config == ALC260_AUTO) { /* automatic parse from the BIOS config */ err = alc260_parse_auto_config(codec); @@ -6863,6 +7042,7 @@ static int patch_alc260(struct hda_codec *codec) spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc260_pcm_analog_capture; spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; @@ -6883,6 +7063,9 @@ static int patch_alc260(struct hda_codec *codec) set_capture_mixer(codec); set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); + if (board_config == ALC260_AUTO) + alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0); + spec->vmaster_nid = 0x08; codec->patch_ops = alc_patch_ops; @@ -7003,7 +7186,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, - { "iMic", 0x1 }, + { "Int Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, }, @@ -8573,8 +8756,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -10265,7 +10448,8 @@ static struct alc_config_preset alc882_presets[] = { * Pin config fixes */ enum { - PINFIX_ABIT_AW9D_MAX + PINFIX_ABIT_AW9D_MAX, + PINFIX_PB_M5210, }; static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { @@ -10275,13 +10459,22 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { { } }; +static const struct hda_verb pb_m5210_verbs[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + {} +}; + static const struct alc_fixup alc882_fixups[] = { [PINFIX_ABIT_AW9D_MAX] = { .pins = alc882_abit_aw9d_pinfix }, + [PINFIX_PB_M5210] = { + .verbs = pb_m5210_verbs + }, }; static struct snd_pci_quirk alc882_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), {} }; @@ -10446,7 +10639,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; static hda_nid_t alc882_ignore[] = { 0x1d, 0 }; - int i, err; + int err; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc882_ignore); @@ -10476,25 +10669,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - /* check multiple SPDIF-out (for recent codecs) */ - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t dig_nid; - err = snd_hda_get_connections(codec, - spec->autocfg.dig_out_pins[i], - &dig_nid, 1); - if (err < 0) - continue; - if (!i) - spec->multiout.dig_out_nid = dig_nid; - else { - spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) - break; - spec->slave_dig_outs[i - 1] = dig_nid; - } - } - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = ALC880_DIGIN_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -10524,6 +10699,7 @@ static void alc882_auto_init(struct hda_codec *codec) alc882_auto_init_hp_out(codec); alc882_auto_init_analog_input(codec); alc882_auto_init_input_src(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -12054,12 +12230,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; dig_only: - if (spec->autocfg.dig_outs) { - spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; - spec->dig_out_type = spec->autocfg.dig_out_type[0]; - } - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = ALC262_DIGIN_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -12091,6 +12262,7 @@ static void alc262_auto_init(struct hda_codec *codec) alc262_auto_init_hp_out(codec); alc262_auto_init_analog_input(codec); alc262_auto_init_input_src(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -13024,10 +13196,14 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, dac = 0x02; break; case 0x15: + case 0x1a: /* ALC259/269 only */ + case 0x1b: /* ALC259/269 only */ case 0x21: /* ALC269vb has this pin, too */ dac = 0x03; break; default: + snd_printd(KERN_WARNING "hda_codec: " + "ignoring pin 0x%x as unknown\n", nid); return 0; } if (spec->multiout.dac_nids[0] != dac && @@ -13078,7 +13254,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) return err; - } else { + } else if (nid) { err = alc268_new_analog_output(spec, nid, "Speaker", 0); if (err < 0) return err; @@ -13227,10 +13403,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) dig_only: /* digital only support output */ - if (spec->autocfg.dig_outs) { - spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; - spec->dig_out_type = spec->autocfg.dig_out_type[0]; - } + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -13260,6 +13433,7 @@ static void alc268_auto_init(struct hda_codec *codec) alc268_auto_init_hp_out(codec); alc268_auto_init_mono_speaker_out(codec); alc268_auto_init_analog_input(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -13303,7 +13477,6 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), - SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL), {} }; @@ -13694,6 +13867,12 @@ static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { { } /* end */ }; +static 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 struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -13914,6 +14093,20 @@ static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { {} }; +static 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 | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x22, AC_VERB_SET_CONNECT_SEL, 6}, + { } +}; + /* toggle speaker-output according to the hp-jack state */ static void alc269_speaker_automute(struct hda_codec *codec) { @@ -14152,6 +14345,36 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) } #endif /* CONFIG_SND_HDA_POWER_SAVE */ +static int alc275_setup_dual_adc(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic) + return 0; + if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) || + (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) { + if (spec->ext_mic.pin <= 0x12) { + spec->private_adc_nids[0] = 0x08; + spec->private_adc_nids[1] = 0x11; + spec->private_capsrc_nids[0] = 0x23; + spec->private_capsrc_nids[1] = 0x22; + } else { + spec->private_adc_nids[0] = 0x11; + spec->private_adc_nids[1] = 0x08; + spec->private_capsrc_nids[0] = 0x22; + spec->private_capsrc_nids[1] = 0x23; + } + spec->adc_nids = spec->private_adc_nids; + spec->capsrc_nids = spec->private_capsrc_nids; + spec->num_adc_nids = 2; + spec->dual_adc_switch = 1; + snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n", + spec->adc_nids[0], spec->adc_nids[1]); + return 1; + } + return 0; +} + /* * BIOS auto configuration */ @@ -14175,8 +14398,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -14191,13 +14413,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - fillup_priv_adc_nids(codec, alc269_adc_candidates, - sizeof(alc269_adc_candidates)); + + if (!alc275_setup_dual_adc(codec)) + fillup_priv_adc_nids(codec, alc269_adc_candidates, + sizeof(alc269_adc_candidates)); /* set default input source */ - snd_hda_codec_write_cache(codec, spec->capsrc_nids[0], - 0, AC_VERB_SET_CONNECT_SEL, - spec->input_mux->items[0].index); + if (!spec->dual_adc_switch) + select_or_unmute_capsrc(codec, spec->capsrc_nids[0], + spec->input_mux->items[0].index); err = alc_auto_add_mic_boost(codec); if (err < 0) @@ -14221,6 +14445,7 @@ static void alc269_auto_init(struct hda_codec *codec) alc269_auto_init_multi_out(codec); alc269_auto_init_hp_out(codec); alc269_auto_init_analog_input(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -14242,6 +14467,7 @@ static const struct alc_fixup alc269_fixups[] = { static struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), {} }; @@ -14261,6 +14487,7 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { static 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), @@ -14422,6 +14649,23 @@ static struct alc_config_preset alc269_presets[] = { .unsol_event = alc269_lifebook_unsol_event, .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, + }, }; static int patch_alc269(struct hda_codec *codec) @@ -14493,6 +14737,10 @@ static int patch_alc269(struct hda_codec *codec) */ spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; + } else if (spec->dual_adc_switch) { + spec->stream_analog_playback = &alc269_pcm_analog_playback; + /* switch ADC dynamically */ + spec->stream_analog_capture = &dualmic_pcm_analog_capture; } else { spec->stream_analog_playback = &alc269_pcm_analog_playback; spec->stream_analog_capture = &alc269_pcm_analog_capture; @@ -15378,8 +15626,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -15405,6 +15652,7 @@ static void alc861_auto_init(struct hda_codec *codec) alc861_auto_init_multi_out(codec); alc861_auto_init_hp_out(codec); alc861_auto_init_analog_input(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -16509,8 +16757,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -16537,6 +16784,7 @@ static void alc861vd_auto_init(struct hda_codec *codec) alc861vd_auto_init_hp_out(codec); alc861vd_auto_init_analog_input(codec); alc861vd_auto_init_input_src(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -18520,7 +18768,7 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t dac) { int i, num; - hda_nid_t srcs[4]; + hda_nid_t srcs[HDA_MAX_CONNECTIONS]; alc_set_pin_output(codec, nid, pin_type); /* need the manual connection? */ @@ -18624,8 +18872,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; + alc_auto_parse_digital(codec); if (spec->kctls.list) add_mixer(spec, spec->kctls.list); @@ -18635,7 +18882,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec) add_verb(spec, alc662_init_verbs); if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || - codec->vendor_id == 0x10ec0665) + codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) add_verb(spec, alc663_init_verbs); if (codec->vendor_id == 0x10ec0272) @@ -18662,6 +18909,7 @@ static void alc662_auto_init(struct hda_codec *codec) alc662_auto_init_hp_out(codec); alc662_auto_init_analog_input(codec); alc662_auto_init_input_src(codec); + alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -18781,6 +19029,445 @@ static int patch_alc888(struct hda_codec *codec) } /* + * ALC680 support + */ +#define ALC680_DIGIN_NID ALC880_DIGIN_NID +#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID +#define alc680_modes alc260_modes + +static hda_nid_t alc680_dac_nids[3] = { + /* Lout1, Lout2, hp */ + 0x02, 0x03, 0x04 +}; + +static hda_nid_t alc680_adc_nids[3] = { + /* ADC0-2 */ + /* DMIC, MIC, Line-in*/ + 0x07, 0x08, 0x09 +}; + +/* + * Analog capture ADC cgange + */ +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; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int pre_mic, pre_line; + + pre_mic = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); + pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]); + + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + + if (pre_mic || pre_line) { + if (pre_mic) + snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0, + format); + else + snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0, + format); + } else + snd_hda_codec_setup_stream(codec, 0x07, 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) +{ + snd_hda_codec_cleanup_stream(codec, 0x07); + snd_hda_codec_cleanup_stream(codec, 0x08); + snd_hda_codec_cleanup_stream(codec, 0x09); + return 0; +} + +static 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 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("Int Mic Boost", 0x12, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT), + { } +}; + +static 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 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 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 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, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_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.input_pins[AUTO_PIN_MIC] = 0x18; + spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19; +} + +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int present; + hda_nid_t new_adc; + + present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); + + new_adc = present ? 0x8 : 0x7; + __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1); + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + +} + +static void alc680_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc_automute_amp(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc680_rec_autoswitch(codec); +} + +static void alc680_inithook(struct hda_codec *codec) +{ + alc_automute_amp(codec); + alc680_rec_autoswitch(codec); +} + +/* create input playback/capture controls for the given pin */ +static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, + const char *ctlname, int idx) +{ + hda_nid_t dac; + int err; + + switch (nid) { + case 0x14: + dac = 0x02; + break; + case 0x15: + dac = 0x03; + break; + case 0x16: + dac = 0x04; + break; + default: + return 0; + } + if (spec->multiout.dac_nids[0] != dac && + spec->multiout.dac_nids[1] != dac) { + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, + HDA_COMPOSE_AMP_VAL(dac, 3, idx, + HDA_OUTPUT)); + if (err < 0) + return err; + + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); + + if (err < 0) + return err; + spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int err; + + spec->multiout.dac_nids = spec->private_dac_nids; + + nid = cfg->line_out_pins[0]; + if (nid) { + const char *name; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + name = "Speaker"; + else + name = "Front"; + err = alc680_new_analog_output(spec, nid, name, 0); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid) { + err = alc680_new_analog_output(spec, nid, "Speaker", 0); + if (err < 0) + return err; + } + nid = cfg->hp_pins[0]; + if (nid) { + err = alc680_new_analog_output(spec, nid, "Headphone", 0); + if (err < 0) + return err; + } + + return 0; +} + +static void alc680_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type) +{ + alc_set_pin_output(codec, nid, pin_type); +} + +static void alc680_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->autocfg.line_out_pins[0]; + if (nid) { + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc680_auto_set_output_and_unmute(codec, nid, pin_type); + } +} + +static void alc680_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pins[0]; + if (pin) + alc680_auto_set_output_and_unmute(codec, pin, PIN_HP); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT); +} + +/* pcm configuration: identical with ALC880 */ +#define alc680_pcm_analog_playback alc880_pcm_analog_playback +#define alc680_pcm_analog_capture alc880_pcm_analog_capture +#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture +#define alc680_pcm_digital_playback alc880_pcm_digital_playback +#define alc680_pcm_digital_capture alc880_pcm_digital_capture + +/* + * BIOS auto configuration + */ +static int alc680_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static hda_nid_t alc680_ignore[] = { 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc680_ignore); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs) { + if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = 2; + + dig_only: + /* digital only support output */ + alc_auto_parse_digital(codec); + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc680_init_verbs); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + return 1; +} + +#define alc680_auto_init_analog_input alc882_auto_init_analog_input + +/* init callback for auto-configuration model -- overriding the default init */ +static void alc680_auto_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + alc680_auto_init_multi_out(codec); + alc680_auto_init_hp_out(codec); + alc680_auto_init_analog_input(codec); + alc_auto_init_digital(codec); + if (spec->unsol_event) + alc_inithook(codec); +} + +/* + * configuration and preset + */ +static const char *alc680_models[ALC680_MODEL_LAST] = { + [ALC680_BASE] = "base", + [ALC680_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc680_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), + {} +}; + +static 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, + + }, +}; + +static int patch_alc680(struct hda_codec *codec) +{ + struct alc_spec *spec; + int board_config; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST, + alc680_models, + alc680_cfg_tbl); + + if (board_config < 0 || board_config >= ALC680_MODEL_LAST) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC680_AUTO; + } + + if (board_config == ALC680_AUTO) { + /* automatic parse from the BIOS config */ + err = alc680_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC680_BASE; + } + } + + if (board_config != ALC680_AUTO) + setup_preset(codec, &alc680_presets[board_config]); + + spec->stream_analog_playback = &alc680_pcm_analog_playback; + spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; + spec->stream_digital_playback = &alc680_pcm_digital_playback; + spec->stream_digital_capture = &alc680_pcm_digital_capture; + + if (!spec->adc_nids) { + spec->adc_nids = alc680_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids); + } + + if (!spec->cap_mixer) + set_capture_mixer(codec); + + spec->vmaster_nid = 0x02; + + codec->patch_ops = alc_patch_ops; + if (board_config == ALC680_AUTO) + spec->init_hook = alc680_auto_init; + + return 0; +} + +/* * patch entries */ static struct hda_codec_preset snd_hda_preset_realtek[] = { @@ -18804,6 +19491,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, + { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f1e7babd6920..95148e58026c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -94,6 +94,7 @@ enum { STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, STAC_92HD83XXX_HP, + STAC_HP_DV7_4000, STAC_92HD83XXX_MODELS }; @@ -202,6 +203,7 @@ struct sigmatel_spec { unsigned int spdif_mute: 1; unsigned int check_volume_offset:1; unsigned int auto_mic:1; + unsigned int linear_tone_beep:1; /* gpio lines */ unsigned int eapd_mask; @@ -1631,10 +1633,17 @@ static unsigned int dell_s14_pin_configs[10] = { 0x40f000f0, 0x40f000f0, }; +static unsigned int hp_dv7_4000_pin_configs[10] = { + 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, + 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, + 0x40f000f0, 0x40f000f0, +}; + static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, [STAC_DELL_S14] = dell_s14_pin_configs, + [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, }; static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { @@ -1643,6 +1652,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_PWR_REF] = "mic-ref", [STAC_DELL_S14] = "dell-s14", [STAC_92HD83XXX_HP] = "hp", + [STAC_HP_DV7_4000] = "hp-dv7-4000", }; static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -3802,7 +3812,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out return err; if (codec->beep) { /* IDT/STAC codecs have linear beep tone parameter */ - codec->beep->linear_tone = 1; + codec->beep->linear_tone = spec->linear_tone_beep; /* if no beep switch is available, make its own one */ caps = query_amp_caps(codec, nid, HDA_OUTPUT); if (!(caps & AC_AMPCAP_MUTE)) { @@ -5005,6 +5015,7 @@ static int patch_stac9200(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); spec->pin_nids = stac9200_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, @@ -5068,6 +5079,7 @@ static int patch_stac925x(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); spec->pin_nids = stac925x_pin_nids; @@ -5153,6 +5165,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 0; codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); spec->pin_nids = stac92hd73xx_pin_nids; @@ -5300,6 +5313,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; spec->mux_nids = stac92hd83xxx_mux_nids; @@ -5335,6 +5349,8 @@ again: case 0x111d7667: case 0x111d7668: case 0x111d7669: + case 0x111d76d1: + case 0x111d76d9: spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); spec->pin_nids = stac92hd88xxx_pin_nids; spec->mono_nid = 0; @@ -5522,6 +5538,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 0; codec->patch_ops = stac92xx_patch_ops; spec->num_pins = STAC92HD71BXX_NUM_PINS; switch (codec->vendor_id) { @@ -5779,6 +5796,7 @@ static int patch_stac922x(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); spec->pin_nids = stac922x_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, @@ -5883,6 +5901,7 @@ static int patch_stac927x(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; codec->slave_dig_outs = stac927x_slave_dig_outs; spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); spec->pin_nids = stac927x_pin_nids; @@ -6018,6 +6037,7 @@ static int patch_stac9205(struct hda_codec *codec) codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); spec->pin_nids = stac9205_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, @@ -6174,6 +6194,7 @@ static int patch_stac9872(struct hda_codec *codec) return -ENOMEM; codec->no_trigger_sense = 1; codec->spec = spec; + spec->linear_tone_beep = 1; spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); spec->pin_nids = stac9872_pin_nids; @@ -6264,6 +6285,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx}, { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx}, { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx}, { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx}, @@ -6280,6 +6303,21 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, + { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 73453814e098..ae3acb2b42d1 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -552,24 +552,30 @@ static void via_auto_init_hp_out(struct hda_codec *codec) } } +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); + static void via_auto_init_analog_input(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + unsigned int ctl; int i; for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; + if (!nid) + continue; + if (spec->smart51_enabled && is_smart51_pins(spec, nid)) + ctl = PIN_OUT; + else if (i <= AUTO_PIN_FRONT_MIC) + ctl = PIN_VREF50; + else + ctl = PIN_IN; snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF50 : PIN_IN)); - + AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); } } -static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); - static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned int *affected_parm) { @@ -658,6 +664,8 @@ static void set_jack_power_state(struct hda_codec *codec) /* PW0 (19h), SW1 (18h), AOW1 (11h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x19, &parm); + if (spec->smart51_enabled) + parm = AC_PWRST_D0; snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, @@ -667,6 +675,8 @@ static void set_jack_power_state(struct hda_codec *codec) if (is_8ch) { parm = AC_PWRST_D3; set_pin_power_state(codec, 0x22, &parm); + if (spec->smart51_enabled) + parm = AC_PWRST_D0; snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm); snd_hda_codec_write(codec, 0x24, 0, @@ -3915,6 +3925,13 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, } } + /* for Smart 5.1, line/mic inputs double as output pins */ + if (cfg->line_outs == 1) { + spec->multiout.num_dacs = 3; + spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11; + spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24; + } + return 0; } @@ -3932,7 +3949,8 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, for (i = 0; i <= AUTO_SEQ_SIDE; i++) { nid = cfg->line_out_pins[i]; - if (!nid) + /* for Smart 5.1, there are always at least six channels */ + if (!nid && i > AUTO_SEQ_CENLFE) continue; nid_vol = nid_vols[i]; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6433e65c9507..467749249576 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1776,6 +1776,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { }, { .subvendor = 0x1014, + .subdevice = 0x0534, + .name = "ThinkPad X31", + .type = AC97_TUNE_INV_EAPD + }, + { + .subvendor = 0x1014, .subdevice = 0x1f00, .name = "MS-9128", .type = AC97_TUNE_ALC_JACK diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index ad4462677615..ad5202efd7a9 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -97,6 +97,7 @@ #include <linux/gameport.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/kernel.h> #include <asm/io.h> #include <sound/core.h> #include <sound/info.h> @@ -667,13 +668,12 @@ static u32 atoh(const unsigned char *in, unsigned int len) unsigned char c; while (len) { + int value; + c = in[len - 1]; - if ((c >= '0') && (c <= '9')) - sum += mult * (c - '0'); - else if ((c >= 'A') && (c <= 'F')) - sum += mult * (c - ('A' - 10)); - else if ((c >= 'a') && (c <= 'f')) - sum += mult * (c - ('a' - 10)); + value = hex_to_bin(c); + if (value >= 0) + sum += mult * value; mult *= 16; --len; } @@ -1224,15 +1224,14 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) firmware.firmware.ASIC, firmware.firmware.CODEC, firmware.firmware.AUXDSP, firmware.firmware.PROG); + if (!chip) + return 1; + for (i = 0; i < FIRMWARE_VERSIONS; i++) { if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) - break; - } - if (i >= FIRMWARE_VERSIONS) - return 0; /* no match */ + return 1; /* OK */ - if (!chip) - return 1; /* OK */ + } snd_printdd("Writing Firmware\n"); if (!chip->fw_entry) { @@ -1615,7 +1614,10 @@ static int snd_riptide_playback_open(struct snd_pcm_substream *substream) chip->playback_substream[sub_num] = substream; runtime->hw = snd_riptide_playback; + data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; data->paths = lbus_play_paths[sub_num]; data->id = play_ids[sub_num]; data->source = play_sources[sub_num]; @@ -1635,7 +1637,10 @@ static int snd_riptide_capture_open(struct snd_pcm_substream *substream) chip->capture_substream = substream; runtime->hw = snd_riptide_capture; + data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; data->paths = lbus_rec_path; data->id = PADC; data->source = ACLNK2PADC; diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 9cc1b5aa0148..1b8f6742b5fa 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -264,11 +264,13 @@ static void sis_update_voice(struct voice *voice) * if using small periods. * * If we're less than 9 samples behind, we're on target. + * Otherwise, shorten the next vperiod by the amount we've + * been delayed. */ if (sync > -9) voice->vperiod = voice->sync_period_size + 1; else - voice->vperiod = voice->sync_period_size - 4; + voice->vperiod = voice->sync_period_size + sync + 10; if (voice->vperiod < voice->buffer_size) { sis_update_sso(voice, voice->vperiod); @@ -736,7 +738,7 @@ static void sis_prepare_timing_voice(struct voice *voice, period_size = buffer_size; /* Initially, we want to interrupt just a bit behind the end of - * the period we're clocking out. 10 samples seems to give a good + * the period we're clocking out. 12 samples seems to give a good * delay. * * We want to spread our interrupts throughout the virtual period, @@ -747,7 +749,7 @@ static void sis_prepare_timing_voice(struct voice *voice, * * This is all moot if we don't need to use virtual periods. */ - vperiod = runtime->period_size + 10; + vperiod = runtime->period_size + 12; if (vperiod > period_size) { u16 tail = vperiod % period_size; u16 quarter_period = period_size / 4; @@ -776,7 +778,7 @@ static void sis_prepare_timing_voice(struct voice *voice, */ timing->flags |= VOICE_SYNC_TIMING; timing->sync_base = voice->ctrl_base; - timing->sync_cso = runtime->period_size - 1; + timing->sync_cso = runtime->period_size; timing->sync_period_size = runtime->period_size; timing->sync_buffer_size = runtime->buffer_size; timing->period_size = period_size; @@ -1047,7 +1049,7 @@ static int sis_chip_free(struct sis7019 *sis) /* Reset the chip, and disable all interrputs. */ outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); - udelay(10); + udelay(25); outl(0, sis->ioport + SIS_GCR); outl(0, sis->ioport + SIS_GIER); @@ -1083,7 +1085,7 @@ static int sis_chip_init(struct sis7019 *sis) /* Reset the audio controller */ outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); - udelay(10); + udelay(25); outl(0, io + SIS_GCR); /* Get the AC-link semaphore, and reset the codecs @@ -1096,7 +1098,7 @@ static int sis_chip_init(struct sis7019 *sis) return -EIO; outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); - udelay(10); + udelay(250); count = 0xffff; while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 7e494b6a1d0e..8c5f8b5a59f0 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -85,6 +85,7 @@ static int joystick; static int ac97_clock = 48000; static char *ac97_quirk; static int dxs_support; +static int dxs_init_volume = 31; static int nodelay; module_param(index, int, 0444); @@ -103,6 +104,8 @@ module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); module_param(dxs_support, int, 0444); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); +module_param(dxs_init_volume, int, 0644); +MODULE_PARM_DESC(dxs_init_volume, "initial DXS volume (0-31)"); module_param(nodelay, int, 0444); MODULE_PARM_DESC(nodelay, "Disable 500ms init delay"); @@ -1245,8 +1248,10 @@ static int snd_via8233_playback_open(struct snd_pcm_substream *substream) return err; stream = viadev->reg_offset / 0x10; if (chip->dxs_controls[stream]) { - chip->playback_volume[stream][0] = 0; - chip->playback_volume[stream][1] = 0; + chip->playback_volume[stream][0] = + VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31); + chip->playback_volume[stream][1] = + VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31); chip->dxs_controls[stream]->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | |