blob: c7751243dc42adc69aed02701144b36aac2ff156 [file] [log] [blame]
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001/******************************************************************************
2
3 AudioScience HPI driver
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +13004 Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of version 2 of the GNU General Public License as
8 published by the Free Software Foundation;
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19\file hpicmn.c
20
21 Common functions used by hpixxxx.c modules
22
23(C) Copyright AudioScience Inc. 1998-2003
24*******************************************************************************/
25#define SOURCEFILE_NAME "hpicmn.c"
26
27#include "hpi_internal.h"
28#include "hpidebug.h"
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130029#include "hpimsginit.h"
30
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020031#include "hpicmn.h"
32
33struct hpi_adapters_list {
34 struct hpios_spinlock list_lock;
35 struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS];
36 u16 gw_num_adapters;
37};
38
39static struct hpi_adapters_list adapters;
40
41/**
42* Given an HPI Message that was sent out and a response that was received,
43* validate that the response has the correct fields filled in,
44* i.e ObjectType, Function etc
45**/
46u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
47{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130048 if (phr->type != HPI_TYPE_RESPONSE) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130049 HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130050 return HPI_ERROR_INVALID_RESPONSE;
51 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020052
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130053 if (phr->object != phm->object) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130054 HPI_DEBUG_LOG(ERROR, "header object %d invalid\n",
55 phr->object);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130056 return HPI_ERROR_INVALID_RESPONSE;
57 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020058
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130059 if (phr->function != phm->function) {
Eliot Blennerhassett938c5652011-07-22 15:52:50 +120060 HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +130061 phr->function);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130062 return HPI_ERROR_INVALID_RESPONSE;
63 }
64
65 return 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020066}
67
68u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
69{
70 u16 retval = 0;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130071 /*HPI_ASSERT(pao->type); */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020072
73 hpios_alistlock_lock(&adapters);
74
75 if (pao->index >= HPI_MAX_ADAPTERS) {
76 retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
77 goto unlock;
78 }
79
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130080 if (adapters.adapter[pao->index].type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130081 int a;
82 for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130083 if (!adapters.adapter[a].type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130084 HPI_DEBUG_LOG(WARNING,
85 "ASI%X duplicate index %d moved to %d\n",
Eliot Blennerhassett7036b922011-12-22 13:38:43 +130086 pao->type, pao->index, a);
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130087 pao->index = a;
88 break;
89 }
90 }
91 if (a < 0) {
92 retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020093 goto unlock;
94 }
95 }
96 adapters.adapter[pao->index] = *pao;
97 hpios_dsplock_init(&adapters.adapter[pao->index]);
98 adapters.gw_num_adapters++;
99
100unlock:
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300101 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200102 return retval;
103}
104
105void hpi_delete_adapter(struct hpi_adapter_obj *pao)
106{
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300107 if (!pao->type) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300108 HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
109 return;
110 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200111
112 hpios_alistlock_lock(&adapters);
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300113 if (adapters.adapter[pao->index].type)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300114 adapters.gw_num_adapters--;
115 memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
116 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200117}
118
119/**
120* FindAdapter returns a pointer to the struct hpi_adapter_obj with
121* index wAdapterIndex in an HPI_ADAPTERS_LIST structure.
122*
123*/
124struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
125{
126 struct hpi_adapter_obj *pao = NULL;
127
128 if (adapter_index >= HPI_MAX_ADAPTERS) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300129 HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200130 adapter_index);
131 return NULL;
132 }
133
134 pao = &adapters.adapter[adapter_index];
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300135 if (pao->type != 0) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200136 /*
137 HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
138 wAdapterIndex);
139 */
140 return pao;
141 } else {
142 /*
143 HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
144 wAdapterIndex);
145 */
146 return NULL;
147 }
148}
149
150/**
151*
152* wipe an HPI_ADAPTERS_LIST structure.
153*
154**/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300155static void wipe_adapter_list(void)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200156{
157 memset(&adapters, 0, sizeof(adapters));
158}
159
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300160static void subsys_get_adapter(struct hpi_message *phm,
161 struct hpi_response *phr)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200162{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300163 int count = phm->obj_index;
164 u16 index = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200165
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300166 /* find the nCount'th nonzero adapter in array */
167 for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300168 if (adapters.adapter[index].type) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300169 if (!count)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300170 break;
171 count--;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200172 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200173 }
174
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300175 if (index < HPI_MAX_ADAPTERS) {
176 phr->u.s.adapter_index = adapters.adapter[index].index;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300177 phr->u.s.adapter_type = adapters.adapter[index].type;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300178 } else {
179 phr->u.s.adapter_index = 0;
Eliot Blennerhassett2f918a62011-02-10 17:26:09 +1300180 phr->u.s.adapter_type = 0;
Eliot Blennerhassett7036b922011-12-22 13:38:43 +1300181 phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300182 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200183}
184
185static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
186{
187 unsigned int i;
188 int cached = 0;
189 if (!pC)
190 return 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200191
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300192 if (pC->init)
193 return pC->init;
194
195 if (!pC->p_cache)
196 return 0;
197
198 if (pC->control_count && pC->cache_size_in_bytes) {
199 char *p_master_cache;
200 unsigned int byte_count = 0;
201
202 p_master_cache = (char *)pC->p_cache;
203 HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200204 pC->control_count);
205 for (i = 0; i < pC->control_count; i++) {
206 struct hpi_control_cache_info *info =
207 (struct hpi_control_cache_info *)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300208 &p_master_cache[byte_count];
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300209 u16 control_index = info->control_index;
210
211 if (control_index >= pC->control_count) {
212 HPI_DEBUG_LOG(INFO,
213 "adap %d control index %d out of range, cache not ready?\n",
214 pC->adap_idx, control_index);
215 return 0;
216 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300217
218 if (!info->size_in32bit_words) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300219 if (!i) {
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300220 HPI_DEBUG_LOG(INFO,
221 "adap %d cache not ready?\n",
222 pC->adap_idx);
223 return 0;
224 }
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300225 /* The cache is invalid.
226 * Minimum valid entry size is
227 * sizeof(struct hpi_control_cache_info)
228 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300229 HPI_DEBUG_LOG(ERROR,
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300230 "adap %d zero size cache entry %d\n",
231 pC->adap_idx, i);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300232 break;
233 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200234
235 if (info->control_type) {
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300236 pC->p_info[control_index] = info;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200237 cached++;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200238 } else { /* dummy cache entry */
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300239 pC->p_info[control_index] = NULL;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200240 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200241
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300242 byte_count += info->size_in32bit_words * 4;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200243
244 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300245 "cached %d, pinfo %p index %d type %d size %d\n",
246 cached, pC->p_info[info->control_index],
247 info->control_index, info->control_type,
248 info->size_in32bit_words);
249
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300250 /* quit loop early if whole cache has been scanned.
251 * dwControlCount is the maximum possible entries
252 * but some may be absent from the cache
253 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300254 if (byte_count >= pC->cache_size_in_bytes)
255 break;
256 /* have seen last control index */
257 if (info->control_index == pC->control_count - 1)
258 break;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200259 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300260
261 if (byte_count != pC->cache_size_in_bytes)
262 HPI_DEBUG_LOG(WARNING,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300263 "adap %d bytecount %d != cache size %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300264 pC->adap_idx, byte_count,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300265 pC->cache_size_in_bytes);
266 else
267 HPI_DEBUG_LOG(DEBUG,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300268 "adap %d cache good, bytecount == cache size = %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300269 pC->adap_idx, byte_count);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300270
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300271 pC->init = (u16)cached;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200272 }
273 return pC->init;
274}
275
276/** Find a control.
277*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300278static short find_control(u16 control_index,
279 struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200280{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200281 if (!control_cache_alloc_check(p_cache)) {
282 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300283 "control_cache_alloc_check() failed %d\n",
284 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200285 return 0;
286 }
287
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300288 *pI = p_cache->p_info[control_index];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200289 if (!*pI) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300290 HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
291 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200292 return 0;
293 } else {
294 HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
295 (*pI)->control_type);
296 }
297 return 1;
298}
299
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200300/* allow unified treatment of several string fields within struct */
301#define HPICMN_PAD_OFS_AND_SIZE(m) {\
302 offsetof(struct hpi_control_cache_pad, m), \
303 sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
304
305struct pad_ofs_size {
306 unsigned int offset;
307 unsigned int field_size;
308};
309
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200310static const struct pad_ofs_size pad_desc[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200311 HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
312 HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
313 HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
314 HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
315};
316
317/** CheckControlCache checks the cache and fills the struct hpi_response
318 * accordingly. It returns one if a cache hit occurred, zero otherwise.
319 */
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300320short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200321 struct hpi_message *phm, struct hpi_response *phr)
322{
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200323 size_t response_size;
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300324 short found = 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200325
Eliot Blennerhassettc6c2c9a2011-07-22 15:52:38 +1200326 /* set the default response size */
327 response_size =
328 sizeof(struct hpi_response_header) +
329 sizeof(struct hpi_control_res);
330
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300331 switch (pC->u.i.control_type) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200332
333 case HPI_CONTROL_METER:
334 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300335 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
336 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200337 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300338 if (pC->u.meter.an_logRMS[0] ==
339 HPI_CACHE_INVALID_SHORT) {
340 phr->error =
341 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
342 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
343 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
344 } else {
345 phr->u.c.an_log_value[0] =
346 pC->u.meter.an_logRMS[0];
347 phr->u.c.an_log_value[1] =
348 pC->u.meter.an_logRMS[1];
349 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200350 } else
351 found = 0;
352 break;
353 case HPI_CONTROL_VOLUME:
354 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300355 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
356 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300357 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
358 if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
359 if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
360 phr->u.c.param1 =
361 HPI_BITMASK_ALL_CHANNELS;
362 else
363 phr->u.c.param1 = 0;
364 } else {
365 phr->error =
366 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
367 phr->u.c.param1 = 0;
368 }
369 } else {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200370 found = 0;
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300371 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200372 break;
373 case HPI_CONTROL_MULTIPLEXER:
374 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300375 phr->u.c.param1 = pC->u.mux.source_node_type;
376 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200377 } else {
378 found = 0;
379 }
380 break;
381 case HPI_CONTROL_CHANNEL_MODE:
382 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300383 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200384 else
385 found = 0;
386 break;
387 case HPI_CONTROL_LEVEL:
388 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300389 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
390 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200391 } else
392 found = 0;
393 break;
394 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200395 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300396 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200397 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300398 phr->u.c.param1 = pC->u.tuner.band;
399 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
400 if (pC->u.tuner.s_level_avg ==
401 HPI_CACHE_INVALID_SHORT) {
402 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200403 phr->error =
404 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
405 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300406 phr->u.cu.tuner.s_level =
407 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200408 else
409 found = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200410 break;
411 case HPI_CONTROL_AESEBU_RECEIVER:
412 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
413 phr->u.c.param1 = pC->u.aes3rx.error_status;
414 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300415 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200416 else
417 found = 0;
418 break;
419 case HPI_CONTROL_AESEBU_TRANSMITTER:
420 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
421 phr->u.c.param1 = pC->u.aes3tx.format;
422 else
423 found = 0;
424 break;
425 case HPI_CONTROL_TONEDETECTOR:
426 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
427 phr->u.c.param1 = pC->u.tone.state;
428 else
429 found = 0;
430 break;
431 case HPI_CONTROL_SILENCEDETECTOR:
432 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
433 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200434 } else
435 found = 0;
436 break;
437 case HPI_CONTROL_MICROPHONE:
438 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300439 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200440 else
441 found = 0;
442 break;
443 case HPI_CONTROL_SAMPLECLOCK:
444 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
445 phr->u.c.param1 = pC->u.clk.source;
446 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
447 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300448 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200449 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200450 phr->error =
451 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200452 } else
453 phr->u.c.param1 = pC->u.clk.source_index;
454 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
455 phr->u.c.param1 = pC->u.clk.sample_rate;
456 else
457 found = 0;
458 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300459 case HPI_CONTROL_PAD:{
460 struct hpi_control_cache_pad *p_pad;
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300461 p_pad = (struct hpi_control_cache_pad *)pC;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200462
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300463 if (!(p_pad->field_valid_flags & (1 <<
464 HPI_CTL_ATTR_INDEX(phm->u.c.
465 attribute)))) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200466 phr->error =
467 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
468 break;
469 }
470
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300471 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
472 phr->u.c.param1 = p_pad->pI;
473 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
474 phr->u.c.param1 = p_pad->pTY;
475 else {
476 unsigned int index =
477 HPI_CTL_ATTR_INDEX(phm->u.c.
478 attribute) - 1;
479 unsigned int offset = phm->u.c.param1;
480 unsigned int pad_string_len, field_size;
481 char *pad_string;
482 unsigned int tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200483
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300484 if (index > ARRAY_SIZE(pad_desc) - 1) {
485 phr->error =
486 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
487 break;
488 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200489
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300490 pad_string =
491 ((char *)p_pad) +
492 pad_desc[index].offset;
493 field_size = pad_desc[index].field_size;
494 /* Ensure null terminator */
495 pad_string[field_size - 1] = 0;
496
497 pad_string_len = strlen(pad_string) + 1;
498
499 if (offset > pad_string_len) {
500 phr->error =
501 HPI_ERROR_INVALID_CONTROL_VALUE;
502 break;
503 }
504
505 tocopy = pad_string_len - offset;
506 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
507 tocopy = sizeof(phr->u.cu.chars8.
508 sz_data);
509
510 memcpy(phr->u.cu.chars8.sz_data,
511 &pad_string[offset], tocopy);
512
513 phr->u.cu.chars8.remaining_chars =
514 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200515 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200516 }
517 break;
518 default:
519 found = 0;
520 break;
521 }
522
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300523 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
524 found ? "Cached" : "Uncached", phm->adapter_index,
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300525 pC->u.i.control_index, pC->u.i.control_type,
526 phm->u.c.attribute);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200527
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300528 if (found) {
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200529 phr->size = (u16)response_size;
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300530 phr->type = HPI_TYPE_RESPONSE;
531 phr->object = phm->object;
532 phr->function = phm->function;
533 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200534
535 return found;
536}
537
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300538short hpi_check_control_cache(struct hpi_control_cache *p_cache,
539 struct hpi_message *phm, struct hpi_response *phr)
540{
541 struct hpi_control_cache_info *pI;
542
543 if (!find_control(phm->obj_index, p_cache, &pI)) {
544 HPI_DEBUG_LOG(VERBOSE,
545 "HPICMN find_control() failed for adap %d\n",
546 phm->adapter_index);
547 return 0;
548 }
549
550 phr->error = 0;
551 phr->specific_error = 0;
552 phr->version = 0;
553
554 return hpi_check_control_cache_single((struct hpi_control_cache_single
555 *)pI, phm, phr);
556}
557
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200558/** Updates the cache with Set values.
559
560Only update if no error.
561Volume and Level return the limited values in the response, so use these
562Multiplexer does so use sent values
563*/
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300564void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
565 *pC, struct hpi_message *phm, struct hpi_response *phr)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200566{
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300567 switch (pC->u.i.control_type) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200568 case HPI_CONTROL_VOLUME:
569 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300570 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
571 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300572 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
573 if (phm->u.c.param1)
574 pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
575 else
576 pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200577 }
578 break;
579 case HPI_CONTROL_MULTIPLEXER:
580 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200581 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300582 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
583 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200584 }
585 break;
586 case HPI_CONTROL_CHANNEL_MODE:
587 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200588 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300589 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200590 break;
591 case HPI_CONTROL_LEVEL:
592 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300593 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
594 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200595 }
596 break;
597 case HPI_CONTROL_MICROPHONE:
598 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300599 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200600 break;
601 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200602 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
603 pC->u.aes3tx.format = phm->u.c.param1;
604 break;
605 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200606 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300607 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200608 break;
609 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200610 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
611 pC->u.clk.source = (u16)phm->u.c.param1;
612 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
613 pC->u.clk.source_index = (u16)phm->u.c.param1;
614 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
615 pC->u.clk.sample_rate = phm->u.c.param1;
616 break;
617 default:
618 break;
619 }
620}
621
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300622void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
623 struct hpi_message *phm, struct hpi_response *phr)
624{
625 struct hpi_control_cache_single *pC;
626 struct hpi_control_cache_info *pI;
627
628 if (phr->error)
629 return;
630
631 if (!find_control(phm->obj_index, p_cache, &pI)) {
632 HPI_DEBUG_LOG(VERBOSE,
633 "HPICMN find_control() failed for adap %d\n",
634 phm->adapter_index);
635 return;
636 }
637
638 /* pC is the default cached control strucure.
639 May be cast to something else in the following switch statement.
640 */
641 pC = (struct hpi_control_cache_single *)pI;
642
643 hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr);
644}
645
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200646/** Allocate control cache.
647
648\return Cache pointer, or NULL if allocation fails.
649*/
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300650struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
651 const u32 size_in_bytes, u8 *p_dsp_control_buffer)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200652{
653 struct hpi_control_cache *p_cache =
654 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200655 if (!p_cache)
656 return NULL;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300657
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300658 p_cache->p_info =
659 kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200660 if (!p_cache->p_info) {
661 kfree(p_cache);
662 return NULL;
663 }
Eliot Blennerhassettc1464a82014-11-20 16:22:52 +1300664
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200665 p_cache->cache_size_in_bytes = size_in_bytes;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300666 p_cache->control_count = control_count;
667 p_cache->p_cache = p_dsp_control_buffer;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200668 p_cache->init = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200669 return p_cache;
670}
671
672void hpi_free_control_cache(struct hpi_control_cache *p_cache)
673{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300674 if (p_cache) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200675 kfree(p_cache->p_info);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200676 kfree(p_cache);
677 }
678}
679
680static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
681{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300682 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200683
684 switch (phm->function) {
685 case HPI_SUBSYS_OPEN:
686 case HPI_SUBSYS_CLOSE:
687 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200688 break;
689 case HPI_SUBSYS_DRIVER_LOAD:
690 wipe_adapter_list();
691 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200692 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300693 case HPI_SUBSYS_GET_ADAPTER:
694 subsys_get_adapter(phm, phr);
695 break;
696 case HPI_SUBSYS_GET_NUM_ADAPTERS:
697 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200698 break;
699 case HPI_SUBSYS_CREATE_ADAPTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200700 break;
701 default:
702 phr->error = HPI_ERROR_INVALID_FUNC;
703 break;
704 }
705}
706
707void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
708{
709 switch (phm->type) {
Eliot Blennerhassett82b57742011-07-22 15:52:36 +1200710 case HPI_TYPE_REQUEST:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200711 switch (phm->object) {
712 case HPI_OBJ_SUBSYSTEM:
713 subsys_message(phm, phr);
714 break;
715 }
716 break;
717
718 default:
719 phr->error = HPI_ERROR_INVALID_TYPE;
720 break;
721 }
722}