blob: e0a08f61a34870209050bc7a38f448f7a00adadb [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) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300159 if (!count)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300160 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;
Eliot Blennerhassett2f918a62011-02-10 17:26:09 +1300167 phr->u.s.adapter_type = adapters.adapter[index].adapter_type;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300168 } else {
169 phr->u.s.adapter_index = 0;
Eliot Blennerhassett2f918a62011-02-10 17:26:09 +1300170 phr->u.s.adapter_type = 0;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300171 phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
172 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200173}
174
175static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
176{
177 unsigned int i;
178 int cached = 0;
179 if (!pC)
180 return 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200181
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300182 if (pC->init)
183 return pC->init;
184
185 if (!pC->p_cache)
186 return 0;
187
188 if (pC->control_count && pC->cache_size_in_bytes) {
189 char *p_master_cache;
190 unsigned int byte_count = 0;
191
192 p_master_cache = (char *)pC->p_cache;
193 HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200194 pC->control_count);
195 for (i = 0; i < pC->control_count; i++) {
196 struct hpi_control_cache_info *info =
197 (struct hpi_control_cache_info *)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300198 &p_master_cache[byte_count];
199
200 if (!info->size_in32bit_words) {
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300201 if (!i) {
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300202 HPI_DEBUG_LOG(INFO,
203 "adap %d cache not ready?\n",
204 pC->adap_idx);
205 return 0;
206 }
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300207 /* The cache is invalid.
208 * Minimum valid entry size is
209 * sizeof(struct hpi_control_cache_info)
210 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300211 HPI_DEBUG_LOG(ERROR,
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300212 "adap %d zero size cache entry %d\n",
213 pC->adap_idx, i);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300214 break;
215 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200216
217 if (info->control_type) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300218 pC->p_info[info->control_index] = info;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200219 cached++;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300220 } else /* dummy cache entry */
221 pC->p_info[info->control_index] = NULL;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200222
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300223 byte_count += info->size_in32bit_words * 4;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200224
225 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300226 "cached %d, pinfo %p index %d type %d size %d\n",
227 cached, pC->p_info[info->control_index],
228 info->control_index, info->control_type,
229 info->size_in32bit_words);
230
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300231 /* quit loop early if whole cache has been scanned.
232 * dwControlCount is the maximum possible entries
233 * but some may be absent from the cache
234 */
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300235 if (byte_count >= pC->cache_size_in_bytes)
236 break;
237 /* have seen last control index */
238 if (info->control_index == pC->control_count - 1)
239 break;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200240 }
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300241
242 if (byte_count != pC->cache_size_in_bytes)
243 HPI_DEBUG_LOG(WARNING,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300244 "adap %d bytecount %d != cache size %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300245 pC->adap_idx, byte_count,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300246 pC->cache_size_in_bytes);
247 else
248 HPI_DEBUG_LOG(DEBUG,
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300249 "adap %d cache good, bytecount == cache size = %d\n",
Eliot Blennerhassettffdb5782011-02-10 17:26:00 +1300250 pC->adap_idx, byte_count);
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300251
Eliot Blennerhassett1528fbb2011-02-10 17:26:02 +1300252 pC->init = (u16)cached;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200253 }
254 return pC->init;
255}
256
257/** Find a control.
258*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300259static short find_control(u16 control_index,
260 struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200261{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200262 if (!control_cache_alloc_check(p_cache)) {
263 HPI_DEBUG_LOG(VERBOSE,
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300264 "control_cache_alloc_check() failed %d\n",
265 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200266 return 0;
267 }
268
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300269 *pI = p_cache->p_info[control_index];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200270 if (!*pI) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300271 HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
272 control_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200273 return 0;
274 } else {
275 HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
276 (*pI)->control_type);
277 }
278 return 1;
279}
280
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200281/* allow unified treatment of several string fields within struct */
282#define HPICMN_PAD_OFS_AND_SIZE(m) {\
283 offsetof(struct hpi_control_cache_pad, m), \
284 sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
285
286struct pad_ofs_size {
287 unsigned int offset;
288 unsigned int field_size;
289};
290
291static struct pad_ofs_size pad_desc[] = {
292 HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
293 HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
294 HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
295 HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */
296};
297
298/** CheckControlCache checks the cache and fills the struct hpi_response
299 * accordingly. It returns one if a cache hit occurred, zero otherwise.
300 */
301short hpi_check_control_cache(struct hpi_control_cache *p_cache,
302 struct hpi_message *phm, struct hpi_response *phr)
303{
304 short found = 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200305 struct hpi_control_cache_info *pI;
306 struct hpi_control_cache_single *pC;
307 struct hpi_control_cache_pad *p_pad;
308
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300309 if (!find_control(phm->obj_index, p_cache, &pI)) {
310 HPI_DEBUG_LOG(VERBOSE,
311 "HPICMN find_control() failed for adap %d\n",
312 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200313 return 0;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300314 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200315
316 phr->error = 0;
317
318 /* pC is the default cached control strucure. May be cast to
319 something else in the following switch statement.
320 */
321 pC = (struct hpi_control_cache_single *)pI;
322 p_pad = (struct hpi_control_cache_pad *)pI;
323
324 switch (pI->control_type) {
325
326 case HPI_CONTROL_METER:
327 if (phm->u.c.attribute == HPI_METER_PEAK) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300328 phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
329 phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200330 } else if (phm->u.c.attribute == HPI_METER_RMS) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300331 if (pC->u.meter.an_logRMS[0] ==
332 HPI_CACHE_INVALID_SHORT) {
333 phr->error =
334 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
335 phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
336 phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
337 } else {
338 phr->u.c.an_log_value[0] =
339 pC->u.meter.an_logRMS[0];
340 phr->u.c.an_log_value[1] =
341 pC->u.meter.an_logRMS[1];
342 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200343 } else
344 found = 0;
345 break;
346 case HPI_CONTROL_VOLUME:
347 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300348 phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
349 phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200350 } else
351 found = 0;
352 break;
353 case HPI_CONTROL_MULTIPLEXER:
354 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300355 phr->u.c.param1 = pC->u.mux.source_node_type;
356 phr->u.c.param2 = pC->u.mux.source_node_index;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200357 } else {
358 found = 0;
359 }
360 break;
361 case HPI_CONTROL_CHANNEL_MODE:
362 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300363 phr->u.c.param1 = pC->u.mode.mode;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200364 else
365 found = 0;
366 break;
367 case HPI_CONTROL_LEVEL:
368 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300369 phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
370 phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200371 } else
372 found = 0;
373 break;
374 case HPI_CONTROL_TUNER:
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200375 if (phm->u.c.attribute == HPI_TUNER_FREQ)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300376 phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200377 else if (phm->u.c.attribute == HPI_TUNER_BAND)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300378 phr->u.c.param1 = pC->u.tuner.band;
379 else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
380 if (pC->u.tuner.s_level_avg ==
381 HPI_CACHE_INVALID_SHORT) {
382 phr->u.cu.tuner.s_level = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200383 phr->error =
384 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
385 } else
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300386 phr->u.cu.tuner.s_level =
387 pC->u.tuner.s_level_avg;
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200388 else
389 found = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200390 break;
391 case HPI_CONTROL_AESEBU_RECEIVER:
392 if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
393 phr->u.c.param1 = pC->u.aes3rx.error_status;
394 else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300395 phr->u.c.param1 = pC->u.aes3rx.format;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200396 else
397 found = 0;
398 break;
399 case HPI_CONTROL_AESEBU_TRANSMITTER:
400 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
401 phr->u.c.param1 = pC->u.aes3tx.format;
402 else
403 found = 0;
404 break;
405 case HPI_CONTROL_TONEDETECTOR:
406 if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
407 phr->u.c.param1 = pC->u.tone.state;
408 else
409 found = 0;
410 break;
411 case HPI_CONTROL_SILENCEDETECTOR:
412 if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
413 phr->u.c.param1 = pC->u.silence.state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200414 } else
415 found = 0;
416 break;
417 case HPI_CONTROL_MICROPHONE:
418 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300419 phr->u.c.param1 = pC->u.microphone.phantom_state;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200420 else
421 found = 0;
422 break;
423 case HPI_CONTROL_SAMPLECLOCK:
424 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
425 phr->u.c.param1 = pC->u.clk.source;
426 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
427 if (pC->u.clk.source_index ==
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300428 HPI_CACHE_INVALID_UINT16) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200429 phr->u.c.param1 = 0;
Eliot Blennerhassett36ed8bd2010-07-06 08:37:10 +1200430 phr->error =
431 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200432 } else
433 phr->u.c.param1 = pC->u.clk.source_index;
434 } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
435 phr->u.c.param1 = pC->u.clk.sample_rate;
436 else
437 found = 0;
438 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300439 case HPI_CONTROL_PAD:{
440 struct hpi_control_cache_pad *p_pad;
441 p_pad = (struct hpi_control_cache_pad *)pI;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200442
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300443 if (!(p_pad->field_valid_flags & (1 <<
444 HPI_CTL_ATTR_INDEX(phm->u.c.
445 attribute)))) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200446 phr->error =
447 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
448 break;
449 }
450
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300451 if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
452 phr->u.c.param1 = p_pad->pI;
453 else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
454 phr->u.c.param1 = p_pad->pTY;
455 else {
456 unsigned int index =
457 HPI_CTL_ATTR_INDEX(phm->u.c.
458 attribute) - 1;
459 unsigned int offset = phm->u.c.param1;
460 unsigned int pad_string_len, field_size;
461 char *pad_string;
462 unsigned int tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200463
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300464 if (index > ARRAY_SIZE(pad_desc) - 1) {
465 phr->error =
466 HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
467 break;
468 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200469
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300470 pad_string =
471 ((char *)p_pad) +
472 pad_desc[index].offset;
473 field_size = pad_desc[index].field_size;
474 /* Ensure null terminator */
475 pad_string[field_size - 1] = 0;
476
477 pad_string_len = strlen(pad_string) + 1;
478
479 if (offset > pad_string_len) {
480 phr->error =
481 HPI_ERROR_INVALID_CONTROL_VALUE;
482 break;
483 }
484
485 tocopy = pad_string_len - offset;
486 if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
487 tocopy = sizeof(phr->u.cu.chars8.
488 sz_data);
489
490 memcpy(phr->u.cu.chars8.sz_data,
491 &pad_string[offset], tocopy);
492
493 phr->u.cu.chars8.remaining_chars =
494 pad_string_len - offset - tocopy;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200495 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200496 }
497 break;
498 default:
499 found = 0;
500 break;
501 }
502
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300503 HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
504 found ? "Cached" : "Uncached", phm->adapter_index,
505 pI->control_index, pI->control_type, phm->u.c.attribute);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200506
507 if (found)
508 phr->size =
509 sizeof(struct hpi_response_header) +
510 sizeof(struct hpi_control_res);
511
512 return found;
513}
514
515/** Updates the cache with Set values.
516
517Only update if no error.
518Volume and Level return the limited values in the response, so use these
519Multiplexer does so use sent values
520*/
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300521void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200522 struct hpi_message *phm, struct hpi_response *phr)
523{
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200524 struct hpi_control_cache_single *pC;
525 struct hpi_control_cache_info *pI;
526
Eliot Blennerhassett3ee317f2010-05-27 17:53:55 +1200527 if (phr->error)
528 return;
529
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300530 if (!find_control(phm->obj_index, p_cache, &pI)) {
531 HPI_DEBUG_LOG(VERBOSE,
532 "HPICMN find_control() failed for adap %d\n",
533 phm->adapter_index);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200534 return;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300535 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200536
537 /* pC is the default cached control strucure.
538 May be cast to something else in the following switch statement.
539 */
540 pC = (struct hpi_control_cache_single *)pI;
541
542 switch (pI->control_type) {
543 case HPI_CONTROL_VOLUME:
544 if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300545 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
546 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200547 }
548 break;
549 case HPI_CONTROL_MULTIPLEXER:
550 /* mux does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200551 if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300552 pC->u.mux.source_node_type = (u16)phm->u.c.param1;
553 pC->u.mux.source_node_index = (u16)phm->u.c.param2;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200554 }
555 break;
556 case HPI_CONTROL_CHANNEL_MODE:
557 /* mode does not return its setting on Set command. */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200558 if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300559 pC->u.mode.mode = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200560 break;
561 case HPI_CONTROL_LEVEL:
562 if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300563 pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
564 pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200565 }
566 break;
567 case HPI_CONTROL_MICROPHONE:
568 if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300569 pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200570 break;
571 case HPI_CONTROL_AESEBU_TRANSMITTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200572 if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
573 pC->u.aes3tx.format = phm->u.c.param1;
574 break;
575 case HPI_CONTROL_AESEBU_RECEIVER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200576 if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300577 pC->u.aes3rx.format = phm->u.c.param1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200578 break;
579 case HPI_CONTROL_SAMPLECLOCK:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200580 if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
581 pC->u.clk.source = (u16)phm->u.c.param1;
582 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
583 pC->u.clk.source_index = (u16)phm->u.c.param1;
584 else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
585 pC->u.clk.sample_rate = phm->u.c.param1;
586 break;
587 default:
588 break;
589 }
590}
591
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300592struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
593 const u32 size_in_bytes, u8 *p_dsp_control_buffer)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200594{
595 struct hpi_control_cache *p_cache =
596 kmalloc(sizeof(*p_cache), GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200597 if (!p_cache)
598 return NULL;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300599
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200600 p_cache->p_info =
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300601 kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL);
Jesper Juhlfd0977d2010-10-29 21:35:25 +0200602 if (!p_cache->p_info) {
603 kfree(p_cache);
604 return NULL;
605 }
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300606 memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200607 p_cache->cache_size_in_bytes = size_in_bytes;
Eliot Blennerhassett47049982011-02-10 17:26:06 +1300608 p_cache->control_count = control_count;
609 p_cache->p_cache = p_dsp_control_buffer;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200610 p_cache->init = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200611 return p_cache;
612}
613
614void hpi_free_control_cache(struct hpi_control_cache *p_cache)
615{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300616 if (p_cache) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200617 kfree(p_cache->p_info);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200618 kfree(p_cache);
619 }
620}
621
622static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
623{
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300624 hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200625
626 switch (phm->function) {
627 case HPI_SUBSYS_OPEN:
628 case HPI_SUBSYS_CLOSE:
629 case HPI_SUBSYS_DRIVER_UNLOAD:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200630 break;
631 case HPI_SUBSYS_DRIVER_LOAD:
632 wipe_adapter_list();
633 hpios_alistlock_init(&adapters);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200634 break;
Eliot Blennerhassett3285ea12011-02-10 17:25:58 +1300635 case HPI_SUBSYS_GET_ADAPTER:
636 subsys_get_adapter(phm, phr);
637 break;
638 case HPI_SUBSYS_GET_NUM_ADAPTERS:
639 phr->u.s.num_adapters = adapters.gw_num_adapters;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200640 break;
641 case HPI_SUBSYS_CREATE_ADAPTER:
642 case HPI_SUBSYS_DELETE_ADAPTER:
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200643 break;
644 default:
645 phr->error = HPI_ERROR_INVALID_FUNC;
646 break;
647 }
648}
649
650void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
651{
652 switch (phm->type) {
653 case HPI_TYPE_MESSAGE:
654 switch (phm->object) {
655 case HPI_OBJ_SUBSYSTEM:
656 subsys_message(phm, phr);
657 break;
658 }
659 break;
660
661 default:
662 phr->error = HPI_ERROR_INVALID_TYPE;
663 break;
664 }
665}