blob: 8346aeabee5dc33c489cc2b066958832b47d997a [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) {
81 {
82 retval = HPI_DUPLICATE_ADAPTER_NUMBER;
83 goto unlock;
84 }
85 }
86 adapters.adapter[pao->index] = *pao;
87 hpios_dsplock_init(&adapters.adapter[pao->index]);
88 adapters.gw_num_adapters++;
89
90unlock:
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130091 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020092 return retval;
93}
94
95void hpi_delete_adapter(struct hpi_adapter_obj *pao)
96{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +130097 if (!pao->adapter_type) {
98 HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
99 return;
100 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200101
102 hpios_alistlock_lock(&adapters);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300103 if (adapters.adapter[pao->index].adapter_type)
104 adapters.gw_num_adapters--;
105 memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
106 hpios_alistlock_unlock(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200107}
108
109/**
110* FindAdapter returns a pointer to the struct hpi_adapter_obj with
111* index wAdapterIndex in an HPI_ADAPTERS_LIST structure.
112*
113*/
114struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
115{
116 struct hpi_adapter_obj *pao = NULL;
117
118 if (adapter_index >= HPI_MAX_ADAPTERS) {
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300119 HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200120 adapter_index);
121 return NULL;
122 }
123
124 pao = &adapters.adapter[adapter_index];
125 if (pao->adapter_type != 0) {
126 /*
127 HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
128 wAdapterIndex);
129 */
130 return pao;
131 } else {
132 /*
133 HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
134 wAdapterIndex);
135 */
136 return NULL;
137 }
138}
139
140/**
141*
142* wipe an HPI_ADAPTERS_LIST structure.
143*
144**/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300145static void wipe_adapter_list(void)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200146{
147 memset(&adapters, 0, sizeof(adapters));
148}
149
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300150static void subsys_get_adapter(struct hpi_message *phm,
151 struct hpi_response *phr)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200152{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300153 int count = phm->obj_index;
154 u16 index = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200155
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300156 /* find the nCount'th nonzero adapter in array */
157 for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
158 if (adapters.adapter[index].adapter_type) {
159 if (count == 0)
160 break;
161 count--;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200162 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200163 }
164
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300165 if (index < HPI_MAX_ADAPTERS) {
166 phr->u.s.adapter_index = adapters.adapter[index].index;
167 phr->u.s.aw_adapter_list[0] =
168 adapters.adapter[index].adapter_type;
169 } else {
170 phr->u.s.adapter_index = 0;
171 phr->u.s.aw_adapter_list[0] = 0;
172 phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
173 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200174}
175
176static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
177{
178 unsigned int i;
179 int cached = 0;
180 if (!pC)
181 return 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200182
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300183 if (pC->init)
184 return pC->init;
185
186 if (!pC->p_cache)
187 return 0;
188
189 if (pC->control_count && pC->cache_size_in_bytes) {
190 char *p_master_cache;
191 unsigned int byte_count = 0;
192
193 p_master_cache = (char *)pC->p_cache;
194 HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200195 pC->control_count);
196 for (i = 0; i < pC->control_count; i++) {
197 struct hpi_control_cache_info *info =
198 (struct hpi_control_cache_info *)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300199 &p_master_cache[byte_count];
200
201 if (!info->size_in32bit_words) {
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300202 if (i == 0) {
203 HPI_DEBUG_LOG(INFO,
204 "adap %d cache not ready?\n",
205 pC->adap_idx);
206 return 0;
207 }
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300208 /* The cache is invalid.
209 * Minimum valid entry size is
210 * sizeof(struct hpi_control_cache_info)
211 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300212 HPI_DEBUG_LOG(ERROR,
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300213 "adap %d zero size cache entry %d\n",
214 pC->adap_idx, i);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300215 break;
216 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200217
218 if (info->control_type) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300219 pC->p_info[info->control_index] = info;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200220 cached++;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300221 } else /* dummy cache entry */
222 pC->p_info[info->control_index] = NULL;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200223
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300224 byte_count += info->size_in32bit_words * 4;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200225
226 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300227 "cached %d, pinfo %p index %d type %d size %d\n",
228 cached, pC->p_info[info->control_index],
229 info->control_index, info->control_type,
230 info->size_in32bit_words);
231
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300232 /* quit loop early if whole cache has been scanned.
233 * dwControlCount is the maximum possible entries
234 * but some may be absent from the cache
235 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300236 if (byte_count >= pC->cache_size_in_bytes)
237 break;
238 /* have seen last control index */
239 if (info->control_index == pC->control_count - 1)
240 break;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200241 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300242
243 if (byte_count != pC->cache_size_in_bytes)
244 HPI_DEBUG_LOG(WARNING,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300245 "adap %d bytecount %d != cache size %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300246 pC->adap_idx, byte_count,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300247 pC->cache_size_in_bytes);
248 else
249 HPI_DEBUG_LOG(DEBUG,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300250 "adap %d cache good, bytecount == cache size = %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300251 pC->adap_idx, byte_count);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300252
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300253 pC->init = (u16)cached;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200254 }
255 return pC->init;
256}
257
258/** Find a control.
259*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300260static short find_control(u16 control_index,
261 struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200262{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200263 if (!control_cache_alloc_check(p_cache)) {
264 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300265 "control_cache_alloc_check() failed %d\n",
266 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200267 return 0;
268 }
269
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300270 *pI = p_cache->p_info[control_index];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200271 if (!*pI) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300272 HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
273 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200274 return 0;
275 } else {
276 HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
277 (*pI)->control_type);
278 }
279 return 1;
280}
281
282/** Used by the kernel driver to figure out if a buffer needs mapping.
283 */
284short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
285 struct hpi_message *phm, void **p, unsigned int *pN)
286{
287 *pN = 0;
288 *p = NULL;
289 if ((phm->function == HPI_CONTROL_GET_STATE)
290 && (phm->object == HPI_OBJ_CONTROLEX)
291 ) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200292 struct hpi_control_cache_info *pI;
293
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300294 if (!find_control(phm->obj_index, p_cache, &pI)) {
295 HPI_DEBUG_LOG(VERBOSE,
296 "HPICMN find_control() failed for adap %d\n",
297 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200298 return 0;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300299 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200300 }
301 return 0;
302}
303
304/* allow unified treatment of several string fields within struct */
305#define HPICMN_PAD_OFS_AND_SIZE(m) {\
306 offsetof(struct hpi_control_cache_pad, m), \
307 sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
308
309struct pad_ofs_size {
310 unsigned int offset;
311 unsigned int field_size;
312};
313
314static struct pad_ofs_size pad_desc[] = {
315 HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
316 HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
317 HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
318 HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
319};
320
321/** CheckControlCache checks the cache and fills the struct hpi_response
322 * accordingly. It returns one if a cache hit occurred, zero otherwise.
323 */
324short hpi_check_control_cache(struct hpi_control_cache *p_cache,
325 struct hpi_message *phm, struct hpi_response *phr)
326{
327 short found = 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200328 struct hpi_control_cache_info *pI;
329 struct hpi_control_cache_single *pC;
330 struct hpi_control_cache_pad *p_pad;
331
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300332 if (!find_control(phm->obj_index, p_cache, &pI)) {
333 HPI_DEBUG_LOG(VERBOSE,
334 "HPICMN find_control() failed for adap %d\n",
335 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200336 return 0;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300337 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200338
339 phr->error = 0;
340
341 /* pC is the default cached control strucure. May be cast to
342 something else in the following switch statement.
343 */
344 pC = (struct hpi_control_cache_single *)pI;
345 p_pad = (struct hpi_control_cache_pad *)pI;
346
347 switch (pI->control_type) {
348
349 case HPI_CONTROL_METER:
350 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300351 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
352 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200353 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300354 if (pC->u.meter.an_logRMS[0] ==
355 HPI_CACHE_INVALID_SHORT) {
356 phr->error =
357 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
358 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
359 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
360 } else {
361 phr->u.c.an_log_value[0] =
362 pC->u.meter.an_logRMS[0];
363 phr->u.c.an_log_value[1] =
364 pC->u.meter.an_logRMS[1];
365 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200366 } else
367 found = 0;
368 break;
369 case HPI_CONTROL_VOLUME:
370 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300371 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
372 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200373 } else
374 found = 0;
375 break;
376 case HPI_CONTROL_MULTIPLEXER:
377 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300378 phr->u.c.param1 = pC->u.mux.source_node_type;
379 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200380 } else {
381 found = 0;
382 }
383 break;
384 case HPI_CONTROL_CHANNEL_MODE:
385 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300386 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200387 else
388 found = 0;
389 break;
390 case HPI_CONTROL_LEVEL:
391 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300392 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
393 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200394 } else
395 found = 0;
396 break;
397 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200398 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300399 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200400 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300401 phr->u.c.param1 = pC->u.tuner.band;
402 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
403 if (pC->u.tuner.s_level_avg ==
404 HPI_CACHE_INVALID_SHORT) {
405 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200406 phr->error =
407 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
408 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300409 phr->u.cu.tuner.s_level =
410 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200411 else
412 found = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200413 break;
414 case HPI_CONTROL_AESEBU_RECEIVER:
415 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
416 phr->u.c.param1 = pC->u.aes3rx.error_status;
417 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300418 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200419 else
420 found = 0;
421 break;
422 case HPI_CONTROL_AESEBU_TRANSMITTER:
423 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
424 phr->u.c.param1 = pC->u.aes3tx.format;
425 else
426 found = 0;
427 break;
428 case HPI_CONTROL_TONEDETECTOR:
429 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
430 phr->u.c.param1 = pC->u.tone.state;
431 else
432 found = 0;
433 break;
434 case HPI_CONTROL_SILENCEDETECTOR:
435 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
436 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200437 } else
438 found = 0;
439 break;
440 case HPI_CONTROL_MICROPHONE:
441 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300442 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200443 else
444 found = 0;
445 break;
446 case HPI_CONTROL_SAMPLECLOCK:
447 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
448 phr->u.c.param1 = pC->u.clk.source;
449 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
450 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300451 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200452 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200453 phr->error =
454 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200455 } else
456 phr->u.c.param1 = pC->u.clk.source_index;
457 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
458 phr->u.c.param1 = pC->u.clk.sample_rate;
459 else
460 found = 0;
461 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300462 case HPI_CONTROL_PAD:{
463 struct hpi_control_cache_pad *p_pad;
464 p_pad = (struct hpi_control_cache_pad *)pI;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200465
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300466 if (!(p_pad->field_valid_flags & (1 <<
467 HPI_CTL_ATTR_INDEX(phm->u.c.
468 attribute)))) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200469 phr->error =
470 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
471 break;
472 }
473
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300474 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
475 phr->u.c.param1 = p_pad->pI;
476 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
477 phr->u.c.param1 = p_pad->pTY;
478 else {
479 unsigned int index =
480 HPI_CTL_ATTR_INDEX(phm->u.c.
481 attribute) - 1;
482 unsigned int offset = phm->u.c.param1;
483 unsigned int pad_string_len, field_size;
484 char *pad_string;
485 unsigned int tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200486
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300487 if (index > ARRAY_SIZE(pad_desc) - 1) {
488 phr->error =
489 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
490 break;
491 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200492
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300493 pad_string =
494 ((char *)p_pad) +
495 pad_desc[index].offset;
496 field_size = pad_desc[index].field_size;
497 /* Ensure null terminator */
498 pad_string[field_size - 1] = 0;
499
500 pad_string_len = strlen(pad_string) + 1;
501
502 if (offset > pad_string_len) {
503 phr->error =
504 HPI_ERROR_INVALID_CONTROL_VALUE;
505 break;
506 }
507
508 tocopy = pad_string_len - offset;
509 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
510 tocopy = sizeof(phr->u.cu.chars8.
511 sz_data);
512
513 memcpy(phr->u.cu.chars8.sz_data,
514 &pad_string[offset], tocopy);
515
516 phr->u.cu.chars8.remaining_chars =
517 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200518 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200519 }
520 break;
521 default:
522 found = 0;
523 break;
524 }
525
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300526 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
527 found ? "Cached" : "Uncached", phm->adapter_index,
528 pI->control_index, pI->control_type, phm->u.c.attribute);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200529
530 if (found)
531 phr->size =
532 sizeof(struct hpi_response_header) +
533 sizeof(struct hpi_control_res);
534
535 return found;
536}
537
538/** Updates the cache with Set values.
539
540Only update if no error.
541Volume and Level return the limited values in the response, so use these
542Multiplexer does so use sent values
543*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300544void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200545 struct hpi_message *phm, struct hpi_response *phr)
546{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200547 struct hpi_control_cache_single *pC;
548 struct hpi_control_cache_info *pI;
549
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200550 if (phr->error)
551 return;
552
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300553 if (!find_control(phm->obj_index, p_cache, &pI)) {
554 HPI_DEBUG_LOG(VERBOSE,
555 "HPICMN find_control() failed for adap %d\n",
556 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200557 return;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300558 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200559
560 /* pC is the default cached control strucure.
561 May be cast to something else in the following switch statement.
562 */
563 pC = (struct hpi_control_cache_single *)pI;
564
565 switch (pI->control_type) {
566 case HPI_CONTROL_VOLUME:
567 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300568 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
569 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200570 }
571 break;
572 case HPI_CONTROL_MULTIPLEXER:
573 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200574 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300575 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
576 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200577 }
578 break;
579 case HPI_CONTROL_CHANNEL_MODE:
580 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200581 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300582 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200583 break;
584 case HPI_CONTROL_LEVEL:
585 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300586 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
587 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200588 }
589 break;
590 case HPI_CONTROL_MICROPHONE:
591 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300592 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200593 break;
594 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200595 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
596 pC->u.aes3tx.format = phm->u.c.param1;
597 break;
598 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200599 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300600 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200601 break;
602 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200603 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
604 pC->u.clk.source = (u16)phm->u.c.param1;
605 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
606 pC->u.clk.source_index = (u16)phm->u.c.param1;
607 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
608 pC->u.clk.sample_rate = phm->u.c.param1;
609 break;
610 default:
611 break;
612 }
613}
614
615struct hpi_control_cache *hpi_alloc_control_cache(const u32
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300616 number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200617{
618 struct hpi_control_cache *p_cache =
619 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200620 if (!p_cache)
621 return NULL;
622 p_cache->p_info =
623 kmalloc(sizeof(*p_cache->p_info) * number_of_controls,
624 GFP_KERNEL);
625 if (!p_cache->p_info) {
626 kfree(p_cache);
627 return NULL;
628 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200629 p_cache->cache_size_in_bytes = size_in_bytes;
630 p_cache->control_count = number_of_controls;
631 p_cache->p_cache =
632 (struct hpi_control_cache_single *)pDSP_control_buffer;
633 p_cache->init = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200634 return p_cache;
635}
636
637void hpi_free_control_cache(struct hpi_control_cache *p_cache)
638{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300639 if (p_cache) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200640 kfree(p_cache->p_info);
641 p_cache->p_info = NULL;
642 p_cache->init = 0;
643 kfree(p_cache);
644 }
645}
646
647static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
648{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300649 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200650
651 switch (phm->function) {
652 case HPI_SUBSYS_OPEN:
653 case HPI_SUBSYS_CLOSE:
654 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200655 break;
656 case HPI_SUBSYS_DRIVER_LOAD:
657 wipe_adapter_list();
658 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200659 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300660 case HPI_SUBSYS_GET_ADAPTER:
661 subsys_get_adapter(phm, phr);
662 break;
663 case HPI_SUBSYS_GET_NUM_ADAPTERS:
664 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200665 break;
666 case HPI_SUBSYS_CREATE_ADAPTER:
667 case HPI_SUBSYS_DELETE_ADAPTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200668 break;
669 default:
670 phr->error = HPI_ERROR_INVALID_FUNC;
671 break;
672 }
673}
674
675void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
676{
677 switch (phm->type) {
678 case HPI_TYPE_MESSAGE:
679 switch (phm->object) {
680 case HPI_OBJ_SUBSYSTEM:
681 subsys_message(phm, phr);
682 break;
683 }
684 break;
685
686 default:
687 phr->error = HPI_ERROR_INVALID_TYPE;
688 break;
689 }
690}