blob: 7d1abaedb46acc37fb7c47dbfb7c7749b7b2c36e [file] [log] [blame]
Thomas Gleixner07d7fe72019-05-29 07:12:47 -07001// SPDX-License-Identifier: GPL-2.0-only
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +02002/******************************************************************************
3
4 AudioScience HPI driver
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +13005 Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +02006
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +02007
8\file hpicmn.c
9
10 Common functions used by hpixxxx.c modules
11
12(C) Copyright AudioScience Inc. 1998-2003
13*******************************************************************************/
14#define SOURCEFILE_NAME "hpicmn.c"
15
16#include "hpi_internal.h"
17#include "hpidebug.h"
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130018#include "hpimsginit.h"
19
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020020#include "hpicmn.h"
21
22struct hpi_adapters_list {
23 struct hpios_spinlock list_lock;
24 struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS];
25 u16 gw_num_adapters;
26};
27
28static struct hpi_adapters_list adapters;
29
30/**
Pierre-Louis Bossart7d23b162020-07-02 14:35:45 -050031 * hpi_validate_response - Given an HPI Message that was sent out and
32 * a response that was received, validate that the response has the
33 * correct fields filled in, i.e ObjectType, Function etc
34 * @phm: message
35 * @phr: response
36 */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020037u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
38{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130039 if (phr->type != HPI_TYPE_RESPONSE) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130040 HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130041 return HPI_ERROR_INVALID_RESPONSE;
42 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020043
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130044 if (phr->object != phm->object) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130045 HPI_DEBUG_LOG(ERROR, "header object %d invalid\n",
46 phr->object);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130047 return HPI_ERROR_INVALID_RESPONSE;
48 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020049
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130050 if (phr->function != phm->function) {
Eliot Blennerhassett938c5652011-07-22 15:52:50 +120051 HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130052 phr->function);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130053 return HPI_ERROR_INVALID_RESPONSE;
54 }
55
56 return 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020057}
58
59u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
60{
61 u16 retval = 0;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130062 /*HPI_ASSERT(pao->type); */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020063
64 hpios_alistlock_lock(&adapters);
65
66 if (pao->index >= HPI_MAX_ADAPTERS) {
67 retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
68 goto unlock;
69 }
70
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130071 if (adapters.adapter[pao->index].type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130072 int a;
73 for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130074 if (!adapters.adapter[a].type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130075 HPI_DEBUG_LOG(WARNING,
76 "ASI%X duplicate index %d moved to %d\n",
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130077 pao->type, pao->index, a);
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130078 pao->index = a;
79 break;
80 }
81 }
82 if (a < 0) {
83 retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020084 goto unlock;
85 }
86 }
87 adapters.adapter[pao->index] = *pao;
88 hpios_dsplock_init(&adapters.adapter[pao->index]);
89 adapters.gw_num_adapters++;
90
91unlock:
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130092 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020093 return retval;
94}
95
96void hpi_delete_adapter(struct hpi_adapter_obj *pao)
97{
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130098 if (!pao->type) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130099 HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
100 return;
101 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200102
103 hpios_alistlock_lock(&adapters);
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300104 if (adapters.adapter[pao->index].type)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300105 adapters.gw_num_adapters--;
106 memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
107 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200108}
109
110/**
Pierre-Louis Bossart7d23b162020-07-02 14:35:45 -0500111 * hpi_find_adapter - FindAdapter returns a pointer to the struct
112 * hpi_adapter_obj with index wAdapterIndex in an HPI_ADAPTERS_LIST
113 * structure.
114 * @adapter_index: value in [0, HPI_MAX_ADAPTERS[
115 */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200116struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
117{
118 struct hpi_adapter_obj *pao = NULL;
119
120 if (adapter_index >= HPI_MAX_ADAPTERS) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300121 HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n",
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200122 adapter_index);
123 return NULL;
124 }
125
126 pao = &adapters.adapter[adapter_index];
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300127 if (pao->type != 0) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200128 /*
129 HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
130 wAdapterIndex);
131 */
132 return pao;
133 } else {
134 /*
135 HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
136 wAdapterIndex);
137 */
138 return NULL;
139 }
140}
141
142/**
Pierre-Louis Bossart7d23b162020-07-02 14:35:45 -0500143 * wipe_adapter_list - wipe an HPI_ADAPTERS_LIST structure.
144 *
145 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300146static void wipe_adapter_list(void)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200147{
148 memset(&adapters, 0, sizeof(adapters));
149}
150
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300151static void subsys_get_adapter(struct hpi_message *phm,
152 struct hpi_response *phr)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200153{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300154 int count = phm->obj_index;
155 u16 index = 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200156
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300157 /* find the nCount'th nonzero adapter in array */
158 for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300159 if (adapters.adapter[index].type) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300160 if (!count)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300161 break;
162 count--;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200163 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200164 }
165
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300166 if (index < HPI_MAX_ADAPTERS) {
167 phr->u.s.adapter_index = adapters.adapter[index].index;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300168 phr->u.s.adapter_type = adapters.adapter[index].type;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300169 } else {
170 phr->u.s.adapter_index = 0;
Eliot Blennerhassett2f918a62011-02-10 17:26:09 +1300171 phr->u.s.adapter_type = 0;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300172 phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300173 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200174}
175
176static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
177{
178 unsigned int i;
179 int cached = 0;
180 if (!pC)
181 return 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200182
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300183 if (pC->init)
184 return pC->init;
185
186 if (!pC->p_cache)
187 return 0;
188
189 if (pC->control_count && pC->cache_size_in_bytes) {
190 char *p_master_cache;
191 unsigned int byte_count = 0;
192
193 p_master_cache = (char *)pC->p_cache;
194 HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200195 pC->control_count);
196 for (i = 0; i < pC->control_count; i++) {
197 struct hpi_control_cache_info *info =
198 (struct hpi_control_cache_info *)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300199 &p_master_cache[byte_count];
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300200 u16 control_index = info->control_index;
201
202 if (control_index >= pC->control_count) {
203 HPI_DEBUG_LOG(INFO,
204 "adap %d control index %d out of range, cache not ready?\n",
205 pC->adap_idx, control_index);
206 return 0;
207 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300208
209 if (!info->size_in32bit_words) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300210 if (!i) {
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300211 HPI_DEBUG_LOG(INFO,
212 "adap %d cache not ready?\n",
213 pC->adap_idx);
214 return 0;
215 }
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300216 /* The cache is invalid.
217 * Minimum valid entry size is
218 * sizeof(struct hpi_control_cache_info)
219 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300220 HPI_DEBUG_LOG(ERROR,
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300221 "adap %d zero size cache entry %d\n",
222 pC->adap_idx, i);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300223 break;
224 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200225
226 if (info->control_type) {
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300227 pC->p_info[control_index] = info;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200228 cached++;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200229 } else { /* dummy cache entry */
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300230 pC->p_info[control_index] = NULL;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200231 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200232
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300233 byte_count += info->size_in32bit_words * 4;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200234
235 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300236 "cached %d, pinfo %p index %d type %d size %d\n",
237 cached, pC->p_info[info->control_index],
238 info->control_index, info->control_type,
239 info->size_in32bit_words);
240
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300241 /* quit loop early if whole cache has been scanned.
242 * dwControlCount is the maximum possible entries
243 * but some may be absent from the cache
244 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300245 if (byte_count >= pC->cache_size_in_bytes)
246 break;
247 /* have seen last control index */
248 if (info->control_index == pC->control_count - 1)
249 break;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200250 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300251
252 if (byte_count != pC->cache_size_in_bytes)
253 HPI_DEBUG_LOG(WARNING,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300254 "adap %d bytecount %d != cache size %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300255 pC->adap_idx, byte_count,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300256 pC->cache_size_in_bytes);
257 else
258 HPI_DEBUG_LOG(DEBUG,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300259 "adap %d cache good, bytecount == cache size = %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300260 pC->adap_idx, byte_count);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300261
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300262 pC->init = (u16)cached;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200263 }
264 return pC->init;
265}
266
267/** Find a control.
268*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300269static short find_control(u16 control_index,
270 struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200271{
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200272 if (!control_cache_alloc_check(p_cache)) {
273 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300274 "control_cache_alloc_check() failed %d\n",
275 control_index);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200276 return 0;
277 }
278
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300279 *pI = p_cache->p_info[control_index];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200280 if (!*pI) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300281 HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
282 control_index);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200283 return 0;
284 } else {
285 HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
286 (*pI)->control_type);
287 }
288 return 1;
289}
290
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200291/* allow unified treatment of several string fields within struct */
292#define HPICMN_PAD_OFS_AND_SIZE(m) {\
293 offsetof(struct hpi_control_cache_pad, m), \
294 sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
295
296struct pad_ofs_size {
297 unsigned int offset;
298 unsigned int field_size;
299};
300
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200301static const struct pad_ofs_size pad_desc[] = {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200302 HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
303 HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
304 HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
305 HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
306};
307
308/** CheckControlCache checks the cache and fills the struct hpi_response
309 * accordingly. It returns one if a cache hit occurred, zero otherwise.
310 */
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300311short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200312 struct hpi_message *phm, struct hpi_response *phr)
313{
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200314 size_t response_size;
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300315 short found = 1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200316
Eliot Blennerhassettc6c2c9a2011-07-22 15:52:38 +1200317 /* set the default response size */
318 response_size =
319 sizeof(struct hpi_response_header) +
320 sizeof(struct hpi_control_res);
321
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300322 switch (pC->u.i.control_type) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200323
324 case HPI_CONTROL_METER:
325 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300326 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
327 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200328 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300329 if (pC->u.meter.an_logRMS[0] ==
330 HPI_CACHE_INVALID_SHORT) {
331 phr->error =
332 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
333 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
334 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
335 } else {
336 phr->u.c.an_log_value[0] =
337 pC->u.meter.an_logRMS[0];
338 phr->u.c.an_log_value[1] =
339 pC->u.meter.an_logRMS[1];
340 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200341 } else
342 found = 0;
343 break;
344 case HPI_CONTROL_VOLUME:
345 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300346 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
347 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300348 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
349 if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
350 if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
351 phr->u.c.param1 =
352 HPI_BITMASK_ALL_CHANNELS;
353 else
354 phr->u.c.param1 = 0;
355 } else {
356 phr->error =
357 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
358 phr->u.c.param1 = 0;
359 }
360 } else {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200361 found = 0;
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300362 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200363 break;
364 case HPI_CONTROL_MULTIPLEXER:
365 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300366 phr->u.c.param1 = pC->u.mux.source_node_type;
367 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200368 } else {
369 found = 0;
370 }
371 break;
372 case HPI_CONTROL_CHANNEL_MODE:
373 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300374 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200375 else
376 found = 0;
377 break;
378 case HPI_CONTROL_LEVEL:
379 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300380 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
381 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200382 } else
383 found = 0;
384 break;
385 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317fe2010-05-27 17:53:55 +1200386 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300387 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317fe2010-05-27 17:53:55 +1200388 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300389 phr->u.c.param1 = pC->u.tuner.band;
390 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
391 if (pC->u.tuner.s_level_avg ==
392 HPI_CACHE_INVALID_SHORT) {
393 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200394 phr->error =
395 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
396 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300397 phr->u.cu.tuner.s_level =
398 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317fe2010-05-27 17:53:55 +1200399 else
400 found = 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200401 break;
402 case HPI_CONTROL_AESEBU_RECEIVER:
403 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
404 phr->u.c.param1 = pC->u.aes3rx.error_status;
405 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300406 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200407 else
408 found = 0;
409 break;
410 case HPI_CONTROL_AESEBU_TRANSMITTER:
411 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
412 phr->u.c.param1 = pC->u.aes3tx.format;
413 else
414 found = 0;
415 break;
416 case HPI_CONTROL_TONEDETECTOR:
417 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
418 phr->u.c.param1 = pC->u.tone.state;
419 else
420 found = 0;
421 break;
422 case HPI_CONTROL_SILENCEDETECTOR:
423 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
424 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200425 } else
426 found = 0;
427 break;
428 case HPI_CONTROL_MICROPHONE:
429 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300430 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200431 else
432 found = 0;
433 break;
434 case HPI_CONTROL_SAMPLECLOCK:
435 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
436 phr->u.c.param1 = pC->u.clk.source;
437 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
438 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300439 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200440 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200441 phr->error =
442 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200443 } else
444 phr->u.c.param1 = pC->u.clk.source_index;
445 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
446 phr->u.c.param1 = pC->u.clk.sample_rate;
447 else
448 found = 0;
449 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300450 case HPI_CONTROL_PAD:{
451 struct hpi_control_cache_pad *p_pad;
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300452 p_pad = (struct hpi_control_cache_pad *)pC;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200453
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300454 if (!(p_pad->field_valid_flags & (1 <<
455 HPI_CTL_ATTR_INDEX(phm->u.c.
456 attribute)))) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200457 phr->error =
458 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
459 break;
460 }
461
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300462 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
463 phr->u.c.param1 = p_pad->pI;
464 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
465 phr->u.c.param1 = p_pad->pTY;
466 else {
467 unsigned int index =
468 HPI_CTL_ATTR_INDEX(phm->u.c.
469 attribute) - 1;
470 unsigned int offset = phm->u.c.param1;
471 unsigned int pad_string_len, field_size;
472 char *pad_string;
473 unsigned int tocopy;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200474
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300475 if (index > ARRAY_SIZE(pad_desc) - 1) {
476 phr->error =
477 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
478 break;
479 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200480
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300481 pad_string =
482 ((char *)p_pad) +
483 pad_desc[index].offset;
484 field_size = pad_desc[index].field_size;
485 /* Ensure null terminator */
486 pad_string[field_size - 1] = 0;
487
488 pad_string_len = strlen(pad_string) + 1;
489
490 if (offset > pad_string_len) {
491 phr->error =
492 HPI_ERROR_INVALID_CONTROL_VALUE;
493 break;
494 }
495
496 tocopy = pad_string_len - offset;
497 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
498 tocopy = sizeof(phr->u.cu.chars8.
499 sz_data);
500
501 memcpy(phr->u.cu.chars8.sz_data,
502 &pad_string[offset], tocopy);
503
504 phr->u.cu.chars8.remaining_chars =
505 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200506 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200507 }
508 break;
509 default:
510 found = 0;
511 break;
512 }
513
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300514 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
515 found ? "Cached" : "Uncached", phm->adapter_index,
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300516 pC->u.i.control_index, pC->u.i.control_type,
517 phm->u.c.attribute);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200518
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300519 if (found) {
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200520 phr->size = (u16)response_size;
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300521 phr->type = HPI_TYPE_RESPONSE;
522 phr->object = phm->object;
523 phr->function = phm->function;
524 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200525
526 return found;
527}
528
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300529short hpi_check_control_cache(struct hpi_control_cache *p_cache,
530 struct hpi_message *phm, struct hpi_response *phr)
531{
532 struct hpi_control_cache_info *pI;
533
534 if (!find_control(phm->obj_index, p_cache, &pI)) {
535 HPI_DEBUG_LOG(VERBOSE,
536 "HPICMN find_control() failed for adap %d\n",
537 phm->adapter_index);
538 return 0;
539 }
540
541 phr->error = 0;
542 phr->specific_error = 0;
543 phr->version = 0;
544
545 return hpi_check_control_cache_single((struct hpi_control_cache_single
546 *)pI, phm, phr);
547}
548
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200549/** Updates the cache with Set values.
550
551Only update if no error.
552Volume and Level return the limited values in the response, so use these
553Multiplexer does so use sent values
554*/
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300555void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
556 *pC, struct hpi_message *phm, struct hpi_response *phr)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200557{
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300558 switch (pC->u.i.control_type) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200559 case HPI_CONTROL_VOLUME:
560 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300561 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
562 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300563 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
564 if (phm->u.c.param1)
565 pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
566 else
567 pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200568 }
569 break;
570 case HPI_CONTROL_MULTIPLEXER:
571 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200572 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300573 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
574 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200575 }
576 break;
577 case HPI_CONTROL_CHANNEL_MODE:
578 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200579 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300580 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200581 break;
582 case HPI_CONTROL_LEVEL:
583 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300584 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
585 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200586 }
587 break;
588 case HPI_CONTROL_MICROPHONE:
589 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300590 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200591 break;
592 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200593 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
594 pC->u.aes3tx.format = phm->u.c.param1;
595 break;
596 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200597 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300598 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200599 break;
600 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200601 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
602 pC->u.clk.source = (u16)phm->u.c.param1;
603 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
604 pC->u.clk.source_index = (u16)phm->u.c.param1;
605 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
606 pC->u.clk.sample_rate = phm->u.c.param1;
607 break;
608 default:
609 break;
610 }
611}
612
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300613void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
614 struct hpi_message *phm, struct hpi_response *phr)
615{
616 struct hpi_control_cache_single *pC;
617 struct hpi_control_cache_info *pI;
618
619 if (phr->error)
620 return;
621
622 if (!find_control(phm->obj_index, p_cache, &pI)) {
623 HPI_DEBUG_LOG(VERBOSE,
624 "HPICMN find_control() failed for adap %d\n",
625 phm->adapter_index);
626 return;
627 }
628
629 /* pC is the default cached control strucure.
630 May be cast to something else in the following switch statement.
631 */
632 pC = (struct hpi_control_cache_single *)pI;
633
634 hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr);
635}
636
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200637/** Allocate control cache.
638
639\return Cache pointer, or NULL if allocation fails.
640*/
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300641struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
642 const u32 size_in_bytes, u8 *p_dsp_control_buffer)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200643{
644 struct hpi_control_cache *p_cache =
645 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200646 if (!p_cache)
647 return NULL;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300648
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300649 p_cache->p_info =
650 kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200651 if (!p_cache->p_info) {
652 kfree(p_cache);
653 return NULL;
654 }
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300655
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200656 p_cache->cache_size_in_bytes = size_in_bytes;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300657 p_cache->control_count = control_count;
658 p_cache->p_cache = p_dsp_control_buffer;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200659 p_cache->init = 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200660 return p_cache;
661}
662
663void hpi_free_control_cache(struct hpi_control_cache *p_cache)
664{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300665 if (p_cache) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200666 kfree(p_cache->p_info);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200667 kfree(p_cache);
668 }
669}
670
671static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
672{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300673 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200674
675 switch (phm->function) {
676 case HPI_SUBSYS_OPEN:
677 case HPI_SUBSYS_CLOSE:
678 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200679 break;
680 case HPI_SUBSYS_DRIVER_LOAD:
681 wipe_adapter_list();
682 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200683 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300684 case HPI_SUBSYS_GET_ADAPTER:
685 subsys_get_adapter(phm, phr);
686 break;
687 case HPI_SUBSYS_GET_NUM_ADAPTERS:
688 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200689 break;
690 case HPI_SUBSYS_CREATE_ADAPTER:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200691 break;
692 default:
693 phr->error = HPI_ERROR_INVALID_FUNC;
694 break;
695 }
696}
697
698void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
699{
700 switch (phm->type) {
Eliot Blennerhassett82b57742011-07-22 15:52:36 +1200701 case HPI_TYPE_REQUEST:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200702 switch (phm->object) {
703 case HPI_OBJ_SUBSYSTEM:
704 subsys_message(phm, phr);
705 break;
706 }
707 break;
708
709 default:
710 phr->error = HPI_ERROR_INVALID_TYPE;
711 break;
712 }
713}