blob: 801dcd89c86ed7752346c7e7cdc8d3ef35f18707 [file] [log] [blame]
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001/******************************************************************************
2
3 AudioScience HPI driver
4 Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com>
5
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 Blennerhassett1528fbb2011-02-10 17:26:02 +130060 HPI_DEBUG_LOG(ERROR, "header type %d invalid\n",
61 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;
71 /*HPI_ASSERT(pao->wAdapterType); */
72
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
80 if (adapters.adapter[pao->index].adapter_type) {
Eliot Blennerhassettd6f1c1c2011-02-10 17:26:12 +130081 int a;
82 for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
83 if (!adapters.adapter[a].adapter_type) {
84 HPI_DEBUG_LOG(WARNING,
85 "ASI%X duplicate index %d moved to %d\n",
86 pao->adapter_type, pao->index, a);
87 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 Blennerhassett3285ea12011-02-10 17:25:58 +1300107 if (!pao->adapter_type) {
108 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 Blennerhassett3285ea12011-02-10 17:25:58 +1300113 if (adapters.adapter[pao->index].adapter_type)
114 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];
135 if (pao->adapter_type != 0) {
136 /*
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++) {
168 if (adapters.adapter[index].adapter_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 Blennerhassett2f918a62011-02-10 17:26:09 +1300177 phr->u.s.adapter_type = adapters.adapter[index].adapter_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 Blennerhassett3285ea12011-02-10 17:25:58 +1300181 phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
182 }
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];
209
210 if (!info->size_in32bit_words) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300211 if (!i) {
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300212 HPI_DEBUG_LOG(INFO,
213 "adap %d cache not ready?\n",
214 pC->adap_idx);
215 return 0;
216 }
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300217 /* The cache is invalid.
218 * Minimum valid entry size is
219 * sizeof(struct hpi_control_cache_info)
220 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300221 HPI_DEBUG_LOG(ERROR,
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300222 "adap %d zero size cache entry %d\n",
223 pC->adap_idx, i);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300224 break;
225 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200226
227 if (info->control_type) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300228 pC->p_info[info->control_index] = info;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200229 cached++;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200230 } else { /* dummy cache entry */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300231 pC->p_info[info->control_index] = NULL;
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200232 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200233
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300234 byte_count += info->size_in32bit_words * 4;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200235
236 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300237 "cached %d, pinfo %p index %d type %d size %d\n",
238 cached, pC->p_info[info->control_index],
239 info->control_index, info->control_type,
240 info->size_in32bit_words);
241
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300242 /* quit loop early if whole cache has been scanned.
243 * dwControlCount is the maximum possible entries
244 * but some may be absent from the cache
245 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300246 if (byte_count >= pC->cache_size_in_bytes)
247 break;
248 /* have seen last control index */
249 if (info->control_index == pC->control_count - 1)
250 break;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200251 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300252
253 if (byte_count != pC->cache_size_in_bytes)
254 HPI_DEBUG_LOG(WARNING,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300255 "adap %d bytecount %d != cache size %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300256 pC->adap_idx, byte_count,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300257 pC->cache_size_in_bytes);
258 else
259 HPI_DEBUG_LOG(DEBUG,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300260 "adap %d cache good, bytecount == cache size = %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300261 pC->adap_idx, byte_count);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300262
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300263 pC->init = (u16)cached;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200264 }
265 return pC->init;
266}
267
268/** Find a control.
269*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300270static short find_control(u16 control_index,
271 struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200272{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200273 if (!control_cache_alloc_check(p_cache)) {
274 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300275 "control_cache_alloc_check() failed %d\n",
276 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200277 return 0;
278 }
279
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300280 *pI = p_cache->p_info[control_index];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200281 if (!*pI) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300282 HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
283 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200284 return 0;
285 } else {
286 HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
287 (*pI)->control_type);
288 }
289 return 1;
290}
291
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200292/* allow unified treatment of several string fields within struct */
293#define HPICMN_PAD_OFS_AND_SIZE(m) {\
294 offsetof(struct hpi_control_cache_pad, m), \
295 sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
296
297struct pad_ofs_size {
298 unsigned int offset;
299 unsigned int field_size;
300};
301
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200302static const struct pad_ofs_size pad_desc[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200303 HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
304 HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
305 HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
306 HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
307};
308
309/** CheckControlCache checks the cache and fills the struct hpi_response
310 * accordingly. It returns one if a cache hit occurred, zero otherwise.
311 */
312short hpi_check_control_cache(struct hpi_control_cache *p_cache,
313 struct hpi_message *phm, struct hpi_response *phr)
314{
315 short found = 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200316 struct hpi_control_cache_info *pI;
317 struct hpi_control_cache_single *pC;
318 struct hpi_control_cache_pad *p_pad;
319
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300320 if (!find_control(phm->obj_index, p_cache, &pI)) {
321 HPI_DEBUG_LOG(VERBOSE,
322 "HPICMN find_control() failed for adap %d\n",
323 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200324 return 0;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300325 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200326
327 phr->error = 0;
328
329 /* pC is the default cached control strucure. May be cast to
330 something else in the following switch statement.
331 */
332 pC = (struct hpi_control_cache_single *)pI;
333 p_pad = (struct hpi_control_cache_pad *)pI;
334
335 switch (pI->control_type) {
336
337 case HPI_CONTROL_METER:
338 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300339 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
340 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200341 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300342 if (pC->u.meter.an_logRMS[0] ==
343 HPI_CACHE_INVALID_SHORT) {
344 phr->error =
345 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
346 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
347 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
348 } else {
349 phr->u.c.an_log_value[0] =
350 pC->u.meter.an_logRMS[0];
351 phr->u.c.an_log_value[1] =
352 pC->u.meter.an_logRMS[1];
353 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200354 } else
355 found = 0;
356 break;
357 case HPI_CONTROL_VOLUME:
358 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300359 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
360 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300361 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
362 if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
363 if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
364 phr->u.c.param1 =
365 HPI_BITMASK_ALL_CHANNELS;
366 else
367 phr->u.c.param1 = 0;
368 } else {
369 phr->error =
370 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
371 phr->u.c.param1 = 0;
372 }
373 } else {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200374 found = 0;
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300375 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200376 break;
377 case HPI_CONTROL_MULTIPLEXER:
378 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300379 phr->u.c.param1 = pC->u.mux.source_node_type;
380 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200381 } else {
382 found = 0;
383 }
384 break;
385 case HPI_CONTROL_CHANNEL_MODE:
386 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300387 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200388 else
389 found = 0;
390 break;
391 case HPI_CONTROL_LEVEL:
392 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300393 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
394 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200395 } else
396 found = 0;
397 break;
398 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200399 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300400 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200401 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300402 phr->u.c.param1 = pC->u.tuner.band;
403 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
404 if (pC->u.tuner.s_level_avg ==
405 HPI_CACHE_INVALID_SHORT) {
406 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200407 phr->error =
408 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
409 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300410 phr->u.cu.tuner.s_level =
411 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200412 else
413 found = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200414 break;
415 case HPI_CONTROL_AESEBU_RECEIVER:
416 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
417 phr->u.c.param1 = pC->u.aes3rx.error_status;
418 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300419 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200420 else
421 found = 0;
422 break;
423 case HPI_CONTROL_AESEBU_TRANSMITTER:
424 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
425 phr->u.c.param1 = pC->u.aes3tx.format;
426 else
427 found = 0;
428 break;
429 case HPI_CONTROL_TONEDETECTOR:
430 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
431 phr->u.c.param1 = pC->u.tone.state;
432 else
433 found = 0;
434 break;
435 case HPI_CONTROL_SILENCEDETECTOR:
436 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
437 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200438 } else
439 found = 0;
440 break;
441 case HPI_CONTROL_MICROPHONE:
442 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300443 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200444 else
445 found = 0;
446 break;
447 case HPI_CONTROL_SAMPLECLOCK:
448 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
449 phr->u.c.param1 = pC->u.clk.source;
450 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
451 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300452 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200453 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200454 phr->error =
455 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200456 } else
457 phr->u.c.param1 = pC->u.clk.source_index;
458 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
459 phr->u.c.param1 = pC->u.clk.sample_rate;
460 else
461 found = 0;
462 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300463 case HPI_CONTROL_PAD:{
464 struct hpi_control_cache_pad *p_pad;
465 p_pad = (struct hpi_control_cache_pad *)pI;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200466
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300467 if (!(p_pad->field_valid_flags & (1 <<
468 HPI_CTL_ATTR_INDEX(phm->u.c.
469 attribute)))) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200470 phr->error =
471 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
472 break;
473 }
474
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300475 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
476 phr->u.c.param1 = p_pad->pI;
477 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
478 phr->u.c.param1 = p_pad->pTY;
479 else {
480 unsigned int index =
481 HPI_CTL_ATTR_INDEX(phm->u.c.
482 attribute) - 1;
483 unsigned int offset = phm->u.c.param1;
484 unsigned int pad_string_len, field_size;
485 char *pad_string;
486 unsigned int tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200487
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300488 if (index > ARRAY_SIZE(pad_desc) - 1) {
489 phr->error =
490 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
491 break;
492 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200493
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300494 pad_string =
495 ((char *)p_pad) +
496 pad_desc[index].offset;
497 field_size = pad_desc[index].field_size;
498 /* Ensure null terminator */
499 pad_string[field_size - 1] = 0;
500
501 pad_string_len = strlen(pad_string) + 1;
502
503 if (offset > pad_string_len) {
504 phr->error =
505 HPI_ERROR_INVALID_CONTROL_VALUE;
506 break;
507 }
508
509 tocopy = pad_string_len - offset;
510 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
511 tocopy = sizeof(phr->u.cu.chars8.
512 sz_data);
513
514 memcpy(phr->u.cu.chars8.sz_data,
515 &pad_string[offset], tocopy);
516
517 phr->u.cu.chars8.remaining_chars =
518 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200519 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200520 }
521 break;
522 default:
523 found = 0;
524 break;
525 }
526
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300527 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
528 found ? "Cached" : "Uncached", phm->adapter_index,
529 pI->control_index, pI->control_type, phm->u.c.attribute);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200530
531 if (found)
532 phr->size =
533 sizeof(struct hpi_response_header) +
534 sizeof(struct hpi_control_res);
535
536 return found;
537}
538
539/** Updates the cache with Set values.
540
541Only update if no error.
542Volume and Level return the limited values in the response, so use these
543Multiplexer does so use sent values
544*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300545void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200546 struct hpi_message *phm, struct hpi_response *phr)
547{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200548 struct hpi_control_cache_single *pC;
549 struct hpi_control_cache_info *pI;
550
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200551 if (phr->error)
552 return;
553
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300554 if (!find_control(phm->obj_index, p_cache, &pI)) {
555 HPI_DEBUG_LOG(VERBOSE,
556 "HPICMN find_control() failed for adap %d\n",
557 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200558 return;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300559 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200560
561 /* pC is the default cached control strucure.
562 May be cast to something else in the following switch statement.
563 */
564 pC = (struct hpi_control_cache_single *)pI;
565
566 switch (pI->control_type) {
567 case HPI_CONTROL_VOLUME:
568 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300569 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
570 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300571 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
572 if (phm->u.c.param1)
573 pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
574 else
575 pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200576 }
577 break;
578 case HPI_CONTROL_MULTIPLEXER:
579 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200580 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300581 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
582 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200583 }
584 break;
585 case HPI_CONTROL_CHANNEL_MODE:
586 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200587 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300588 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200589 break;
590 case HPI_CONTROL_LEVEL:
591 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300592 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
593 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200594 }
595 break;
596 case HPI_CONTROL_MICROPHONE:
597 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300598 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200599 break;
600 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200601 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
602 pC->u.aes3tx.format = phm->u.c.param1;
603 break;
604 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200605 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300606 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200607 break;
608 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200609 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
610 pC->u.clk.source = (u16)phm->u.c.param1;
611 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
612 pC->u.clk.source_index = (u16)phm->u.c.param1;
613 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
614 pC->u.clk.sample_rate = phm->u.c.param1;
615 break;
616 default:
617 break;
618 }
619}
620
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200621/** Allocate control cache.
622
623\return Cache pointer, or NULL if allocation fails.
624*/
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300625struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
626 const u32 size_in_bytes, u8 *p_dsp_control_buffer)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200627{
628 struct hpi_control_cache *p_cache =
629 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200630 if (!p_cache)
631 return NULL;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300632
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200633 p_cache->p_info =
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300634 kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200635 if (!p_cache->p_info) {
636 kfree(p_cache);
637 return NULL;
638 }
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300639 memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200640 p_cache->cache_size_in_bytes = size_in_bytes;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300641 p_cache->control_count = control_count;
642 p_cache->p_cache = p_dsp_control_buffer;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200643 p_cache->init = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200644 return p_cache;
645}
646
647void hpi_free_control_cache(struct hpi_control_cache *p_cache)
648{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300649 if (p_cache) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200650 kfree(p_cache->p_info);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200651 kfree(p_cache);
652 }
653}
654
655static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
656{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300657 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200658
659 switch (phm->function) {
660 case HPI_SUBSYS_OPEN:
661 case HPI_SUBSYS_CLOSE:
662 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200663 break;
664 case HPI_SUBSYS_DRIVER_LOAD:
665 wipe_adapter_list();
666 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200667 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300668 case HPI_SUBSYS_GET_ADAPTER:
669 subsys_get_adapter(phm, phr);
670 break;
671 case HPI_SUBSYS_GET_NUM_ADAPTERS:
672 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200673 break;
674 case HPI_SUBSYS_CREATE_ADAPTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200675 break;
676 default:
677 phr->error = HPI_ERROR_INVALID_FUNC;
678 break;
679 }
680}
681
682void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
683{
684 switch (phm->type) {
Eliot Blennerhassett82b57742011-07-22 15:52:36 +1200685 case HPI_TYPE_REQUEST:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200686 switch (phm->object) {
687 case HPI_OBJ_SUBSYSTEM:
688 subsys_message(phm, phr);
689 break;
690 }
691 break;
692
693 default:
694 phr->error = HPI_ERROR_INVALID_TYPE;
695 break;
696 }
697}