Commit | Line | Data |
---|---|---|
719f82d3 EB |
1 | /****************************************************************************** |
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" | |
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) { |
1528fbb5 EB |
60 | HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", |
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; | |
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 | ||
90 | unlock: | |
3285ea10 | 91 | hpios_alistlock_unlock(&adapters); |
719f82d3 EB |
92 | return retval; |
93 | } | |
94 | ||
95 | void hpi_delete_adapter(struct hpi_adapter_obj *pao) | |
96 | { | |
3285ea10 EB |
97 | if (!pao->adapter_type) { |
98 | HPI_DEBUG_LOG(ERROR, "removing null adapter?\n"); | |
99 | return; | |
100 | } | |
719f82d3 EB |
101 | |
102 | hpios_alistlock_lock(&adapters); | |
3285ea10 EB |
103 | 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); | |
719f82d3 EB |
107 | } |
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 | */ | |
114 | struct 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) { | |
1528fbb5 | 119 | HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n", |
719f82d3 EB |
120 | 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 | **/ | |
3285ea10 | 145 | static void wipe_adapter_list(void) |
719f82d3 EB |
146 | { |
147 | memset(&adapters, 0, sizeof(adapters)); | |
148 | } | |
149 | ||
3285ea10 EB |
150 | static void subsys_get_adapter(struct hpi_message *phm, |
151 | struct hpi_response *phr) | |
719f82d3 | 152 | { |
3285ea10 EB |
153 | int count = phm->obj_index; |
154 | u16 index = 0; | |
719f82d3 | 155 | |
3285ea10 EB |
156 | /* find the nCount'th nonzero adapter in array */ |
157 | for (index = 0; index < HPI_MAX_ADAPTERS; index++) { | |
158 | if (adapters.adapter[index].adapter_type) { | |
4704998e | 159 | if (!count) |
3285ea10 EB |
160 | break; |
161 | count--; | |
719f82d3 | 162 | } |
719f82d3 EB |
163 | } |
164 | ||
3285ea10 EB |
165 | 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 | } | |
719f82d3 EB |
174 | } |
175 | ||
176 | static 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; | |
719f82d3 | 182 | |
3285ea10 EB |
183 | 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", | |
719f82d3 EB |
195 | 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 *) | |
3285ea10 EB |
199 | &p_master_cache[byte_count]; |
200 | ||
201 | if (!info->size_in32bit_words) { | |
4704998e | 202 | if (!i) { |
ffdb5787 EB |
203 | HPI_DEBUG_LOG(INFO, |
204 | "adap %d cache not ready?\n", | |
205 | pC->adap_idx); | |
206 | return 0; | |
207 | } | |
1528fbb5 EB |
208 | /* The cache is invalid. |
209 | * Minimum valid entry size is | |
210 | * sizeof(struct hpi_control_cache_info) | |
211 | */ | |
3285ea10 | 212 | HPI_DEBUG_LOG(ERROR, |
ffdb5787 EB |
213 | "adap %d zero size cache entry %d\n", |
214 | pC->adap_idx, i); | |
3285ea10 EB |
215 | break; |
216 | } | |
719f82d3 EB |
217 | |
218 | if (info->control_type) { | |
3285ea10 | 219 | pC->p_info[info->control_index] = info; |
719f82d3 | 220 | cached++; |
3285ea10 EB |
221 | } else /* dummy cache entry */ |
222 | pC->p_info[info->control_index] = NULL; | |
719f82d3 | 223 | |
3285ea10 | 224 | byte_count += info->size_in32bit_words * 4; |
719f82d3 EB |
225 | |
226 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
227 | "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 | ||
1528fbb5 EB |
232 | /* 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 | */ | |
3285ea10 EB |
236 | 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; | |
719f82d3 | 241 | } |
3285ea10 EB |
242 | |
243 | if (byte_count != pC->cache_size_in_bytes) | |
244 | HPI_DEBUG_LOG(WARNING, | |
1528fbb5 | 245 | "adap %d bytecount %d != cache size %d\n", |
ffdb5787 | 246 | pC->adap_idx, byte_count, |
3285ea10 EB |
247 | pC->cache_size_in_bytes); |
248 | else | |
249 | HPI_DEBUG_LOG(DEBUG, | |
1528fbb5 | 250 | "adap %d cache good, bytecount == cache size = %d\n", |
ffdb5787 | 251 | pC->adap_idx, byte_count); |
3285ea10 | 252 | |
1528fbb5 | 253 | pC->init = (u16)cached; |
719f82d3 EB |
254 | } |
255 | return pC->init; | |
256 | } | |
257 | ||
258 | /** Find a control. | |
259 | */ | |
3285ea10 EB |
260 | static short find_control(u16 control_index, |
261 | struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI) | |
719f82d3 | 262 | { |
719f82d3 EB |
263 | if (!control_cache_alloc_check(p_cache)) { |
264 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
265 | "control_cache_alloc_check() failed %d\n", |
266 | control_index); | |
719f82d3 EB |
267 | return 0; |
268 | } | |
269 | ||
3285ea10 | 270 | *pI = p_cache->p_info[control_index]; |
719f82d3 | 271 | if (!*pI) { |
3285ea10 EB |
272 | HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", |
273 | control_index); | |
719f82d3 EB |
274 | return 0; |
275 | } else { | |
276 | HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", | |
277 | (*pI)->control_type); | |
278 | } | |
279 | return 1; | |
280 | } | |
281 | ||
719f82d3 EB |
282 | /* allow unified treatment of several string fields within struct */ |
283 | #define HPICMN_PAD_OFS_AND_SIZE(m) {\ | |
284 | offsetof(struct hpi_control_cache_pad, m), \ | |
285 | sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } | |
286 | ||
287 | struct pad_ofs_size { | |
288 | unsigned int offset; | |
289 | unsigned int field_size; | |
290 | }; | |
291 | ||
292 | static struct pad_ofs_size pad_desc[] = { | |
293 | HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ | |
294 | HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ | |
295 | HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ | |
296 | HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ | |
297 | }; | |
298 | ||
299 | /** CheckControlCache checks the cache and fills the struct hpi_response | |
300 | * accordingly. It returns one if a cache hit occurred, zero otherwise. | |
301 | */ | |
302 | short hpi_check_control_cache(struct hpi_control_cache *p_cache, | |
303 | struct hpi_message *phm, struct hpi_response *phr) | |
304 | { | |
305 | short found = 1; | |
719f82d3 EB |
306 | struct hpi_control_cache_info *pI; |
307 | struct hpi_control_cache_single *pC; | |
308 | struct hpi_control_cache_pad *p_pad; | |
309 | ||
3285ea10 EB |
310 | if (!find_control(phm->obj_index, p_cache, &pI)) { |
311 | HPI_DEBUG_LOG(VERBOSE, | |
312 | "HPICMN find_control() failed for adap %d\n", | |
313 | phm->adapter_index); | |
719f82d3 | 314 | return 0; |
3285ea10 | 315 | } |
719f82d3 EB |
316 | |
317 | phr->error = 0; | |
318 | ||
319 | /* pC is the default cached control strucure. May be cast to | |
320 | something else in the following switch statement. | |
321 | */ | |
322 | pC = (struct hpi_control_cache_single *)pI; | |
323 | p_pad = (struct hpi_control_cache_pad *)pI; | |
324 | ||
325 | switch (pI->control_type) { | |
326 | ||
327 | case HPI_CONTROL_METER: | |
328 | if (phm->u.c.attribute == HPI_METER_PEAK) { | |
3285ea10 EB |
329 | phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; |
330 | phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; | |
719f82d3 | 331 | } else if (phm->u.c.attribute == HPI_METER_RMS) { |
3285ea10 EB |
332 | if (pC->u.meter.an_logRMS[0] == |
333 | HPI_CACHE_INVALID_SHORT) { | |
334 | phr->error = | |
335 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
336 | phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; | |
337 | phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; | |
338 | } else { | |
339 | phr->u.c.an_log_value[0] = | |
340 | pC->u.meter.an_logRMS[0]; | |
341 | phr->u.c.an_log_value[1] = | |
342 | pC->u.meter.an_logRMS[1]; | |
343 | } | |
719f82d3 EB |
344 | } else |
345 | found = 0; | |
346 | break; | |
347 | case HPI_CONTROL_VOLUME: | |
348 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
349 | phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; |
350 | phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; | |
719f82d3 EB |
351 | } else |
352 | found = 0; | |
353 | break; | |
354 | case HPI_CONTROL_MULTIPLEXER: | |
355 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | |
3285ea10 EB |
356 | phr->u.c.param1 = pC->u.mux.source_node_type; |
357 | phr->u.c.param2 = pC->u.mux.source_node_index; | |
719f82d3 EB |
358 | } else { |
359 | found = 0; | |
360 | } | |
361 | break; | |
362 | case HPI_CONTROL_CHANNEL_MODE: | |
363 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | |
3285ea10 | 364 | phr->u.c.param1 = pC->u.mode.mode; |
719f82d3 EB |
365 | else |
366 | found = 0; | |
367 | break; | |
368 | case HPI_CONTROL_LEVEL: | |
369 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
370 | phr->u.c.an_log_value[0] = pC->u.level.an_log[0]; |
371 | phr->u.c.an_log_value[1] = pC->u.level.an_log[1]; | |
719f82d3 EB |
372 | } else |
373 | found = 0; | |
374 | break; | |
375 | case HPI_CONTROL_TUNER: | |
3ee317fe | 376 | if (phm->u.c.attribute == HPI_TUNER_FREQ) |
3285ea10 | 377 | phr->u.c.param1 = pC->u.tuner.freq_ink_hz; |
3ee317fe | 378 | else if (phm->u.c.attribute == HPI_TUNER_BAND) |
3285ea10 EB |
379 | phr->u.c.param1 = pC->u.tuner.band; |
380 | else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG) | |
381 | if (pC->u.tuner.s_level_avg == | |
382 | HPI_CACHE_INVALID_SHORT) { | |
383 | phr->u.cu.tuner.s_level = 0; | |
36ed8bdd EB |
384 | phr->error = |
385 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
386 | } else | |
3285ea10 EB |
387 | phr->u.cu.tuner.s_level = |
388 | pC->u.tuner.s_level_avg; | |
3ee317fe EB |
389 | else |
390 | found = 0; | |
719f82d3 EB |
391 | break; |
392 | case HPI_CONTROL_AESEBU_RECEIVER: | |
393 | if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) | |
394 | phr->u.c.param1 = pC->u.aes3rx.error_status; | |
395 | else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | |
3285ea10 | 396 | phr->u.c.param1 = pC->u.aes3rx.format; |
719f82d3 EB |
397 | else |
398 | found = 0; | |
399 | break; | |
400 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
401 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | |
402 | phr->u.c.param1 = pC->u.aes3tx.format; | |
403 | else | |
404 | found = 0; | |
405 | break; | |
406 | case HPI_CONTROL_TONEDETECTOR: | |
407 | if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) | |
408 | phr->u.c.param1 = pC->u.tone.state; | |
409 | else | |
410 | found = 0; | |
411 | break; | |
412 | case HPI_CONTROL_SILENCEDETECTOR: | |
413 | if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { | |
414 | phr->u.c.param1 = pC->u.silence.state; | |
719f82d3 EB |
415 | } else |
416 | found = 0; | |
417 | break; | |
418 | case HPI_CONTROL_MICROPHONE: | |
419 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 420 | phr->u.c.param1 = pC->u.microphone.phantom_state; |
719f82d3 EB |
421 | else |
422 | found = 0; | |
423 | break; | |
424 | case HPI_CONTROL_SAMPLECLOCK: | |
425 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | |
426 | phr->u.c.param1 = pC->u.clk.source; | |
427 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { | |
428 | if (pC->u.clk.source_index == | |
3285ea10 | 429 | HPI_CACHE_INVALID_UINT16) { |
719f82d3 | 430 | phr->u.c.param1 = 0; |
36ed8bdd EB |
431 | phr->error = |
432 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
719f82d3 EB |
433 | } else |
434 | phr->u.c.param1 = pC->u.clk.source_index; | |
435 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
436 | phr->u.c.param1 = pC->u.clk.sample_rate; | |
437 | else | |
438 | found = 0; | |
439 | break; | |
3285ea10 EB |
440 | case HPI_CONTROL_PAD:{ |
441 | struct hpi_control_cache_pad *p_pad; | |
442 | p_pad = (struct hpi_control_cache_pad *)pI; | |
719f82d3 | 443 | |
3285ea10 EB |
444 | if (!(p_pad->field_valid_flags & (1 << |
445 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
446 | attribute)))) { | |
719f82d3 EB |
447 | phr->error = |
448 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
449 | break; | |
450 | } | |
451 | ||
3285ea10 EB |
452 | if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) |
453 | phr->u.c.param1 = p_pad->pI; | |
454 | else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) | |
455 | phr->u.c.param1 = p_pad->pTY; | |
456 | else { | |
457 | unsigned int index = | |
458 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
459 | attribute) - 1; | |
460 | unsigned int offset = phm->u.c.param1; | |
461 | unsigned int pad_string_len, field_size; | |
462 | char *pad_string; | |
463 | unsigned int tocopy; | |
464 | ||
465 | if (index > ARRAY_SIZE(pad_desc) - 1) { | |
466 | phr->error = | |
467 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
468 | break; | |
469 | } | |
470 | ||
471 | pad_string = | |
472 | ((char *)p_pad) + | |
473 | pad_desc[index].offset; | |
474 | field_size = pad_desc[index].field_size; | |
475 | /* Ensure null terminator */ | |
476 | pad_string[field_size - 1] = 0; | |
477 | ||
478 | pad_string_len = strlen(pad_string) + 1; | |
479 | ||
480 | if (offset > pad_string_len) { | |
481 | phr->error = | |
482 | HPI_ERROR_INVALID_CONTROL_VALUE; | |
483 | break; | |
484 | } | |
485 | ||
486 | tocopy = pad_string_len - offset; | |
487 | if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) | |
488 | tocopy = sizeof(phr->u.cu.chars8. | |
489 | sz_data); | |
490 | ||
491 | memcpy(phr->u.cu.chars8.sz_data, | |
492 | &pad_string[offset], tocopy); | |
493 | ||
494 | phr->u.cu.chars8.remaining_chars = | |
495 | pad_string_len - offset - tocopy; | |
719f82d3 | 496 | } |
719f82d3 EB |
497 | } |
498 | break; | |
499 | default: | |
500 | found = 0; | |
501 | break; | |
502 | } | |
503 | ||
3285ea10 EB |
504 | HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", |
505 | found ? "Cached" : "Uncached", phm->adapter_index, | |
506 | pI->control_index, pI->control_type, phm->u.c.attribute); | |
719f82d3 EB |
507 | |
508 | if (found) | |
509 | phr->size = | |
510 | sizeof(struct hpi_response_header) + | |
511 | sizeof(struct hpi_control_res); | |
512 | ||
513 | return found; | |
514 | } | |
515 | ||
516 | /** Updates the cache with Set values. | |
517 | ||
518 | Only update if no error. | |
519 | Volume and Level return the limited values in the response, so use these | |
520 | Multiplexer does so use sent values | |
521 | */ | |
3285ea10 | 522 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, |
719f82d3 EB |
523 | struct hpi_message *phm, struct hpi_response *phr) |
524 | { | |
719f82d3 EB |
525 | struct hpi_control_cache_single *pC; |
526 | struct hpi_control_cache_info *pI; | |
527 | ||
3ee317fe EB |
528 | if (phr->error) |
529 | return; | |
530 | ||
3285ea10 EB |
531 | if (!find_control(phm->obj_index, p_cache, &pI)) { |
532 | HPI_DEBUG_LOG(VERBOSE, | |
533 | "HPICMN find_control() failed for adap %d\n", | |
534 | phm->adapter_index); | |
719f82d3 | 535 | return; |
3285ea10 | 536 | } |
719f82d3 EB |
537 | |
538 | /* pC is the default cached control strucure. | |
539 | May be cast to something else in the following switch statement. | |
540 | */ | |
541 | pC = (struct hpi_control_cache_single *)pI; | |
542 | ||
543 | switch (pI->control_type) { | |
544 | case HPI_CONTROL_VOLUME: | |
545 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
546 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
547 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
719f82d3 EB |
548 | } |
549 | break; | |
550 | case HPI_CONTROL_MULTIPLEXER: | |
551 | /* mux does not return its setting on Set command. */ | |
719f82d3 | 552 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { |
3285ea10 EB |
553 | pC->u.mux.source_node_type = (u16)phm->u.c.param1; |
554 | pC->u.mux.source_node_index = (u16)phm->u.c.param2; | |
719f82d3 EB |
555 | } |
556 | break; | |
557 | case HPI_CONTROL_CHANNEL_MODE: | |
558 | /* mode does not return its setting on Set command. */ | |
719f82d3 | 559 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) |
3285ea10 | 560 | pC->u.mode.mode = (u16)phm->u.c.param1; |
719f82d3 EB |
561 | break; |
562 | case HPI_CONTROL_LEVEL: | |
563 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
564 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
565 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
719f82d3 EB |
566 | } |
567 | break; | |
568 | case HPI_CONTROL_MICROPHONE: | |
569 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 570 | pC->u.microphone.phantom_state = (u16)phm->u.c.param1; |
719f82d3 EB |
571 | break; |
572 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
719f82d3 EB |
573 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) |
574 | pC->u.aes3tx.format = phm->u.c.param1; | |
575 | break; | |
576 | case HPI_CONTROL_AESEBU_RECEIVER: | |
719f82d3 | 577 | if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) |
3285ea10 | 578 | pC->u.aes3rx.format = phm->u.c.param1; |
719f82d3 EB |
579 | break; |
580 | case HPI_CONTROL_SAMPLECLOCK: | |
719f82d3 EB |
581 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) |
582 | pC->u.clk.source = (u16)phm->u.c.param1; | |
583 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) | |
584 | pC->u.clk.source_index = (u16)phm->u.c.param1; | |
585 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
586 | pC->u.clk.sample_rate = phm->u.c.param1; | |
587 | break; | |
588 | default: | |
589 | break; | |
590 | } | |
591 | } | |
592 | ||
4704998e EB |
593 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, |
594 | const u32 size_in_bytes, u8 *p_dsp_control_buffer) | |
719f82d3 EB |
595 | { |
596 | struct hpi_control_cache *p_cache = | |
597 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | |
fd0977d0 JJ |
598 | if (!p_cache) |
599 | return NULL; | |
4704998e | 600 | |
fd0977d0 | 601 | p_cache->p_info = |
4704998e | 602 | kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL); |
fd0977d0 JJ |
603 | if (!p_cache->p_info) { |
604 | kfree(p_cache); | |
605 | return NULL; | |
606 | } | |
4704998e | 607 | memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count); |
719f82d3 | 608 | p_cache->cache_size_in_bytes = size_in_bytes; |
4704998e EB |
609 | p_cache->control_count = control_count; |
610 | p_cache->p_cache = p_dsp_control_buffer; | |
719f82d3 | 611 | p_cache->init = 0; |
719f82d3 EB |
612 | return p_cache; |
613 | } | |
614 | ||
615 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | |
616 | { | |
3285ea10 | 617 | if (p_cache) { |
719f82d3 | 618 | kfree(p_cache->p_info); |
719f82d3 EB |
619 | kfree(p_cache); |
620 | } | |
621 | } | |
622 | ||
623 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | |
624 | { | |
3285ea10 | 625 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0); |
719f82d3 EB |
626 | |
627 | switch (phm->function) { | |
628 | case HPI_SUBSYS_OPEN: | |
629 | case HPI_SUBSYS_CLOSE: | |
630 | case HPI_SUBSYS_DRIVER_UNLOAD: | |
719f82d3 EB |
631 | break; |
632 | case HPI_SUBSYS_DRIVER_LOAD: | |
633 | wipe_adapter_list(); | |
634 | hpios_alistlock_init(&adapters); | |
719f82d3 | 635 | break; |
3285ea10 EB |
636 | case HPI_SUBSYS_GET_ADAPTER: |
637 | subsys_get_adapter(phm, phr); | |
638 | break; | |
639 | case HPI_SUBSYS_GET_NUM_ADAPTERS: | |
640 | phr->u.s.num_adapters = adapters.gw_num_adapters; | |
719f82d3 EB |
641 | break; |
642 | case HPI_SUBSYS_CREATE_ADAPTER: | |
643 | case HPI_SUBSYS_DELETE_ADAPTER: | |
719f82d3 EB |
644 | break; |
645 | default: | |
646 | phr->error = HPI_ERROR_INVALID_FUNC; | |
647 | break; | |
648 | } | |
649 | } | |
650 | ||
651 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | |
652 | { | |
653 | switch (phm->type) { | |
654 | case HPI_TYPE_MESSAGE: | |
655 | switch (phm->object) { | |
656 | case HPI_OBJ_SUBSYSTEM: | |
657 | subsys_message(phm, phr); | |
658 | break; | |
659 | } | |
660 | break; | |
661 | ||
662 | default: | |
663 | phr->error = HPI_ERROR_INVALID_TYPE; | |
664 | break; | |
665 | } | |
666 | } |