Commit | Line | Data |
---|---|---|
719f82d3 EB |
1 | /****************************************************************************** |
2 | ||
3 | AudioScience HPI driver | |
c1464a88 | 4 | Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> |
719f82d3 EB |
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" | |
3285ea10 EB |
29 | #include "hpimsginit.h" |
30 | ||
719f82d3 EB |
31 | #include "hpicmn.h" |
32 | ||
33 | struct 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 | ||
39 | static 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 | **/ | |
46 | u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) | |
47 | { | |
3285ea10 | 48 | if (phr->type != HPI_TYPE_RESPONSE) { |
1528fbb5 | 49 | HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type); |
3285ea10 EB |
50 | return HPI_ERROR_INVALID_RESPONSE; |
51 | } | |
52 | ||
53 | if (phr->object != phm->object) { | |
1528fbb5 EB |
54 | HPI_DEBUG_LOG(ERROR, "header object %d invalid\n", |
55 | phr->object); | |
3285ea10 EB |
56 | return HPI_ERROR_INVALID_RESPONSE; |
57 | } | |
719f82d3 | 58 | |
3285ea10 | 59 | if (phr->function != phm->function) { |
938c565a | 60 | HPI_DEBUG_LOG(ERROR, "header function %d invalid\n", |
1528fbb5 | 61 | phr->function); |
3285ea10 EB |
62 | return HPI_ERROR_INVALID_RESPONSE; |
63 | } | |
719f82d3 | 64 | |
3285ea10 | 65 | return 0; |
719f82d3 EB |
66 | } |
67 | ||
68 | u16 hpi_add_adapter(struct hpi_adapter_obj *pao) | |
69 | { | |
70 | u16 retval = 0; | |
7036b92d | 71 | /*HPI_ASSERT(pao->type); */ |
719f82d3 EB |
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 | ||
7036b92d | 80 | if (adapters.adapter[pao->index].type) { |
d6f1c1c3 EB |
81 | int a; |
82 | for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) { | |
7036b92d | 83 | if (!adapters.adapter[a].type) { |
d6f1c1c3 EB |
84 | HPI_DEBUG_LOG(WARNING, |
85 | "ASI%X duplicate index %d moved to %d\n", | |
7036b92d | 86 | pao->type, pao->index, a); |
d6f1c1c3 EB |
87 | pao->index = a; |
88 | break; | |
89 | } | |
90 | } | |
91 | if (a < 0) { | |
92 | retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER; | |
719f82d3 EB |
93 | goto unlock; |
94 | } | |
95 | } | |
96 | adapters.adapter[pao->index] = *pao; | |
97 | hpios_dsplock_init(&adapters.adapter[pao->index]); | |
98 | adapters.gw_num_adapters++; | |
99 | ||
100 | unlock: | |
3285ea10 | 101 | hpios_alistlock_unlock(&adapters); |
719f82d3 EB |
102 | return retval; |
103 | } | |
104 | ||
105 | void hpi_delete_adapter(struct hpi_adapter_obj *pao) | |
106 | { | |
7036b92d | 107 | if (!pao->type) { |
3285ea10 EB |
108 | HPI_DEBUG_LOG(ERROR, "removing null adapter?\n"); |
109 | return; | |
110 | } | |
719f82d3 EB |
111 | |
112 | hpios_alistlock_lock(&adapters); | |
7036b92d | 113 | if (adapters.adapter[pao->index].type) |
3285ea10 EB |
114 | adapters.gw_num_adapters--; |
115 | memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0])); | |
116 | hpios_alistlock_unlock(&adapters); | |
719f82d3 EB |
117 | } |
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 | */ | |
124 | struct 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) { | |
1528fbb5 | 129 | HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n", |
719f82d3 EB |
130 | adapter_index); |
131 | return NULL; | |
132 | } | |
133 | ||
134 | pao = &adapters.adapter[adapter_index]; | |
7036b92d | 135 | if (pao->type != 0) { |
719f82d3 EB |
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 | **/ | |
3285ea10 | 155 | static void wipe_adapter_list(void) |
719f82d3 EB |
156 | { |
157 | memset(&adapters, 0, sizeof(adapters)); | |
158 | } | |
159 | ||
3285ea10 EB |
160 | static void subsys_get_adapter(struct hpi_message *phm, |
161 | struct hpi_response *phr) | |
719f82d3 | 162 | { |
3285ea10 EB |
163 | int count = phm->obj_index; |
164 | u16 index = 0; | |
719f82d3 | 165 | |
3285ea10 EB |
166 | /* find the nCount'th nonzero adapter in array */ |
167 | for (index = 0; index < HPI_MAX_ADAPTERS; index++) { | |
7036b92d | 168 | if (adapters.adapter[index].type) { |
4704998e | 169 | if (!count) |
3285ea10 EB |
170 | break; |
171 | count--; | |
719f82d3 | 172 | } |
719f82d3 EB |
173 | } |
174 | ||
3285ea10 EB |
175 | if (index < HPI_MAX_ADAPTERS) { |
176 | phr->u.s.adapter_index = adapters.adapter[index].index; | |
7036b92d | 177 | phr->u.s.adapter_type = adapters.adapter[index].type; |
3285ea10 EB |
178 | } else { |
179 | phr->u.s.adapter_index = 0; | |
2f918a64 | 180 | phr->u.s.adapter_type = 0; |
7036b92d | 181 | phr->error = HPI_ERROR_INVALID_OBJ_INDEX; |
3285ea10 | 182 | } |
719f82d3 EB |
183 | } |
184 | ||
185 | static 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; | |
719f82d3 | 191 | |
3285ea10 EB |
192 | 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", | |
719f82d3 EB |
204 | 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 *) | |
3285ea10 | 208 | &p_master_cache[byte_count]; |
c1464a88 EB |
209 | u16 control_index = info->control_index; |
210 | ||
211 | if (control_index >= pC->control_count) { | |
212 | HPI_DEBUG_LOG(INFO, | |
213 | "adap %d control index %d out of range, cache not ready?\n", | |
214 | pC->adap_idx, control_index); | |
215 | return 0; | |
216 | } | |
3285ea10 EB |
217 | |
218 | if (!info->size_in32bit_words) { | |
4704998e | 219 | if (!i) { |
ffdb5787 EB |
220 | HPI_DEBUG_LOG(INFO, |
221 | "adap %d cache not ready?\n", | |
222 | pC->adap_idx); | |
223 | return 0; | |
224 | } | |
1528fbb5 EB |
225 | /* The cache is invalid. |
226 | * Minimum valid entry size is | |
227 | * sizeof(struct hpi_control_cache_info) | |
228 | */ | |
3285ea10 | 229 | HPI_DEBUG_LOG(ERROR, |
ffdb5787 EB |
230 | "adap %d zero size cache entry %d\n", |
231 | pC->adap_idx, i); | |
3285ea10 EB |
232 | break; |
233 | } | |
719f82d3 EB |
234 | |
235 | if (info->control_type) { | |
c1464a88 | 236 | pC->p_info[control_index] = info; |
719f82d3 | 237 | cached++; |
42258dab | 238 | } else { /* dummy cache entry */ |
c1464a88 | 239 | pC->p_info[control_index] = NULL; |
42258dab | 240 | } |
719f82d3 | 241 | |
3285ea10 | 242 | byte_count += info->size_in32bit_words * 4; |
719f82d3 EB |
243 | |
244 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
245 | "cached %d, pinfo %p index %d type %d size %d\n", |
246 | cached, pC->p_info[info->control_index], | |
247 | info->control_index, info->control_type, | |
248 | info->size_in32bit_words); | |
249 | ||
1528fbb5 EB |
250 | /* quit loop early if whole cache has been scanned. |
251 | * dwControlCount is the maximum possible entries | |
252 | * but some may be absent from the cache | |
253 | */ | |
3285ea10 EB |
254 | if (byte_count >= pC->cache_size_in_bytes) |
255 | break; | |
256 | /* have seen last control index */ | |
257 | if (info->control_index == pC->control_count - 1) | |
258 | break; | |
719f82d3 | 259 | } |
3285ea10 EB |
260 | |
261 | if (byte_count != pC->cache_size_in_bytes) | |
262 | HPI_DEBUG_LOG(WARNING, | |
1528fbb5 | 263 | "adap %d bytecount %d != cache size %d\n", |
ffdb5787 | 264 | pC->adap_idx, byte_count, |
3285ea10 EB |
265 | pC->cache_size_in_bytes); |
266 | else | |
267 | HPI_DEBUG_LOG(DEBUG, | |
1528fbb5 | 268 | "adap %d cache good, bytecount == cache size = %d\n", |
ffdb5787 | 269 | pC->adap_idx, byte_count); |
3285ea10 | 270 | |
1528fbb5 | 271 | pC->init = (u16)cached; |
719f82d3 EB |
272 | } |
273 | return pC->init; | |
274 | } | |
275 | ||
276 | /** Find a control. | |
277 | */ | |
3285ea10 EB |
278 | static short find_control(u16 control_index, |
279 | struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI) | |
719f82d3 | 280 | { |
719f82d3 EB |
281 | if (!control_cache_alloc_check(p_cache)) { |
282 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
283 | "control_cache_alloc_check() failed %d\n", |
284 | control_index); | |
719f82d3 EB |
285 | return 0; |
286 | } | |
287 | ||
3285ea10 | 288 | *pI = p_cache->p_info[control_index]; |
719f82d3 | 289 | if (!*pI) { |
3285ea10 EB |
290 | HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", |
291 | control_index); | |
719f82d3 EB |
292 | return 0; |
293 | } else { | |
294 | HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", | |
295 | (*pI)->control_type); | |
296 | } | |
297 | return 1; | |
298 | } | |
299 | ||
719f82d3 EB |
300 | /* allow unified treatment of several string fields within struct */ |
301 | #define HPICMN_PAD_OFS_AND_SIZE(m) {\ | |
302 | offsetof(struct hpi_control_cache_pad, m), \ | |
303 | sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } | |
304 | ||
305 | struct pad_ofs_size { | |
306 | unsigned int offset; | |
307 | unsigned int field_size; | |
308 | }; | |
309 | ||
42258dab | 310 | static const struct pad_ofs_size pad_desc[] = { |
719f82d3 EB |
311 | HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ |
312 | HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ | |
313 | HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ | |
314 | HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ | |
315 | }; | |
316 | ||
317 | /** CheckControlCache checks the cache and fills the struct hpi_response | |
318 | * accordingly. It returns one if a cache hit occurred, zero otherwise. | |
319 | */ | |
c1464a88 | 320 | short hpi_check_control_cache_single(struct hpi_control_cache_single *pC, |
719f82d3 EB |
321 | struct hpi_message *phm, struct hpi_response *phr) |
322 | { | |
3d0591ee | 323 | size_t response_size; |
c1464a88 | 324 | short found = 1; |
719f82d3 | 325 | |
c6c2c9ab EB |
326 | /* set the default response size */ |
327 | response_size = | |
328 | sizeof(struct hpi_response_header) + | |
329 | sizeof(struct hpi_control_res); | |
330 | ||
c1464a88 | 331 | switch (pC->u.i.control_type) { |
719f82d3 EB |
332 | |
333 | case HPI_CONTROL_METER: | |
334 | if (phm->u.c.attribute == HPI_METER_PEAK) { | |
3285ea10 EB |
335 | phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; |
336 | phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; | |
719f82d3 | 337 | } else if (phm->u.c.attribute == HPI_METER_RMS) { |
3285ea10 EB |
338 | if (pC->u.meter.an_logRMS[0] == |
339 | HPI_CACHE_INVALID_SHORT) { | |
340 | phr->error = | |
341 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
342 | phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; | |
343 | phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; | |
344 | } else { | |
345 | phr->u.c.an_log_value[0] = | |
346 | pC->u.meter.an_logRMS[0]; | |
347 | phr->u.c.an_log_value[1] = | |
348 | pC->u.meter.an_logRMS[1]; | |
349 | } | |
719f82d3 EB |
350 | } else |
351 | found = 0; | |
352 | break; | |
353 | case HPI_CONTROL_VOLUME: | |
354 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
355 | phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; |
356 | phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; | |
fc3a3990 EB |
357 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
358 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) { | |
359 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED) | |
360 | phr->u.c.param1 = | |
361 | HPI_BITMASK_ALL_CHANNELS; | |
362 | else | |
363 | phr->u.c.param1 = 0; | |
364 | } else { | |
365 | phr->error = | |
366 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
367 | phr->u.c.param1 = 0; | |
368 | } | |
369 | } else { | |
719f82d3 | 370 | found = 0; |
fc3a3990 | 371 | } |
719f82d3 EB |
372 | break; |
373 | case HPI_CONTROL_MULTIPLEXER: | |
374 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | |
3285ea10 EB |
375 | phr->u.c.param1 = pC->u.mux.source_node_type; |
376 | phr->u.c.param2 = pC->u.mux.source_node_index; | |
719f82d3 EB |
377 | } else { |
378 | found = 0; | |
379 | } | |
380 | break; | |
381 | case HPI_CONTROL_CHANNEL_MODE: | |
382 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | |
3285ea10 | 383 | phr->u.c.param1 = pC->u.mode.mode; |
719f82d3 EB |
384 | else |
385 | found = 0; | |
386 | break; | |
387 | case HPI_CONTROL_LEVEL: | |
388 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
389 | phr->u.c.an_log_value[0] = pC->u.level.an_log[0]; |
390 | phr->u.c.an_log_value[1] = pC->u.level.an_log[1]; | |
719f82d3 EB |
391 | } else |
392 | found = 0; | |
393 | break; | |
394 | case HPI_CONTROL_TUNER: | |
3ee317fe | 395 | if (phm->u.c.attribute == HPI_TUNER_FREQ) |
3285ea10 | 396 | phr->u.c.param1 = pC->u.tuner.freq_ink_hz; |
3ee317fe | 397 | else if (phm->u.c.attribute == HPI_TUNER_BAND) |
3285ea10 EB |
398 | phr->u.c.param1 = pC->u.tuner.band; |
399 | else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG) | |
400 | if (pC->u.tuner.s_level_avg == | |
401 | HPI_CACHE_INVALID_SHORT) { | |
402 | phr->u.cu.tuner.s_level = 0; | |
36ed8bdd EB |
403 | phr->error = |
404 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
405 | } else | |
3285ea10 EB |
406 | phr->u.cu.tuner.s_level = |
407 | pC->u.tuner.s_level_avg; | |
3ee317fe EB |
408 | else |
409 | found = 0; | |
719f82d3 EB |
410 | break; |
411 | case HPI_CONTROL_AESEBU_RECEIVER: | |
412 | if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) | |
413 | phr->u.c.param1 = pC->u.aes3rx.error_status; | |
414 | else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | |
3285ea10 | 415 | phr->u.c.param1 = pC->u.aes3rx.format; |
719f82d3 EB |
416 | else |
417 | found = 0; | |
418 | break; | |
419 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
420 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | |
421 | phr->u.c.param1 = pC->u.aes3tx.format; | |
422 | else | |
423 | found = 0; | |
424 | break; | |
425 | case HPI_CONTROL_TONEDETECTOR: | |
426 | if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) | |
427 | phr->u.c.param1 = pC->u.tone.state; | |
428 | else | |
429 | found = 0; | |
430 | break; | |
431 | case HPI_CONTROL_SILENCEDETECTOR: | |
432 | if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { | |
433 | phr->u.c.param1 = pC->u.silence.state; | |
719f82d3 EB |
434 | } else |
435 | found = 0; | |
436 | break; | |
437 | case HPI_CONTROL_MICROPHONE: | |
438 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 439 | phr->u.c.param1 = pC->u.microphone.phantom_state; |
719f82d3 EB |
440 | else |
441 | found = 0; | |
442 | break; | |
443 | case HPI_CONTROL_SAMPLECLOCK: | |
444 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | |
445 | phr->u.c.param1 = pC->u.clk.source; | |
446 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { | |
447 | if (pC->u.clk.source_index == | |
3285ea10 | 448 | HPI_CACHE_INVALID_UINT16) { |
719f82d3 | 449 | phr->u.c.param1 = 0; |
36ed8bdd EB |
450 | phr->error = |
451 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
719f82d3 EB |
452 | } else |
453 | phr->u.c.param1 = pC->u.clk.source_index; | |
454 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
455 | phr->u.c.param1 = pC->u.clk.sample_rate; | |
456 | else | |
457 | found = 0; | |
458 | break; | |
3285ea10 EB |
459 | case HPI_CONTROL_PAD:{ |
460 | struct hpi_control_cache_pad *p_pad; | |
c1464a88 | 461 | p_pad = (struct hpi_control_cache_pad *)pC; |
719f82d3 | 462 | |
3285ea10 EB |
463 | if (!(p_pad->field_valid_flags & (1 << |
464 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
465 | attribute)))) { | |
719f82d3 EB |
466 | phr->error = |
467 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
468 | break; | |
469 | } | |
470 | ||
3285ea10 EB |
471 | if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) |
472 | phr->u.c.param1 = p_pad->pI; | |
473 | else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) | |
474 | phr->u.c.param1 = p_pad->pTY; | |
475 | else { | |
476 | unsigned int index = | |
477 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
478 | attribute) - 1; | |
479 | unsigned int offset = phm->u.c.param1; | |
480 | unsigned int pad_string_len, field_size; | |
481 | char *pad_string; | |
482 | unsigned int tocopy; | |
483 | ||
484 | if (index > ARRAY_SIZE(pad_desc) - 1) { | |
485 | phr->error = | |
486 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
487 | break; | |
488 | } | |
489 | ||
490 | pad_string = | |
491 | ((char *)p_pad) + | |
492 | pad_desc[index].offset; | |
493 | field_size = pad_desc[index].field_size; | |
494 | /* Ensure null terminator */ | |
495 | pad_string[field_size - 1] = 0; | |
496 | ||
497 | pad_string_len = strlen(pad_string) + 1; | |
498 | ||
499 | if (offset > pad_string_len) { | |
500 | phr->error = | |
501 | HPI_ERROR_INVALID_CONTROL_VALUE; | |
502 | break; | |
503 | } | |
504 | ||
505 | tocopy = pad_string_len - offset; | |
506 | if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) | |
507 | tocopy = sizeof(phr->u.cu.chars8. | |
508 | sz_data); | |
509 | ||
510 | memcpy(phr->u.cu.chars8.sz_data, | |
511 | &pad_string[offset], tocopy); | |
512 | ||
513 | phr->u.cu.chars8.remaining_chars = | |
514 | pad_string_len - offset - tocopy; | |
719f82d3 | 515 | } |
719f82d3 EB |
516 | } |
517 | break; | |
518 | default: | |
519 | found = 0; | |
520 | break; | |
521 | } | |
522 | ||
3285ea10 EB |
523 | HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", |
524 | found ? "Cached" : "Uncached", phm->adapter_index, | |
c1464a88 EB |
525 | pC->u.i.control_index, pC->u.i.control_type, |
526 | phm->u.c.attribute); | |
719f82d3 | 527 | |
8637bc94 | 528 | if (found) { |
3d0591ee | 529 | phr->size = (u16)response_size; |
8637bc94 EB |
530 | phr->type = HPI_TYPE_RESPONSE; |
531 | phr->object = phm->object; | |
532 | phr->function = phm->function; | |
533 | } | |
719f82d3 EB |
534 | |
535 | return found; | |
536 | } | |
537 | ||
c1464a88 | 538 | short hpi_check_control_cache(struct hpi_control_cache *p_cache, |
719f82d3 EB |
539 | struct hpi_message *phm, struct hpi_response *phr) |
540 | { | |
719f82d3 EB |
541 | struct hpi_control_cache_info *pI; |
542 | ||
3285ea10 EB |
543 | if (!find_control(phm->obj_index, p_cache, &pI)) { |
544 | HPI_DEBUG_LOG(VERBOSE, | |
545 | "HPICMN find_control() failed for adap %d\n", | |
546 | phm->adapter_index); | |
c1464a88 | 547 | return 0; |
3285ea10 | 548 | } |
719f82d3 | 549 | |
c1464a88 EB |
550 | phr->error = 0; |
551 | phr->specific_error = 0; | |
552 | phr->version = 0; | |
553 | ||
554 | return hpi_check_control_cache_single((struct hpi_control_cache_single | |
555 | *)pI, phm, phr); | |
556 | } | |
557 | ||
558 | /** Updates the cache with Set values. | |
719f82d3 | 559 | |
c1464a88 EB |
560 | Only update if no error. |
561 | Volume and Level return the limited values in the response, so use these | |
562 | Multiplexer does so use sent values | |
563 | */ | |
564 | void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single | |
565 | *pC, struct hpi_message *phm, struct hpi_response *phr) | |
566 | { | |
567 | switch (pC->u.i.control_type) { | |
719f82d3 EB |
568 | case HPI_CONTROL_VOLUME: |
569 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
570 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
571 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
fc3a3990 EB |
572 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
573 | if (phm->u.c.param1) | |
574 | pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED; | |
575 | else | |
576 | pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED; | |
719f82d3 EB |
577 | } |
578 | break; | |
579 | case HPI_CONTROL_MULTIPLEXER: | |
580 | /* mux does not return its setting on Set command. */ | |
719f82d3 | 581 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { |
3285ea10 EB |
582 | pC->u.mux.source_node_type = (u16)phm->u.c.param1; |
583 | pC->u.mux.source_node_index = (u16)phm->u.c.param2; | |
719f82d3 EB |
584 | } |
585 | break; | |
586 | case HPI_CONTROL_CHANNEL_MODE: | |
587 | /* mode does not return its setting on Set command. */ | |
719f82d3 | 588 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) |
3285ea10 | 589 | pC->u.mode.mode = (u16)phm->u.c.param1; |
719f82d3 EB |
590 | break; |
591 | case HPI_CONTROL_LEVEL: | |
592 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
593 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
594 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
719f82d3 EB |
595 | } |
596 | break; | |
597 | case HPI_CONTROL_MICROPHONE: | |
598 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 599 | pC->u.microphone.phantom_state = (u16)phm->u.c.param1; |
719f82d3 EB |
600 | break; |
601 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
719f82d3 EB |
602 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) |
603 | pC->u.aes3tx.format = phm->u.c.param1; | |
604 | break; | |
605 | case HPI_CONTROL_AESEBU_RECEIVER: | |
719f82d3 | 606 | if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) |
3285ea10 | 607 | pC->u.aes3rx.format = phm->u.c.param1; |
719f82d3 EB |
608 | break; |
609 | case HPI_CONTROL_SAMPLECLOCK: | |
719f82d3 EB |
610 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) |
611 | pC->u.clk.source = (u16)phm->u.c.param1; | |
612 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) | |
613 | pC->u.clk.source_index = (u16)phm->u.c.param1; | |
614 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
615 | pC->u.clk.sample_rate = phm->u.c.param1; | |
616 | break; | |
617 | default: | |
618 | break; | |
619 | } | |
620 | } | |
621 | ||
c1464a88 EB |
622 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, |
623 | struct hpi_message *phm, struct hpi_response *phr) | |
624 | { | |
625 | struct hpi_control_cache_single *pC; | |
626 | struct hpi_control_cache_info *pI; | |
627 | ||
628 | if (phr->error) | |
629 | return; | |
630 | ||
631 | if (!find_control(phm->obj_index, p_cache, &pI)) { | |
632 | HPI_DEBUG_LOG(VERBOSE, | |
633 | "HPICMN find_control() failed for adap %d\n", | |
634 | phm->adapter_index); | |
635 | return; | |
636 | } | |
637 | ||
638 | /* pC is the default cached control strucure. | |
639 | May be cast to something else in the following switch statement. | |
640 | */ | |
641 | pC = (struct hpi_control_cache_single *)pI; | |
642 | ||
643 | hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr); | |
644 | } | |
645 | ||
42258dab EB |
646 | /** Allocate control cache. |
647 | ||
648 | \return Cache pointer, or NULL if allocation fails. | |
649 | */ | |
4704998e EB |
650 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, |
651 | const u32 size_in_bytes, u8 *p_dsp_control_buffer) | |
719f82d3 EB |
652 | { |
653 | struct hpi_control_cache *p_cache = | |
654 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | |
fd0977d0 JJ |
655 | if (!p_cache) |
656 | return NULL; | |
4704998e | 657 | |
c1464a88 EB |
658 | p_cache->p_info = |
659 | kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL); | |
fd0977d0 JJ |
660 | if (!p_cache->p_info) { |
661 | kfree(p_cache); | |
662 | return NULL; | |
663 | } | |
c1464a88 | 664 | |
719f82d3 | 665 | p_cache->cache_size_in_bytes = size_in_bytes; |
4704998e EB |
666 | p_cache->control_count = control_count; |
667 | p_cache->p_cache = p_dsp_control_buffer; | |
719f82d3 | 668 | p_cache->init = 0; |
719f82d3 EB |
669 | return p_cache; |
670 | } | |
671 | ||
672 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | |
673 | { | |
3285ea10 | 674 | if (p_cache) { |
719f82d3 | 675 | kfree(p_cache->p_info); |
719f82d3 EB |
676 | kfree(p_cache); |
677 | } | |
678 | } | |
679 | ||
680 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | |
681 | { | |
3285ea10 | 682 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0); |
719f82d3 EB |
683 | |
684 | switch (phm->function) { | |
685 | case HPI_SUBSYS_OPEN: | |
686 | case HPI_SUBSYS_CLOSE: | |
687 | case HPI_SUBSYS_DRIVER_UNLOAD: | |
719f82d3 EB |
688 | break; |
689 | case HPI_SUBSYS_DRIVER_LOAD: | |
690 | wipe_adapter_list(); | |
691 | hpios_alistlock_init(&adapters); | |
719f82d3 | 692 | break; |
3285ea10 EB |
693 | case HPI_SUBSYS_GET_ADAPTER: |
694 | subsys_get_adapter(phm, phr); | |
695 | break; | |
696 | case HPI_SUBSYS_GET_NUM_ADAPTERS: | |
697 | phr->u.s.num_adapters = adapters.gw_num_adapters; | |
719f82d3 EB |
698 | break; |
699 | case HPI_SUBSYS_CREATE_ADAPTER: | |
719f82d3 EB |
700 | break; |
701 | default: | |
702 | phr->error = HPI_ERROR_INVALID_FUNC; | |
703 | break; | |
704 | } | |
705 | } | |
706 | ||
707 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | |
708 | { | |
709 | switch (phm->type) { | |
82b5774f | 710 | case HPI_TYPE_REQUEST: |
719f82d3 EB |
711 | switch (phm->object) { |
712 | case HPI_OBJ_SUBSYSTEM: | |
713 | subsys_message(phm, phr); | |
714 | break; | |
715 | } | |
716 | break; | |
717 | ||
718 | default: | |
719 | phr->error = HPI_ERROR_INVALID_TYPE; | |
720 | break; | |
721 | } | |
722 | } |