162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci AudioScience HPI driver 562306a36Sopenharmony_ci Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci\file hpicmn.c 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci Common functions used by hpixxxx.c modules 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci(C) Copyright AudioScience Inc. 1998-2003 1362306a36Sopenharmony_ci*******************************************************************************/ 1462306a36Sopenharmony_ci#define SOURCEFILE_NAME "hpicmn.c" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "hpi_internal.h" 1762306a36Sopenharmony_ci#include "hpidebug.h" 1862306a36Sopenharmony_ci#include "hpimsginit.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "hpicmn.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct hpi_adapters_list { 2362306a36Sopenharmony_ci struct hpios_spinlock list_lock; 2462306a36Sopenharmony_ci struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS]; 2562306a36Sopenharmony_ci u16 gw_num_adapters; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic struct hpi_adapters_list adapters; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * hpi_validate_response - Given an HPI Message that was sent out and 3262306a36Sopenharmony_ci * a response that was received, validate that the response has the 3362306a36Sopenharmony_ci * correct fields filled in, i.e ObjectType, Function etc 3462306a36Sopenharmony_ci * @phm: message 3562306a36Sopenharmony_ci * @phr: response 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ciu16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci if (phr->type != HPI_TYPE_RESPONSE) { 4062306a36Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type); 4162306a36Sopenharmony_ci return HPI_ERROR_INVALID_RESPONSE; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (phr->object != phm->object) { 4562306a36Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "header object %d invalid\n", 4662306a36Sopenharmony_ci phr->object); 4762306a36Sopenharmony_ci return HPI_ERROR_INVALID_RESPONSE; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (phr->function != phm->function) { 5162306a36Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "header function %d invalid\n", 5262306a36Sopenharmony_ci phr->function); 5362306a36Sopenharmony_ci return HPI_ERROR_INVALID_RESPONSE; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciu16 hpi_add_adapter(struct hpi_adapter_obj *pao) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci u16 retval = 0; 6262306a36Sopenharmony_ci /*HPI_ASSERT(pao->type); */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci hpios_alistlock_lock(&adapters); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (pao->index >= HPI_MAX_ADAPTERS) { 6762306a36Sopenharmony_ci retval = HPI_ERROR_BAD_ADAPTER_NUMBER; 6862306a36Sopenharmony_ci goto unlock; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (adapters.adapter[pao->index].type) { 7262306a36Sopenharmony_ci int a; 7362306a36Sopenharmony_ci for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) { 7462306a36Sopenharmony_ci if (!adapters.adapter[a].type) { 7562306a36Sopenharmony_ci HPI_DEBUG_LOG(WARNING, 7662306a36Sopenharmony_ci "ASI%X duplicate index %d moved to %d\n", 7762306a36Sopenharmony_ci pao->type, pao->index, a); 7862306a36Sopenharmony_ci pao->index = a; 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci if (a < 0) { 8362306a36Sopenharmony_ci retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER; 8462306a36Sopenharmony_ci goto unlock; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci adapters.adapter[pao->index] = *pao; 8862306a36Sopenharmony_ci hpios_dsplock_init(&adapters.adapter[pao->index]); 8962306a36Sopenharmony_ci adapters.gw_num_adapters++; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciunlock: 9262306a36Sopenharmony_ci hpios_alistlock_unlock(&adapters); 9362306a36Sopenharmony_ci return retval; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid hpi_delete_adapter(struct hpi_adapter_obj *pao) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if (!pao->type) { 9962306a36Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "removing null adapter?\n"); 10062306a36Sopenharmony_ci return; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci hpios_alistlock_lock(&adapters); 10462306a36Sopenharmony_ci if (adapters.adapter[pao->index].type) 10562306a36Sopenharmony_ci adapters.gw_num_adapters--; 10662306a36Sopenharmony_ci memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0])); 10762306a36Sopenharmony_ci hpios_alistlock_unlock(&adapters); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/** 11162306a36Sopenharmony_ci * hpi_find_adapter - FindAdapter returns a pointer to the struct 11262306a36Sopenharmony_ci * hpi_adapter_obj with index wAdapterIndex in an HPI_ADAPTERS_LIST 11362306a36Sopenharmony_ci * structure. 11462306a36Sopenharmony_ci * @adapter_index: value in [0, HPI_MAX_ADAPTERS[ 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistruct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct hpi_adapter_obj *pao = NULL; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (adapter_index >= HPI_MAX_ADAPTERS) { 12162306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n", 12262306a36Sopenharmony_ci adapter_index); 12362306a36Sopenharmony_ci return NULL; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci pao = &adapters.adapter[adapter_index]; 12762306a36Sopenharmony_ci if (pao->type != 0) { 12862306a36Sopenharmony_ci /* 12962306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n", 13062306a36Sopenharmony_ci wAdapterIndex); 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci return pao; 13362306a36Sopenharmony_ci } else { 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n", 13662306a36Sopenharmony_ci wAdapterIndex); 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci return NULL; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * wipe_adapter_list - wipe an HPI_ADAPTERS_LIST structure. 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic void wipe_adapter_list(void) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci memset(&adapters, 0, sizeof(adapters)); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void subsys_get_adapter(struct hpi_message *phm, 15262306a36Sopenharmony_ci struct hpi_response *phr) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci int count = phm->obj_index; 15562306a36Sopenharmony_ci u16 index = 0; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* find the nCount'th nonzero adapter in array */ 15862306a36Sopenharmony_ci for (index = 0; index < HPI_MAX_ADAPTERS; index++) { 15962306a36Sopenharmony_ci if (adapters.adapter[index].type) { 16062306a36Sopenharmony_ci if (!count) 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci count--; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (index < HPI_MAX_ADAPTERS) { 16762306a36Sopenharmony_ci phr->u.s.adapter_index = adapters.adapter[index].index; 16862306a36Sopenharmony_ci phr->u.s.adapter_type = adapters.adapter[index].type; 16962306a36Sopenharmony_ci } else { 17062306a36Sopenharmony_ci phr->u.s.adapter_index = 0; 17162306a36Sopenharmony_ci phr->u.s.adapter_type = 0; 17262306a36Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OBJ_INDEX; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci unsigned int i; 17962306a36Sopenharmony_ci int cached = 0; 18062306a36Sopenharmony_ci if (!pC) 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (pC->init) 18462306a36Sopenharmony_ci return pC->init; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!pC->p_cache) 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (pC->control_count && pC->cache_size_in_bytes) { 19062306a36Sopenharmony_ci char *p_master_cache; 19162306a36Sopenharmony_ci unsigned int byte_count = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci p_master_cache = (char *)pC->p_cache; 19462306a36Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "check %d controls\n", 19562306a36Sopenharmony_ci pC->control_count); 19662306a36Sopenharmony_ci for (i = 0; i < pC->control_count; i++) { 19762306a36Sopenharmony_ci struct hpi_control_cache_info *info = 19862306a36Sopenharmony_ci (struct hpi_control_cache_info *) 19962306a36Sopenharmony_ci &p_master_cache[byte_count]; 20062306a36Sopenharmony_ci u16 control_index = info->control_index; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (control_index >= pC->control_count) { 20362306a36Sopenharmony_ci HPI_DEBUG_LOG(INFO, 20462306a36Sopenharmony_ci "adap %d control index %d out of range, cache not ready?\n", 20562306a36Sopenharmony_ci pC->adap_idx, control_index); 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!info->size_in32bit_words) { 21062306a36Sopenharmony_ci if (!i) { 21162306a36Sopenharmony_ci HPI_DEBUG_LOG(INFO, 21262306a36Sopenharmony_ci "adap %d cache not ready?\n", 21362306a36Sopenharmony_ci pC->adap_idx); 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci /* The cache is invalid. 21762306a36Sopenharmony_ci * Minimum valid entry size is 21862306a36Sopenharmony_ci * sizeof(struct hpi_control_cache_info) 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 22162306a36Sopenharmony_ci "adap %d zero size cache entry %d\n", 22262306a36Sopenharmony_ci pC->adap_idx, i); 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (info->control_type) { 22762306a36Sopenharmony_ci pC->p_info[control_index] = info; 22862306a36Sopenharmony_ci cached++; 22962306a36Sopenharmony_ci } else { /* dummy cache entry */ 23062306a36Sopenharmony_ci pC->p_info[control_index] = NULL; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci byte_count += info->size_in32bit_words * 4; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 23662306a36Sopenharmony_ci "cached %d, pinfo %p index %d type %d size %d\n", 23762306a36Sopenharmony_ci cached, pC->p_info[info->control_index], 23862306a36Sopenharmony_ci info->control_index, info->control_type, 23962306a36Sopenharmony_ci info->size_in32bit_words); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* quit loop early if whole cache has been scanned. 24262306a36Sopenharmony_ci * dwControlCount is the maximum possible entries 24362306a36Sopenharmony_ci * but some may be absent from the cache 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci if (byte_count >= pC->cache_size_in_bytes) 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci /* have seen last control index */ 24862306a36Sopenharmony_ci if (info->control_index == pC->control_count - 1) 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (byte_count != pC->cache_size_in_bytes) 25362306a36Sopenharmony_ci HPI_DEBUG_LOG(WARNING, 25462306a36Sopenharmony_ci "adap %d bytecount %d != cache size %d\n", 25562306a36Sopenharmony_ci pC->adap_idx, byte_count, 25662306a36Sopenharmony_ci pC->cache_size_in_bytes); 25762306a36Sopenharmony_ci else 25862306a36Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, 25962306a36Sopenharmony_ci "adap %d cache good, bytecount == cache size = %d\n", 26062306a36Sopenharmony_ci pC->adap_idx, byte_count); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci pC->init = (u16)cached; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci return pC->init; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/** Find a control. 26862306a36Sopenharmony_ci*/ 26962306a36Sopenharmony_cistatic short find_control(u16 control_index, 27062306a36Sopenharmony_ci struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci if (!control_cache_alloc_check(p_cache)) { 27362306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 27462306a36Sopenharmony_ci "control_cache_alloc_check() failed %d\n", 27562306a36Sopenharmony_ci control_index); 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci *pI = p_cache->p_info[control_index]; 28062306a36Sopenharmony_ci if (!*pI) { 28162306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", 28262306a36Sopenharmony_ci control_index); 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci } else { 28562306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", 28662306a36Sopenharmony_ci (*pI)->control_type); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci return 1; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* allow unified treatment of several string fields within struct */ 29262306a36Sopenharmony_ci#define HPICMN_PAD_OFS_AND_SIZE(m) {\ 29362306a36Sopenharmony_ci offsetof(struct hpi_control_cache_pad, m), \ 29462306a36Sopenharmony_ci sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistruct pad_ofs_size { 29762306a36Sopenharmony_ci unsigned int offset; 29862306a36Sopenharmony_ci unsigned int field_size; 29962306a36Sopenharmony_ci}; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic const struct pad_ofs_size pad_desc[] = { 30262306a36Sopenharmony_ci HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ 30362306a36Sopenharmony_ci HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ 30462306a36Sopenharmony_ci HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ 30562306a36Sopenharmony_ci HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ 30662306a36Sopenharmony_ci}; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/** CheckControlCache checks the cache and fills the struct hpi_response 30962306a36Sopenharmony_ci * accordingly. It returns one if a cache hit occurred, zero otherwise. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cishort hpi_check_control_cache_single(struct hpi_control_cache_single *pC, 31262306a36Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci size_t response_size; 31562306a36Sopenharmony_ci short found = 1; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* set the default response size */ 31862306a36Sopenharmony_ci response_size = 31962306a36Sopenharmony_ci sizeof(struct hpi_response_header) + 32062306a36Sopenharmony_ci sizeof(struct hpi_control_res); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci switch (pC->u.i.control_type) { 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci case HPI_CONTROL_METER: 32562306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_METER_PEAK) { 32662306a36Sopenharmony_ci phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; 32762306a36Sopenharmony_ci phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; 32862306a36Sopenharmony_ci } else if (phm->u.c.attribute == HPI_METER_RMS) { 32962306a36Sopenharmony_ci if (pC->u.meter.an_logRMS[0] == 33062306a36Sopenharmony_ci HPI_CACHE_INVALID_SHORT) { 33162306a36Sopenharmony_ci phr->error = 33262306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; 33362306a36Sopenharmony_ci phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; 33462306a36Sopenharmony_ci phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; 33562306a36Sopenharmony_ci } else { 33662306a36Sopenharmony_ci phr->u.c.an_log_value[0] = 33762306a36Sopenharmony_ci pC->u.meter.an_logRMS[0]; 33862306a36Sopenharmony_ci phr->u.c.an_log_value[1] = 33962306a36Sopenharmony_ci pC->u.meter.an_logRMS[1]; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } else 34262306a36Sopenharmony_ci found = 0; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case HPI_CONTROL_VOLUME: 34562306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_VOLUME_GAIN) { 34662306a36Sopenharmony_ci phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; 34762306a36Sopenharmony_ci phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; 34862306a36Sopenharmony_ci } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { 34962306a36Sopenharmony_ci if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) { 35062306a36Sopenharmony_ci if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED) 35162306a36Sopenharmony_ci phr->u.c.param1 = 35262306a36Sopenharmony_ci HPI_BITMASK_ALL_CHANNELS; 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci phr->u.c.param1 = 0; 35562306a36Sopenharmony_ci } else { 35662306a36Sopenharmony_ci phr->error = 35762306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; 35862306a36Sopenharmony_ci phr->u.c.param1 = 0; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci } else { 36162306a36Sopenharmony_ci found = 0; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci case HPI_CONTROL_MULTIPLEXER: 36562306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { 36662306a36Sopenharmony_ci phr->u.c.param1 = pC->u.mux.source_node_type; 36762306a36Sopenharmony_ci phr->u.c.param2 = pC->u.mux.source_node_index; 36862306a36Sopenharmony_ci } else { 36962306a36Sopenharmony_ci found = 0; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci case HPI_CONTROL_CHANNEL_MODE: 37362306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) 37462306a36Sopenharmony_ci phr->u.c.param1 = pC->u.mode.mode; 37562306a36Sopenharmony_ci else 37662306a36Sopenharmony_ci found = 0; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci case HPI_CONTROL_LEVEL: 37962306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_LEVEL_GAIN) { 38062306a36Sopenharmony_ci phr->u.c.an_log_value[0] = pC->u.level.an_log[0]; 38162306a36Sopenharmony_ci phr->u.c.an_log_value[1] = pC->u.level.an_log[1]; 38262306a36Sopenharmony_ci } else 38362306a36Sopenharmony_ci found = 0; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case HPI_CONTROL_TUNER: 38662306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_TUNER_FREQ) 38762306a36Sopenharmony_ci phr->u.c.param1 = pC->u.tuner.freq_ink_hz; 38862306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_TUNER_BAND) 38962306a36Sopenharmony_ci phr->u.c.param1 = pC->u.tuner.band; 39062306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG) 39162306a36Sopenharmony_ci if (pC->u.tuner.s_level_avg == 39262306a36Sopenharmony_ci HPI_CACHE_INVALID_SHORT) { 39362306a36Sopenharmony_ci phr->u.cu.tuner.s_level = 0; 39462306a36Sopenharmony_ci phr->error = 39562306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; 39662306a36Sopenharmony_ci } else 39762306a36Sopenharmony_ci phr->u.cu.tuner.s_level = 39862306a36Sopenharmony_ci pC->u.tuner.s_level_avg; 39962306a36Sopenharmony_ci else 40062306a36Sopenharmony_ci found = 0; 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci case HPI_CONTROL_AESEBU_RECEIVER: 40362306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) 40462306a36Sopenharmony_ci phr->u.c.param1 = pC->u.aes3rx.error_status; 40562306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) 40662306a36Sopenharmony_ci phr->u.c.param1 = pC->u.aes3rx.format; 40762306a36Sopenharmony_ci else 40862306a36Sopenharmony_ci found = 0; 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case HPI_CONTROL_AESEBU_TRANSMITTER: 41162306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) 41262306a36Sopenharmony_ci phr->u.c.param1 = pC->u.aes3tx.format; 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci found = 0; 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci case HPI_CONTROL_TONEDETECTOR: 41762306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) 41862306a36Sopenharmony_ci phr->u.c.param1 = pC->u.tone.state; 41962306a36Sopenharmony_ci else 42062306a36Sopenharmony_ci found = 0; 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case HPI_CONTROL_SILENCEDETECTOR: 42362306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { 42462306a36Sopenharmony_ci phr->u.c.param1 = pC->u.silence.state; 42562306a36Sopenharmony_ci } else 42662306a36Sopenharmony_ci found = 0; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci case HPI_CONTROL_MICROPHONE: 42962306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) 43062306a36Sopenharmony_ci phr->u.c.param1 = pC->u.microphone.phantom_state; 43162306a36Sopenharmony_ci else 43262306a36Sopenharmony_ci found = 0; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case HPI_CONTROL_SAMPLECLOCK: 43562306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) 43662306a36Sopenharmony_ci phr->u.c.param1 = pC->u.clk.source; 43762306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { 43862306a36Sopenharmony_ci if (pC->u.clk.source_index == 43962306a36Sopenharmony_ci HPI_CACHE_INVALID_UINT16) { 44062306a36Sopenharmony_ci phr->u.c.param1 = 0; 44162306a36Sopenharmony_ci phr->error = 44262306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; 44362306a36Sopenharmony_ci } else 44462306a36Sopenharmony_ci phr->u.c.param1 = pC->u.clk.source_index; 44562306a36Sopenharmony_ci } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) 44662306a36Sopenharmony_ci phr->u.c.param1 = pC->u.clk.sample_rate; 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci found = 0; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case HPI_CONTROL_PAD:{ 45162306a36Sopenharmony_ci struct hpi_control_cache_pad *p_pad; 45262306a36Sopenharmony_ci p_pad = (struct hpi_control_cache_pad *)pC; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (!(p_pad->field_valid_flags & (1 << 45562306a36Sopenharmony_ci HPI_CTL_ATTR_INDEX(phm->u.c. 45662306a36Sopenharmony_ci attribute)))) { 45762306a36Sopenharmony_ci phr->error = 45862306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) 46362306a36Sopenharmony_ci phr->u.c.param1 = p_pad->pI; 46462306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) 46562306a36Sopenharmony_ci phr->u.c.param1 = p_pad->pTY; 46662306a36Sopenharmony_ci else { 46762306a36Sopenharmony_ci unsigned int index = 46862306a36Sopenharmony_ci HPI_CTL_ATTR_INDEX(phm->u.c. 46962306a36Sopenharmony_ci attribute) - 1; 47062306a36Sopenharmony_ci unsigned int offset = phm->u.c.param1; 47162306a36Sopenharmony_ci unsigned int pad_string_len, field_size; 47262306a36Sopenharmony_ci char *pad_string; 47362306a36Sopenharmony_ci unsigned int tocopy; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (index > ARRAY_SIZE(pad_desc) - 1) { 47662306a36Sopenharmony_ci phr->error = 47762306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci pad_string = 48262306a36Sopenharmony_ci ((char *)p_pad) + 48362306a36Sopenharmony_ci pad_desc[index].offset; 48462306a36Sopenharmony_ci field_size = pad_desc[index].field_size; 48562306a36Sopenharmony_ci /* Ensure null terminator */ 48662306a36Sopenharmony_ci pad_string[field_size - 1] = 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci pad_string_len = strlen(pad_string) + 1; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (offset > pad_string_len) { 49162306a36Sopenharmony_ci phr->error = 49262306a36Sopenharmony_ci HPI_ERROR_INVALID_CONTROL_VALUE; 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci tocopy = pad_string_len - offset; 49762306a36Sopenharmony_ci if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) 49862306a36Sopenharmony_ci tocopy = sizeof(phr->u.cu.chars8. 49962306a36Sopenharmony_ci sz_data); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci memcpy(phr->u.cu.chars8.sz_data, 50262306a36Sopenharmony_ci &pad_string[offset], tocopy); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci phr->u.cu.chars8.remaining_chars = 50562306a36Sopenharmony_ci pad_string_len - offset - tocopy; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci default: 51062306a36Sopenharmony_ci found = 0; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", 51562306a36Sopenharmony_ci found ? "Cached" : "Uncached", phm->adapter_index, 51662306a36Sopenharmony_ci pC->u.i.control_index, pC->u.i.control_type, 51762306a36Sopenharmony_ci phm->u.c.attribute); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (found) { 52062306a36Sopenharmony_ci phr->size = (u16)response_size; 52162306a36Sopenharmony_ci phr->type = HPI_TYPE_RESPONSE; 52262306a36Sopenharmony_ci phr->object = phm->object; 52362306a36Sopenharmony_ci phr->function = phm->function; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return found; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cishort hpi_check_control_cache(struct hpi_control_cache *p_cache, 53062306a36Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct hpi_control_cache_info *pI; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (!find_control(phm->obj_index, p_cache, &pI)) { 53562306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 53662306a36Sopenharmony_ci "HPICMN find_control() failed for adap %d\n", 53762306a36Sopenharmony_ci phm->adapter_index); 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci phr->error = 0; 54262306a36Sopenharmony_ci phr->specific_error = 0; 54362306a36Sopenharmony_ci phr->version = 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return hpi_check_control_cache_single((struct hpi_control_cache_single 54662306a36Sopenharmony_ci *)pI, phm, phr); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/** Updates the cache with Set values. 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ciOnly update if no error. 55262306a36Sopenharmony_ciVolume and Level return the limited values in the response, so use these 55362306a36Sopenharmony_ciMultiplexer does so use sent values 55462306a36Sopenharmony_ci*/ 55562306a36Sopenharmony_civoid hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single 55662306a36Sopenharmony_ci *pC, struct hpi_message *phm, struct hpi_response *phr) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci switch (pC->u.i.control_type) { 55962306a36Sopenharmony_ci case HPI_CONTROL_VOLUME: 56062306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_VOLUME_GAIN) { 56162306a36Sopenharmony_ci pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; 56262306a36Sopenharmony_ci pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; 56362306a36Sopenharmony_ci } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { 56462306a36Sopenharmony_ci if (phm->u.c.param1) 56562306a36Sopenharmony_ci pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED; 56662306a36Sopenharmony_ci else 56762306a36Sopenharmony_ci pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci case HPI_CONTROL_MULTIPLEXER: 57162306a36Sopenharmony_ci /* mux does not return its setting on Set command. */ 57262306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { 57362306a36Sopenharmony_ci pC->u.mux.source_node_type = (u16)phm->u.c.param1; 57462306a36Sopenharmony_ci pC->u.mux.source_node_index = (u16)phm->u.c.param2; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci case HPI_CONTROL_CHANNEL_MODE: 57862306a36Sopenharmony_ci /* mode does not return its setting on Set command. */ 57962306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) 58062306a36Sopenharmony_ci pC->u.mode.mode = (u16)phm->u.c.param1; 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case HPI_CONTROL_LEVEL: 58362306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_LEVEL_GAIN) { 58462306a36Sopenharmony_ci pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; 58562306a36Sopenharmony_ci pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci case HPI_CONTROL_MICROPHONE: 58962306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) 59062306a36Sopenharmony_ci pC->u.microphone.phantom_state = (u16)phm->u.c.param1; 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci case HPI_CONTROL_AESEBU_TRANSMITTER: 59362306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) 59462306a36Sopenharmony_ci pC->u.aes3tx.format = phm->u.c.param1; 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci case HPI_CONTROL_AESEBU_RECEIVER: 59762306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) 59862306a36Sopenharmony_ci pC->u.aes3rx.format = phm->u.c.param1; 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case HPI_CONTROL_SAMPLECLOCK: 60162306a36Sopenharmony_ci if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) 60262306a36Sopenharmony_ci pC->u.clk.source = (u16)phm->u.c.param1; 60362306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) 60462306a36Sopenharmony_ci pC->u.clk.source_index = (u16)phm->u.c.param1; 60562306a36Sopenharmony_ci else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) 60662306a36Sopenharmony_ci pC->u.clk.sample_rate = phm->u.c.param1; 60762306a36Sopenharmony_ci break; 60862306a36Sopenharmony_ci default: 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_civoid hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, 61462306a36Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct hpi_control_cache_single *pC; 61762306a36Sopenharmony_ci struct hpi_control_cache_info *pI; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (phr->error) 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (!find_control(phm->obj_index, p_cache, &pI)) { 62362306a36Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 62462306a36Sopenharmony_ci "HPICMN find_control() failed for adap %d\n", 62562306a36Sopenharmony_ci phm->adapter_index); 62662306a36Sopenharmony_ci return; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* pC is the default cached control strucure. 63062306a36Sopenharmony_ci May be cast to something else in the following switch statement. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci pC = (struct hpi_control_cache_single *)pI; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/** Allocate control cache. 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci\return Cache pointer, or NULL if allocation fails. 64062306a36Sopenharmony_ci*/ 64162306a36Sopenharmony_cistruct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, 64262306a36Sopenharmony_ci const u32 size_in_bytes, u8 *p_dsp_control_buffer) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct hpi_control_cache *p_cache = 64562306a36Sopenharmony_ci kmalloc(sizeof(*p_cache), GFP_KERNEL); 64662306a36Sopenharmony_ci if (!p_cache) 64762306a36Sopenharmony_ci return NULL; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci p_cache->p_info = 65062306a36Sopenharmony_ci kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL); 65162306a36Sopenharmony_ci if (!p_cache->p_info) { 65262306a36Sopenharmony_ci kfree(p_cache); 65362306a36Sopenharmony_ci return NULL; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci p_cache->cache_size_in_bytes = size_in_bytes; 65762306a36Sopenharmony_ci p_cache->control_count = control_count; 65862306a36Sopenharmony_ci p_cache->p_cache = p_dsp_control_buffer; 65962306a36Sopenharmony_ci p_cache->init = 0; 66062306a36Sopenharmony_ci return p_cache; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_civoid hpi_free_control_cache(struct hpi_control_cache *p_cache) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci if (p_cache) { 66662306a36Sopenharmony_ci kfree(p_cache->p_info); 66762306a36Sopenharmony_ci kfree(p_cache); 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic void subsys_message(struct hpi_message *phm, struct hpi_response *phr) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci switch (phm->function) { 67662306a36Sopenharmony_ci case HPI_SUBSYS_OPEN: 67762306a36Sopenharmony_ci case HPI_SUBSYS_CLOSE: 67862306a36Sopenharmony_ci case HPI_SUBSYS_DRIVER_UNLOAD: 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci case HPI_SUBSYS_DRIVER_LOAD: 68162306a36Sopenharmony_ci wipe_adapter_list(); 68262306a36Sopenharmony_ci hpios_alistlock_init(&adapters); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case HPI_SUBSYS_GET_ADAPTER: 68562306a36Sopenharmony_ci subsys_get_adapter(phm, phr); 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci case HPI_SUBSYS_GET_NUM_ADAPTERS: 68862306a36Sopenharmony_ci phr->u.s.num_adapters = adapters.gw_num_adapters; 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci case HPI_SUBSYS_CREATE_ADAPTER: 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci default: 69362306a36Sopenharmony_ci phr->error = HPI_ERROR_INVALID_FUNC; 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_civoid HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci switch (phm->type) { 70162306a36Sopenharmony_ci case HPI_TYPE_REQUEST: 70262306a36Sopenharmony_ci switch (phm->object) { 70362306a36Sopenharmony_ci case HPI_OBJ_SUBSYSTEM: 70462306a36Sopenharmony_ci subsys_message(phm, phr); 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci break; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci default: 71062306a36Sopenharmony_ci phr->error = HPI_ERROR_INVALID_TYPE; 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci} 714