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) { | |
d6f1c1c3 EB |
81 | int a; |
82 | for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) { | |
83 | if (!adapters.adapter[a].adapter_type) { | |
84 | HPI_DEBUG_LOG(WARNING, | |
85 | "ASI%X duplicate index %d moved to %d\n", | |
86 | pao->adapter_type, pao->index, a); | |
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 | { | |
3285ea10 EB |
107 | if (!pao->adapter_type) { |
108 | HPI_DEBUG_LOG(ERROR, "removing null adapter?\n"); | |
109 | return; | |
110 | } | |
719f82d3 EB |
111 | |
112 | hpios_alistlock_lock(&adapters); | |
3285ea10 EB |
113 | if (adapters.adapter[pao->index].adapter_type) |
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]; | |
135 | if (pao->adapter_type != 0) { | |
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++) { | |
168 | if (adapters.adapter[index].adapter_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; | |
2f918a64 | 177 | phr->u.s.adapter_type = adapters.adapter[index].adapter_type; |
3285ea10 EB |
178 | } else { |
179 | phr->u.s.adapter_index = 0; | |
2f918a64 | 180 | phr->u.s.adapter_type = 0; |
3285ea10 EB |
181 | phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER; |
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 EB |
208 | &p_master_cache[byte_count]; |
209 | ||
210 | if (!info->size_in32bit_words) { | |
4704998e | 211 | if (!i) { |
ffdb5787 EB |
212 | HPI_DEBUG_LOG(INFO, |
213 | "adap %d cache not ready?\n", | |
214 | pC->adap_idx); | |
215 | return 0; | |
216 | } | |
1528fbb5 EB |
217 | /* The cache is invalid. |
218 | * Minimum valid entry size is | |
219 | * sizeof(struct hpi_control_cache_info) | |
220 | */ | |
3285ea10 | 221 | HPI_DEBUG_LOG(ERROR, |
ffdb5787 EB |
222 | "adap %d zero size cache entry %d\n", |
223 | pC->adap_idx, i); | |
3285ea10 EB |
224 | break; |
225 | } | |
719f82d3 EB |
226 | |
227 | if (info->control_type) { | |
3285ea10 | 228 | pC->p_info[info->control_index] = info; |
719f82d3 | 229 | cached++; |
3285ea10 EB |
230 | } else /* dummy cache entry */ |
231 | pC->p_info[info->control_index] = NULL; | |
719f82d3 | 232 | |
3285ea10 | 233 | byte_count += info->size_in32bit_words * 4; |
719f82d3 EB |
234 | |
235 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
236 | "cached %d, pinfo %p index %d type %d size %d\n", |
237 | cached, pC->p_info[info->control_index], | |
238 | info->control_index, info->control_type, | |
239 | info->size_in32bit_words); | |
240 | ||
1528fbb5 EB |
241 | /* quit loop early if whole cache has been scanned. |
242 | * dwControlCount is the maximum possible entries | |
243 | * but some may be absent from the cache | |
244 | */ | |
3285ea10 EB |
245 | if (byte_count >= pC->cache_size_in_bytes) |
246 | break; | |
247 | /* have seen last control index */ | |
248 | if (info->control_index == pC->control_count - 1) | |
249 | break; | |
719f82d3 | 250 | } |
3285ea10 EB |
251 | |
252 | if (byte_count != pC->cache_size_in_bytes) | |
253 | HPI_DEBUG_LOG(WARNING, | |
1528fbb5 | 254 | "adap %d bytecount %d != cache size %d\n", |
ffdb5787 | 255 | pC->adap_idx, byte_count, |
3285ea10 EB |
256 | pC->cache_size_in_bytes); |
257 | else | |
258 | HPI_DEBUG_LOG(DEBUG, | |
1528fbb5 | 259 | "adap %d cache good, bytecount == cache size = %d\n", |
ffdb5787 | 260 | pC->adap_idx, byte_count); |
3285ea10 | 261 | |
1528fbb5 | 262 | pC->init = (u16)cached; |
719f82d3 EB |
263 | } |
264 | return pC->init; | |
265 | } | |
266 | ||
267 | /** Find a control. | |
268 | */ | |
3285ea10 EB |
269 | static short find_control(u16 control_index, |
270 | struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI) | |
719f82d3 | 271 | { |
719f82d3 EB |
272 | if (!control_cache_alloc_check(p_cache)) { |
273 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
274 | "control_cache_alloc_check() failed %d\n", |
275 | control_index); | |
719f82d3 EB |
276 | return 0; |
277 | } | |
278 | ||
3285ea10 | 279 | *pI = p_cache->p_info[control_index]; |
719f82d3 | 280 | if (!*pI) { |
3285ea10 EB |
281 | HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", |
282 | control_index); | |
719f82d3 EB |
283 | return 0; |
284 | } else { | |
285 | HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", | |
286 | (*pI)->control_type); | |
287 | } | |
288 | return 1; | |
289 | } | |
290 | ||
719f82d3 EB |
291 | /* allow unified treatment of several string fields within struct */ |
292 | #define HPICMN_PAD_OFS_AND_SIZE(m) {\ | |
293 | offsetof(struct hpi_control_cache_pad, m), \ | |
294 | sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } | |
295 | ||
296 | struct pad_ofs_size { | |
297 | unsigned int offset; | |
298 | unsigned int field_size; | |
299 | }; | |
300 | ||
301 | static struct pad_ofs_size pad_desc[] = { | |
302 | HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ | |
303 | HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ | |
304 | HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ | |
305 | HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ | |
306 | }; | |
307 | ||
308 | /** CheckControlCache checks the cache and fills the struct hpi_response | |
309 | * accordingly. It returns one if a cache hit occurred, zero otherwise. | |
310 | */ | |
311 | short hpi_check_control_cache(struct hpi_control_cache *p_cache, | |
312 | struct hpi_message *phm, struct hpi_response *phr) | |
313 | { | |
314 | short found = 1; | |
719f82d3 EB |
315 | struct hpi_control_cache_info *pI; |
316 | struct hpi_control_cache_single *pC; | |
317 | struct hpi_control_cache_pad *p_pad; | |
318 | ||
3285ea10 EB |
319 | if (!find_control(phm->obj_index, p_cache, &pI)) { |
320 | HPI_DEBUG_LOG(VERBOSE, | |
321 | "HPICMN find_control() failed for adap %d\n", | |
322 | phm->adapter_index); | |
719f82d3 | 323 | return 0; |
3285ea10 | 324 | } |
719f82d3 EB |
325 | |
326 | phr->error = 0; | |
327 | ||
328 | /* pC is the default cached control strucure. May be cast to | |
329 | something else in the following switch statement. | |
330 | */ | |
331 | pC = (struct hpi_control_cache_single *)pI; | |
332 | p_pad = (struct hpi_control_cache_pad *)pI; | |
333 | ||
334 | switch (pI->control_type) { | |
335 | ||
336 | case HPI_CONTROL_METER: | |
337 | if (phm->u.c.attribute == HPI_METER_PEAK) { | |
3285ea10 EB |
338 | phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; |
339 | phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; | |
719f82d3 | 340 | } else if (phm->u.c.attribute == HPI_METER_RMS) { |
3285ea10 EB |
341 | if (pC->u.meter.an_logRMS[0] == |
342 | HPI_CACHE_INVALID_SHORT) { | |
343 | phr->error = | |
344 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
345 | phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; | |
346 | phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; | |
347 | } else { | |
348 | phr->u.c.an_log_value[0] = | |
349 | pC->u.meter.an_logRMS[0]; | |
350 | phr->u.c.an_log_value[1] = | |
351 | pC->u.meter.an_logRMS[1]; | |
352 | } | |
719f82d3 EB |
353 | } else |
354 | found = 0; | |
355 | break; | |
356 | case HPI_CONTROL_VOLUME: | |
357 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
358 | phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; |
359 | phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; | |
fc3a3990 EB |
360 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
361 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) { | |
362 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED) | |
363 | phr->u.c.param1 = | |
364 | HPI_BITMASK_ALL_CHANNELS; | |
365 | else | |
366 | phr->u.c.param1 = 0; | |
367 | } else { | |
368 | phr->error = | |
369 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
370 | phr->u.c.param1 = 0; | |
371 | } | |
372 | } else { | |
719f82d3 | 373 | found = 0; |
fc3a3990 | 374 | } |
719f82d3 EB |
375 | break; |
376 | case HPI_CONTROL_MULTIPLEXER: | |
377 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | |
3285ea10 EB |
378 | phr->u.c.param1 = pC->u.mux.source_node_type; |
379 | phr->u.c.param2 = pC->u.mux.source_node_index; | |
719f82d3 EB |
380 | } else { |
381 | found = 0; | |
382 | } | |
383 | break; | |
384 | case HPI_CONTROL_CHANNEL_MODE: | |
385 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | |
3285ea10 | 386 | phr->u.c.param1 = pC->u.mode.mode; |
719f82d3 EB |
387 | else |
388 | found = 0; | |
389 | break; | |
390 | case HPI_CONTROL_LEVEL: | |
391 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
392 | 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]; | |
719f82d3 EB |
394 | } else |
395 | found = 0; | |
396 | break; | |
397 | case HPI_CONTROL_TUNER: | |
3ee317fe | 398 | if (phm->u.c.attribute == HPI_TUNER_FREQ) |
3285ea10 | 399 | phr->u.c.param1 = pC->u.tuner.freq_ink_hz; |
3ee317fe | 400 | else if (phm->u.c.attribute == HPI_TUNER_BAND) |
3285ea10 EB |
401 | 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; | |
36ed8bdd EB |
406 | phr->error = |
407 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
408 | } else | |
3285ea10 EB |
409 | phr->u.cu.tuner.s_level = |
410 | pC->u.tuner.s_level_avg; | |
3ee317fe EB |
411 | else |
412 | found = 0; | |
719f82d3 EB |
413 | 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) | |
3285ea10 | 418 | phr->u.c.param1 = pC->u.aes3rx.format; |
719f82d3 EB |
419 | 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; | |
719f82d3 EB |
437 | } else |
438 | found = 0; | |
439 | break; | |
440 | case HPI_CONTROL_MICROPHONE: | |
441 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 442 | phr->u.c.param1 = pC->u.microphone.phantom_state; |
719f82d3 EB |
443 | 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 == | |
3285ea10 | 451 | HPI_CACHE_INVALID_UINT16) { |
719f82d3 | 452 | phr->u.c.param1 = 0; |
36ed8bdd EB |
453 | phr->error = |
454 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
719f82d3 EB |
455 | } 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; | |
3285ea10 EB |
462 | case HPI_CONTROL_PAD:{ |
463 | struct hpi_control_cache_pad *p_pad; | |
464 | p_pad = (struct hpi_control_cache_pad *)pI; | |
719f82d3 | 465 | |
3285ea10 EB |
466 | if (!(p_pad->field_valid_flags & (1 << |
467 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
468 | attribute)))) { | |
719f82d3 EB |
469 | phr->error = |
470 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
471 | break; | |
472 | } | |
473 | ||
3285ea10 EB |
474 | 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; | |
486 | ||
487 | if (index > ARRAY_SIZE(pad_desc) - 1) { | |
488 | phr->error = | |
489 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
490 | break; | |
491 | } | |
492 | ||
493 | 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; | |
719f82d3 | 518 | } |
719f82d3 EB |
519 | } |
520 | break; | |
521 | default: | |
522 | found = 0; | |
523 | break; | |
524 | } | |
525 | ||
3285ea10 EB |
526 | 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); | |
719f82d3 EB |
529 | |
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 | ||
540 | Only update if no error. | |
541 | Volume and Level return the limited values in the response, so use these | |
542 | Multiplexer does so use sent values | |
543 | */ | |
3285ea10 | 544 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, |
719f82d3 EB |
545 | struct hpi_message *phm, struct hpi_response *phr) |
546 | { | |
719f82d3 EB |
547 | struct hpi_control_cache_single *pC; |
548 | struct hpi_control_cache_info *pI; | |
549 | ||
3ee317fe EB |
550 | if (phr->error) |
551 | return; | |
552 | ||
3285ea10 EB |
553 | 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); | |
719f82d3 | 557 | return; |
3285ea10 | 558 | } |
719f82d3 EB |
559 | |
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) { | |
3285ea10 EB |
568 | 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]; | |
fc3a3990 EB |
570 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
571 | if (phm->u.c.param1) | |
572 | pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED; | |
573 | else | |
574 | pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED; | |
719f82d3 EB |
575 | } |
576 | break; | |
577 | case HPI_CONTROL_MULTIPLEXER: | |
578 | /* mux does not return its setting on Set command. */ | |
719f82d3 | 579 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { |
3285ea10 EB |
580 | pC->u.mux.source_node_type = (u16)phm->u.c.param1; |
581 | pC->u.mux.source_node_index = (u16)phm->u.c.param2; | |
719f82d3 EB |
582 | } |
583 | break; | |
584 | case HPI_CONTROL_CHANNEL_MODE: | |
585 | /* mode does not return its setting on Set command. */ | |
719f82d3 | 586 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) |
3285ea10 | 587 | pC->u.mode.mode = (u16)phm->u.c.param1; |
719f82d3 EB |
588 | break; |
589 | case HPI_CONTROL_LEVEL: | |
590 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
591 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
592 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
719f82d3 EB |
593 | } |
594 | break; | |
595 | case HPI_CONTROL_MICROPHONE: | |
596 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 597 | pC->u.microphone.phantom_state = (u16)phm->u.c.param1; |
719f82d3 EB |
598 | break; |
599 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
719f82d3 EB |
600 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) |
601 | pC->u.aes3tx.format = phm->u.c.param1; | |
602 | break; | |
603 | case HPI_CONTROL_AESEBU_RECEIVER: | |
719f82d3 | 604 | if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) |
3285ea10 | 605 | pC->u.aes3rx.format = phm->u.c.param1; |
719f82d3 EB |
606 | break; |
607 | case HPI_CONTROL_SAMPLECLOCK: | |
719f82d3 EB |
608 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) |
609 | pC->u.clk.source = (u16)phm->u.c.param1; | |
610 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) | |
611 | pC->u.clk.source_index = (u16)phm->u.c.param1; | |
612 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
613 | pC->u.clk.sample_rate = phm->u.c.param1; | |
614 | break; | |
615 | default: | |
616 | break; | |
617 | } | |
618 | } | |
619 | ||
4704998e EB |
620 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, |
621 | const u32 size_in_bytes, u8 *p_dsp_control_buffer) | |
719f82d3 EB |
622 | { |
623 | struct hpi_control_cache *p_cache = | |
624 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | |
fd0977d0 JJ |
625 | if (!p_cache) |
626 | return NULL; | |
4704998e | 627 | |
fd0977d0 | 628 | p_cache->p_info = |
4704998e | 629 | kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL); |
fd0977d0 JJ |
630 | if (!p_cache->p_info) { |
631 | kfree(p_cache); | |
632 | return NULL; | |
633 | } | |
4704998e | 634 | memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count); |
719f82d3 | 635 | p_cache->cache_size_in_bytes = size_in_bytes; |
4704998e EB |
636 | p_cache->control_count = control_count; |
637 | p_cache->p_cache = p_dsp_control_buffer; | |
719f82d3 | 638 | p_cache->init = 0; |
719f82d3 EB |
639 | return p_cache; |
640 | } | |
641 | ||
642 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | |
643 | { | |
3285ea10 | 644 | if (p_cache) { |
719f82d3 | 645 | kfree(p_cache->p_info); |
719f82d3 EB |
646 | kfree(p_cache); |
647 | } | |
648 | } | |
649 | ||
650 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | |
651 | { | |
3285ea10 | 652 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0); |
719f82d3 EB |
653 | |
654 | switch (phm->function) { | |
655 | case HPI_SUBSYS_OPEN: | |
656 | case HPI_SUBSYS_CLOSE: | |
657 | case HPI_SUBSYS_DRIVER_UNLOAD: | |
719f82d3 EB |
658 | break; |
659 | case HPI_SUBSYS_DRIVER_LOAD: | |
660 | wipe_adapter_list(); | |
661 | hpios_alistlock_init(&adapters); | |
719f82d3 | 662 | break; |
3285ea10 EB |
663 | case HPI_SUBSYS_GET_ADAPTER: |
664 | subsys_get_adapter(phm, phr); | |
665 | break; | |
666 | case HPI_SUBSYS_GET_NUM_ADAPTERS: | |
667 | phr->u.s.num_adapters = adapters.gw_num_adapters; | |
719f82d3 EB |
668 | break; |
669 | case HPI_SUBSYS_CREATE_ADAPTER: | |
719f82d3 EB |
670 | break; |
671 | default: | |
672 | phr->error = HPI_ERROR_INVALID_FUNC; | |
673 | break; | |
674 | } | |
675 | } | |
676 | ||
677 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | |
678 | { | |
679 | switch (phm->type) { | |
680 | case HPI_TYPE_MESSAGE: | |
681 | switch (phm->object) { | |
682 | case HPI_OBJ_SUBSYSTEM: | |
683 | subsys_message(phm, phr); | |
684 | break; | |
685 | } | |
686 | break; | |
687 | ||
688 | default: | |
689 | phr->error = HPI_ERROR_INVALID_TYPE; | |
690 | break; | |
691 | } | |
692 | } |