blob: 7ed5c26c3737f11fd2eb98a5c4da858ac23f3731 [file] [log] [blame]
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001/******************************************************************************
2
3 AudioScience HPI driver
Eliot Blennerhassett40818b62011-12-22 13:38:32 +13004 Copyright (C) 1997-2011 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];
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;
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200318 size_t response_size;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300319 if (!find_control(phm->obj_index, p_cache, &pI)) {
320 HPI_DEBUG_LOG(VERBOSE,
321 "HPICMN find_control() failed for adap %d\n",
322 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200323 return 0;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300324 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200325
326 phr->error = 0;
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300327 phr->specific_error = 0;
328 phr->version = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200329
Eliot Blennerhassettc6c2c9a2011-07-22 15:52:38 +1200330 /* set the default response size */
331 response_size =
332 sizeof(struct hpi_response_header) +
333 sizeof(struct hpi_control_res);
334
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200335 /* pC is the default cached control strucure. May be cast to
336 something else in the following switch statement.
337 */
338 pC = (struct hpi_control_cache_single *)pI;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200339
340 switch (pI->control_type) {
341
342 case HPI_CONTROL_METER:
343 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300344 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
345 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200346 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300347 if (pC->u.meter.an_logRMS[0] ==
348 HPI_CACHE_INVALID_SHORT) {
349 phr->error =
350 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
351 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
352 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
353 } else {
354 phr->u.c.an_log_value[0] =
355 pC->u.meter.an_logRMS[0];
356 phr->u.c.an_log_value[1] =
357 pC->u.meter.an_logRMS[1];
358 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200359 } else
360 found = 0;
361 break;
362 case HPI_CONTROL_VOLUME:
363 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300364 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
365 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300366 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
367 if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
368 if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
369 phr->u.c.param1 =
370 HPI_BITMASK_ALL_CHANNELS;
371 else
372 phr->u.c.param1 = 0;
373 } else {
374 phr->error =
375 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
376 phr->u.c.param1 = 0;
377 }
378 } else {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200379 found = 0;
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300380 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200381 break;
382 case HPI_CONTROL_MULTIPLEXER:
383 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300384 phr->u.c.param1 = pC->u.mux.source_node_type;
385 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200386 } else {
387 found = 0;
388 }
389 break;
390 case HPI_CONTROL_CHANNEL_MODE:
391 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300392 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200393 else
394 found = 0;
395 break;
396 case HPI_CONTROL_LEVEL:
397 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300398 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
399 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200400 } else
401 found = 0;
402 break;
403 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200404 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300405 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200406 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300407 phr->u.c.param1 = pC->u.tuner.band;
408 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
409 if (pC->u.tuner.s_level_avg ==
410 HPI_CACHE_INVALID_SHORT) {
411 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200412 phr->error =
413 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
414 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300415 phr->u.cu.tuner.s_level =
416 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200417 else
418 found = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200419 break;
420 case HPI_CONTROL_AESEBU_RECEIVER:
421 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
422 phr->u.c.param1 = pC->u.aes3rx.error_status;
423 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300424 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200425 else
426 found = 0;
427 break;
428 case HPI_CONTROL_AESEBU_TRANSMITTER:
429 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
430 phr->u.c.param1 = pC->u.aes3tx.format;
431 else
432 found = 0;
433 break;
434 case HPI_CONTROL_TONEDETECTOR:
435 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
436 phr->u.c.param1 = pC->u.tone.state;
437 else
438 found = 0;
439 break;
440 case HPI_CONTROL_SILENCEDETECTOR:
441 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
442 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200443 } else
444 found = 0;
445 break;
446 case HPI_CONTROL_MICROPHONE:
447 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300448 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200449 else
450 found = 0;
451 break;
452 case HPI_CONTROL_SAMPLECLOCK:
453 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
454 phr->u.c.param1 = pC->u.clk.source;
455 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
456 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300457 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200458 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200459 phr->error =
460 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200461 } else
462 phr->u.c.param1 = pC->u.clk.source_index;
463 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
464 phr->u.c.param1 = pC->u.clk.sample_rate;
465 else
466 found = 0;
467 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300468 case HPI_CONTROL_PAD:{
469 struct hpi_control_cache_pad *p_pad;
470 p_pad = (struct hpi_control_cache_pad *)pI;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200471
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300472 if (!(p_pad->field_valid_flags & (1 <<
473 HPI_CTL_ATTR_INDEX(phm->u.c.
474 attribute)))) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200475 phr->error =
476 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
477 break;
478 }
479
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300480 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
481 phr->u.c.param1 = p_pad->pI;
482 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
483 phr->u.c.param1 = p_pad->pTY;
484 else {
485 unsigned int index =
486 HPI_CTL_ATTR_INDEX(phm->u.c.
487 attribute) - 1;
488 unsigned int offset = phm->u.c.param1;
489 unsigned int pad_string_len, field_size;
490 char *pad_string;
491 unsigned int tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200492
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300493 if (index > ARRAY_SIZE(pad_desc) - 1) {
494 phr->error =
495 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
496 break;
497 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200498
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300499 pad_string =
500 ((char *)p_pad) +
501 pad_desc[index].offset;
502 field_size = pad_desc[index].field_size;
503 /* Ensure null terminator */
504 pad_string[field_size - 1] = 0;
505
506 pad_string_len = strlen(pad_string) + 1;
507
508 if (offset > pad_string_len) {
509 phr->error =
510 HPI_ERROR_INVALID_CONTROL_VALUE;
511 break;
512 }
513
514 tocopy = pad_string_len - offset;
515 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
516 tocopy = sizeof(phr->u.cu.chars8.
517 sz_data);
518
519 memcpy(phr->u.cu.chars8.sz_data,
520 &pad_string[offset], tocopy);
521
522 phr->u.cu.chars8.remaining_chars =
523 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200524 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200525 }
526 break;
527 default:
528 found = 0;
529 break;
530 }
531
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300532 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
533 found ? "Cached" : "Uncached", phm->adapter_index,
534 pI->control_index, pI->control_type, phm->u.c.attribute);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200535
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300536 if (found) {
Eliot Blennerhassett3d0591e2011-07-22 15:52:58 +1200537 phr->size = (u16)response_size;
Eliot Blennerhassett8637bc92011-12-22 13:38:49 +1300538 phr->type = HPI_TYPE_RESPONSE;
539 phr->object = phm->object;
540 phr->function = phm->function;
541 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200542
543 return found;
544}
545
546/** Updates the cache with Set values.
547
548Only update if no error.
549Volume and Level return the limited values in the response, so use these
550Multiplexer does so use sent values
551*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300552void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200553 struct hpi_message *phm, struct hpi_response *phr)
554{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200555 struct hpi_control_cache_single *pC;
556 struct hpi_control_cache_info *pI;
557
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200558 if (phr->error)
559 return;
560
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300561 if (!find_control(phm->obj_index, p_cache, &pI)) {
562 HPI_DEBUG_LOG(VERBOSE,
563 "HPICMN find_control() failed for adap %d\n",
564 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200565 return;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300566 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200567
568 /* pC is the default cached control strucure.
569 May be cast to something else in the following switch statement.
570 */
571 pC = (struct hpi_control_cache_single *)pI;
572
573 switch (pI->control_type) {
574 case HPI_CONTROL_VOLUME:
575 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300576 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
577 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassettfc3a3992011-02-10 17:26:11 +1300578 } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
579 if (phm->u.c.param1)
580 pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
581 else
582 pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200583 }
584 break;
585 case HPI_CONTROL_MULTIPLEXER:
586 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200587 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300588 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
589 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200590 }
591 break;
592 case HPI_CONTROL_CHANNEL_MODE:
593 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200594 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300595 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200596 break;
597 case HPI_CONTROL_LEVEL:
598 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300599 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
600 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200601 }
602 break;
603 case HPI_CONTROL_MICROPHONE:
604 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300605 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200606 break;
607 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200608 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
609 pC->u.aes3tx.format = phm->u.c.param1;
610 break;
611 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200612 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300613 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200614 break;
615 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200616 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
617 pC->u.clk.source = (u16)phm->u.c.param1;
618 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
619 pC->u.clk.source_index = (u16)phm->u.c.param1;
620 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
621 pC->u.clk.sample_rate = phm->u.c.param1;
622 break;
623 default:
624 break;
625 }
626}
627
Eliot Blennerhassett42258da2011-04-05 20:55:48 +1200628/** Allocate control cache.
629
630\return Cache pointer, or NULL if allocation fails.
631*/
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300632struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
633 const u32 size_in_bytes, u8 *p_dsp_control_buffer)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200634{
635 struct hpi_control_cache *p_cache =
636 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200637 if (!p_cache)
638 return NULL;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300639
Thomas Meyer6d2d4312011-11-29 22:08:00 +0100640 p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info),
Thomas Meyer67ada832011-08-06 13:26:20 +0200641 GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200642 if (!p_cache->p_info) {
643 kfree(p_cache);
644 return NULL;
645 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200646 p_cache->cache_size_in_bytes = size_in_bytes;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300647 p_cache->control_count = control_count;
648 p_cache->p_cache = p_dsp_control_buffer;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200649 p_cache->init = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200650 return p_cache;
651}
652
653void hpi_free_control_cache(struct hpi_control_cache *p_cache)
654{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300655 if (p_cache) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200656 kfree(p_cache->p_info);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200657 kfree(p_cache);
658 }
659}
660
661static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
662{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300663 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200664
665 switch (phm->function) {
666 case HPI_SUBSYS_OPEN:
667 case HPI_SUBSYS_CLOSE:
668 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200669 break;
670 case HPI_SUBSYS_DRIVER_LOAD:
671 wipe_adapter_list();
672 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200673 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300674 case HPI_SUBSYS_GET_ADAPTER:
675 subsys_get_adapter(phm, phr);
676 break;
677 case HPI_SUBSYS_GET_NUM_ADAPTERS:
678 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200679 break;
680 case HPI_SUBSYS_CREATE_ADAPTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200681 break;
682 default:
683 phr->error = HPI_ERROR_INVALID_FUNC;
684 break;
685 }
686}
687
688void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
689{
690 switch (phm->type) {
Eliot Blennerhassett82b57742011-07-22 15:52:36 +1200691 case HPI_TYPE_REQUEST:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200692 switch (phm->object) {
693 case HPI_OBJ_SUBSYSTEM:
694 subsys_message(phm, phr);
695 break;
696 }
697 break;
698
699 default:
700 phr->error = HPI_ERROR_INVALID_TYPE;
701 break;
702 }
703}