blob: 968510bc2552a122ed2a360eefd5ab39a27fdb1d [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/**
31* Given an HPI Message that was sent out and a response that was received,
32* validate that the response has the correct fields filled in,
33* i.e ObjectType, Function etc
34**/
35u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
36{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130037 if (phr->type != HPI_TYPE_RESPONSE) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130038 HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130039 return HPI_ERROR_INVALID_RESPONSE;
40 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020041
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130042 if (phr->object != phm->object) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130043 HPI_DEBUG_LOG(ERROR, "header object %d invalid\n",
44 phr->object);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130045 return HPI_ERROR_INVALID_RESPONSE;
46 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020047
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130048 if (phr->function != phm->function) {
Eliot Blennerhassett938c5652011-07-22 15:52:50 +120049 HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130050 phr->function);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130051 return HPI_ERROR_INVALID_RESPONSE;
52 }
53
54 return 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020055}
56
57u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
58{
59 u16 retval = 0;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130060 /*HPI_ASSERT(pao->type); */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020061
62 hpios_alistlock_lock(&adapters);
63
64 if (pao->index >= HPI_MAX_ADAPTERS) {
65 retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
66 goto unlock;
67 }
68
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130069 if (adapters.adapter[pao->index].type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130070 int a;
71 for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130072 if (!adapters.adapter[a].type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130073 HPI_DEBUG_LOG(WARNING,
74 "ASI%X duplicate index %d moved to %d\n",
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130075 pao->type, pao->index, a);
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130076 pao->index = a;
77 break;
78 }
79 }
80 if (a < 0) {
81 retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020082 goto unlock;
83 }
84 }
85 adapters.adapter[pao->index] = *pao;
86 hpios_dsplock_init(&adapters.adapter[pao->index]);
87 adapters.gw_num_adapters++;
88
89unlock:
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130090 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +020091 return retval;
92}
93
94void hpi_delete_adapter(struct hpi_adapter_obj *pao)
95{
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130096 if (!pao->type) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130097 HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
98 return;
99 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200100
101 hpios_alistlock_lock(&adapters);
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300102 if (adapters.adapter[pao->index].type)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300103 adapters.gw_num_adapters--;
104 memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
105 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200106}
107
108/**
109* FindAdapter returns a pointer to the struct hpi_adapter_obj with
110* index wAdapterIndex in an HPI_ADAPTERS_LIST structure.
111*
112*/
113struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
114{
115 struct hpi_adapter_obj *pao = NULL;
116
117 if (adapter_index >= HPI_MAX_ADAPTERS) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300118 HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n",
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200119 adapter_index);
120 return NULL;
121 }
122
123 pao = &adapters.adapter[adapter_index];
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300124 if (pao->type != 0) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200125 /*
126 HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
127 wAdapterIndex);
128 */
129 return pao;
130 } else {
131 /*
132 HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
133 wAdapterIndex);
134 */
135 return NULL;
136 }
137}
138
139/**
140*
141* wipe an HPI_ADAPTERS_LIST structure.
142*
143**/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300144static void wipe_adapter_list(void)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200145{
146 memset(&adapters, 0, sizeof(adapters));
147}
148
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300149static void subsys_get_adapter(struct hpi_message *phm,
150 struct hpi_response *phr)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200151{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300152 int count = phm->obj_index;
153 u16 index = 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200154
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300155 /* find the nCount'th nonzero adapter in array */
156 for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300157 if (adapters.adapter[index].type) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300158 if (!count)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300159 break;
160 count--;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200161 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200162 }
163
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300164 if (index < HPI_MAX_ADAPTERS) {
165 phr->u.s.adapter_index = adapters.adapter[index].index;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300166 phr->u.s.adapter_type = adapters.adapter[index].type;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300167 } else {
168 phr->u.s.adapter_index = 0;
Eliot Blennerhassett2f918a62011-02-10 17:26:09 +1300169 phr->u.s.adapter_type = 0;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300170 phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300171 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200172}
173
174static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
175{
176 unsigned int i;
177 int cached = 0;
178 if (!pC)
179 return 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200180
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300181 if (pC->init)
182 return pC->init;
183
184 if (!pC->p_cache)
185 return 0;
186
187 if (pC->control_count && pC->cache_size_in_bytes) {
188 char *p_master_cache;
189 unsigned int byte_count = 0;
190
191 p_master_cache = (char *)pC->p_cache;
192 HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200193 pC->control_count);
194 for (i = 0; i < pC->control_count; i++) {
195 struct hpi_control_cache_info *info =
196 (struct hpi_control_cache_info *)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300197 &p_master_cache[byte_count];
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300198 u16 control_index = info->control_index;
199
200 if (control_index >= pC->control_count) {
201 HPI_DEBUG_LOG(INFO,
202 "adap %d control index %d out of range, cache not ready?\n",
203 pC->adap_idx, control_index);
204 return 0;
205 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300206
207 if (!info->size_in32bit_words) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300208 if (!i) {
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300209 HPI_DEBUG_LOG(INFO,
210 "adap %d cache not ready?\n",
211 pC->adap_idx);
212 return 0;
213 }
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300214 /* The cache is invalid.
215 * Minimum valid entry size is
216 * sizeof(struct hpi_control_cache_info)
217 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300218 HPI_DEBUG_LOG(ERROR,
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300219 "adap %d zero size cache entry %d\n",
220 pC->adap_idx, i);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300221 break;
222 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200223
224 if (info->control_type) {
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300225 pC->p_info[control_index] = info;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200226 cached++;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200227 } else { /* dummy cache entry */
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300228 pC->p_info[control_index] = NULL;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200229 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200230
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300231 byte_count += info->size_in32bit_words * 4;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200232
233 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300234 "cached %d, pinfo %p index %d type %d size %d\n",
235 cached, pC->p_info[info->control_index],
236 info->control_index, info->control_type,
237 info->size_in32bit_words);
238
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300239 /* quit loop early if whole cache has been scanned.
240 * dwControlCount is the maximum possible entries
241 * but some may be absent from the cache
242 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300243 if (byte_count >= pC->cache_size_in_bytes)
244 break;
245 /* have seen last control index */
246 if (info->control_index == pC->control_count - 1)
247 break;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200248 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300249
250 if (byte_count != pC->cache_size_in_bytes)
251 HPI_DEBUG_LOG(WARNING,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300252 "adap %d bytecount %d != cache size %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300253 pC->adap_idx, byte_count,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300254 pC->cache_size_in_bytes);
255 else
256 HPI_DEBUG_LOG(DEBUG,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300257 "adap %d cache good, bytecount == cache size = %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300258 pC->adap_idx, byte_count);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300259
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300260 pC->init = (u16)cached;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200261 }
262 return pC->init;
263}
264
265/** Find a control.
266*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300267static short find_control(u16 control_index,
268 struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200269{
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200270 if (!control_cache_alloc_check(p_cache)) {
271 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300272 "control_cache_alloc_check() failed %d\n",
273 control_index);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200274 return 0;
275 }
276
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300277 *pI = p_cache->p_info[control_index];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200278 if (!*pI) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300279 HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
280 control_index);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200281 return 0;
282 } else {
283 HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
284 (*pI)->control_type);
285 }
286 return 1;
287}
288
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200289/* allow unified treatment of several string fields within struct */
290#define HPICMN_PAD_OFS_AND_SIZE(m) {\
291 offsetof(struct hpi_control_cache_pad, m), \
292 sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
293
294struct pad_ofs_size {
295 unsigned int offset;
296 unsigned int field_size;
297};
298
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200299static const struct pad_ofs_size pad_desc[] = {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200300 HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
301 HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
302 HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
303 HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
304};
305
306/** CheckControlCache checks the cache and fills the struct hpi_response
307 * accordingly. It returns one if a cache hit occurred, zero otherwise.
308 */
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300309short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200310 struct hpi_message *phm, struct hpi_response *phr)
311{
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200312 size_t response_size;
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300313 short found = 1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200314
Eliot Blennerhassettc6c2c9a2011-07-22 15:52:38 +1200315 /* set the default response size */
316 response_size =
317 sizeof(struct hpi_response_header) +
318 sizeof(struct hpi_control_res);
319
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300320 switch (pC->u.i.control_type) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200321
322 case HPI_CONTROL_METER:
323 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300324 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
325 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200326 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300327 if (pC->u.meter.an_logRMS[0] ==
328 HPI_CACHE_INVALID_SHORT) {
329 phr->error =
330 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
331 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
332 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
333 } else {
334 phr->u.c.an_log_value[0] =
335 pC->u.meter.an_logRMS[0];
336 phr->u.c.an_log_value[1] =
337 pC->u.meter.an_logRMS[1];
338 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200339 } else
340 found = 0;
341 break;
342 case HPI_CONTROL_VOLUME:
343 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300344 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
345 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300346 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
347 if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
348 if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
349 phr->u.c.param1 =
350 HPI_BITMASK_ALL_CHANNELS;
351 else
352 phr->u.c.param1 = 0;
353 } else {
354 phr->error =
355 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
356 phr->u.c.param1 = 0;
357 }
358 } else {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200359 found = 0;
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300360 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200361 break;
362 case HPI_CONTROL_MULTIPLEXER:
363 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300364 phr->u.c.param1 = pC->u.mux.source_node_type;
365 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200366 } else {
367 found = 0;
368 }
369 break;
370 case HPI_CONTROL_CHANNEL_MODE:
371 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300372 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200373 else
374 found = 0;
375 break;
376 case HPI_CONTROL_LEVEL:
377 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300378 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
379 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200380 } else
381 found = 0;
382 break;
383 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317fe2010-05-27 17:53:55 +1200384 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300385 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317fe2010-05-27 17:53:55 +1200386 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300387 phr->u.c.param1 = pC->u.tuner.band;
388 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
389 if (pC->u.tuner.s_level_avg ==
390 HPI_CACHE_INVALID_SHORT) {
391 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200392 phr->error =
393 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
394 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300395 phr->u.cu.tuner.s_level =
396 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317fe2010-05-27 17:53:55 +1200397 else
398 found = 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200399 break;
400 case HPI_CONTROL_AESEBU_RECEIVER:
401 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
402 phr->u.c.param1 = pC->u.aes3rx.error_status;
403 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300404 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200405 else
406 found = 0;
407 break;
408 case HPI_CONTROL_AESEBU_TRANSMITTER:
409 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
410 phr->u.c.param1 = pC->u.aes3tx.format;
411 else
412 found = 0;
413 break;
414 case HPI_CONTROL_TONEDETECTOR:
415 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
416 phr->u.c.param1 = pC->u.tone.state;
417 else
418 found = 0;
419 break;
420 case HPI_CONTROL_SILENCEDETECTOR:
421 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
422 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200423 } else
424 found = 0;
425 break;
426 case HPI_CONTROL_MICROPHONE:
427 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300428 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200429 else
430 found = 0;
431 break;
432 case HPI_CONTROL_SAMPLECLOCK:
433 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
434 phr->u.c.param1 = pC->u.clk.source;
435 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
436 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300437 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200438 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200439 phr->error =
440 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200441 } else
442 phr->u.c.param1 = pC->u.clk.source_index;
443 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
444 phr->u.c.param1 = pC->u.clk.sample_rate;
445 else
446 found = 0;
447 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300448 case HPI_CONTROL_PAD:{
449 struct hpi_control_cache_pad *p_pad;
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300450 p_pad = (struct hpi_control_cache_pad *)pC;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200451
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300452 if (!(p_pad->field_valid_flags & (1 <<
453 HPI_CTL_ATTR_INDEX(phm->u.c.
454 attribute)))) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200455 phr->error =
456 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
457 break;
458 }
459
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300460 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
461 phr->u.c.param1 = p_pad->pI;
462 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
463 phr->u.c.param1 = p_pad->pTY;
464 else {
465 unsigned int index =
466 HPI_CTL_ATTR_INDEX(phm->u.c.
467 attribute) - 1;
468 unsigned int offset = phm->u.c.param1;
469 unsigned int pad_string_len, field_size;
470 char *pad_string;
471 unsigned int tocopy;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200472
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300473 if (index > ARRAY_SIZE(pad_desc) - 1) {
474 phr->error =
475 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
476 break;
477 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200478
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300479 pad_string =
480 ((char *)p_pad) +
481 pad_desc[index].offset;
482 field_size = pad_desc[index].field_size;
483 /* Ensure null terminator */
484 pad_string[field_size - 1] = 0;
485
486 pad_string_len = strlen(pad_string) + 1;
487
488 if (offset > pad_string_len) {
489 phr->error =
490 HPI_ERROR_INVALID_CONTROL_VALUE;
491 break;
492 }
493
494 tocopy = pad_string_len - offset;
495 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
496 tocopy = sizeof(phr->u.cu.chars8.
497 sz_data);
498
499 memcpy(phr->u.cu.chars8.sz_data,
500 &pad_string[offset], tocopy);
501
502 phr->u.cu.chars8.remaining_chars =
503 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200504 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200505 }
506 break;
507 default:
508 found = 0;
509 break;
510 }
511
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300512 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
513 found ? "Cached" : "Uncached", phm->adapter_index,
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300514 pC->u.i.control_index, pC->u.i.control_type,
515 phm->u.c.attribute);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200516
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300517 if (found) {
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200518 phr->size = (u16)response_size;
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300519 phr->type = HPI_TYPE_RESPONSE;
520 phr->object = phm->object;
521 phr->function = phm->function;
522 }
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200523
524 return found;
525}
526
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300527short hpi_check_control_cache(struct hpi_control_cache *p_cache,
528 struct hpi_message *phm, struct hpi_response *phr)
529{
530 struct hpi_control_cache_info *pI;
531
532 if (!find_control(phm->obj_index, p_cache, &pI)) {
533 HPI_DEBUG_LOG(VERBOSE,
534 "HPICMN find_control() failed for adap %d\n",
535 phm->adapter_index);
536 return 0;
537 }
538
539 phr->error = 0;
540 phr->specific_error = 0;
541 phr->version = 0;
542
543 return hpi_check_control_cache_single((struct hpi_control_cache_single
544 *)pI, phm, phr);
545}
546
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200547/** Updates the cache with Set values.
548
549Only update if no error.
550Volume and Level return the limited values in the response, so use these
551Multiplexer does so use sent values
552*/
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300553void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
554 *pC, struct hpi_message *phm, struct hpi_response *phr)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200555{
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300556 switch (pC->u.i.control_type) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200557 case HPI_CONTROL_VOLUME:
558 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300559 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
560 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300561 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
562 if (phm->u.c.param1)
563 pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
564 else
565 pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200566 }
567 break;
568 case HPI_CONTROL_MULTIPLEXER:
569 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200570 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300571 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
572 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200573 }
574 break;
575 case HPI_CONTROL_CHANNEL_MODE:
576 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200577 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300578 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200579 break;
580 case HPI_CONTROL_LEVEL:
581 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300582 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
583 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200584 }
585 break;
586 case HPI_CONTROL_MICROPHONE:
587 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300588 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200589 break;
590 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200591 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
592 pC->u.aes3tx.format = phm->u.c.param1;
593 break;
594 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200595 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300596 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200597 break;
598 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200599 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
600 pC->u.clk.source = (u16)phm->u.c.param1;
601 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
602 pC->u.clk.source_index = (u16)phm->u.c.param1;
603 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
604 pC->u.clk.sample_rate = phm->u.c.param1;
605 break;
606 default:
607 break;
608 }
609}
610
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300611void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
612 struct hpi_message *phm, struct hpi_response *phr)
613{
614 struct hpi_control_cache_single *pC;
615 struct hpi_control_cache_info *pI;
616
617 if (phr->error)
618 return;
619
620 if (!find_control(phm->obj_index, p_cache, &pI)) {
621 HPI_DEBUG_LOG(VERBOSE,
622 "HPICMN find_control() failed for adap %d\n",
623 phm->adapter_index);
624 return;
625 }
626
627 /* pC is the default cached control strucure.
628 May be cast to something else in the following switch statement.
629 */
630 pC = (struct hpi_control_cache_single *)pI;
631
632 hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr);
633}
634
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200635/** Allocate control cache.
636
637\return Cache pointer, or NULL if allocation fails.
638*/
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300639struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
640 const u32 size_in_bytes, u8 *p_dsp_control_buffer)
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200641{
642 struct hpi_control_cache *p_cache =
643 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200644 if (!p_cache)
645 return NULL;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300646
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300647 p_cache->p_info =
648 kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200649 if (!p_cache->p_info) {
650 kfree(p_cache);
651 return NULL;
652 }
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300653
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200654 p_cache->cache_size_in_bytes = size_in_bytes;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300655 p_cache->control_count = control_count;
656 p_cache->p_cache = p_dsp_control_buffer;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200657 p_cache->init = 0;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200658 return p_cache;
659}
660
661void hpi_free_control_cache(struct hpi_control_cache *p_cache)
662{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300663 if (p_cache) {
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200664 kfree(p_cache->p_info);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200665 kfree(p_cache);
666 }
667}
668
669static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
670{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300671 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200672
673 switch (phm->function) {
674 case HPI_SUBSYS_OPEN:
675 case HPI_SUBSYS_CLOSE:
676 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200677 break;
678 case HPI_SUBSYS_DRIVER_LOAD:
679 wipe_adapter_list();
680 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200681 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300682 case HPI_SUBSYS_GET_ADAPTER:
683 subsys_get_adapter(phm, phr);
684 break;
685 case HPI_SUBSYS_GET_NUM_ADAPTERS:
686 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200687 break;
688 case HPI_SUBSYS_CREATE_ADAPTER:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200689 break;
690 default:
691 phr->error = HPI_ERROR_INVALID_FUNC;
692 break;
693 }
694}
695
696void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
697{
698 switch (phm->type) {
Eliot Blennerhassett82b57742011-07-22 15:52:36 +1200699 case HPI_TYPE_REQUEST:
Eliot Blennerhassett719f82d32010-04-21 18:17:39 +0200700 switch (phm->object) {
701 case HPI_OBJ_SUBSYSTEM:
702 subsys_message(phm, phr);
703 break;
704 }
705 break;
706
707 default:
708 phr->error = HPI_ERROR_INVALID_TYPE;
709 break;
710 }
711}