]>
Commit | Line | Data |
---|---|---|
719f82d3 EB |
1 | /****************************************************************************** |
2 | ||
3 | AudioScience HPI driver | |
40818b62 | 4 | Copyright (C) 1997-2011 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 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++; |
42258dab | 230 | } else { /* dummy cache entry */ |
3285ea10 | 231 | pC->p_info[info->control_index] = NULL; |
42258dab | 232 | } |
719f82d3 | 233 | |
3285ea10 | 234 | byte_count += info->size_in32bit_words * 4; |
719f82d3 EB |
235 | |
236 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
237 | "cached %d, pinfo %p index %d type %d size %d\n", |
238 | cached, pC->p_info[info->control_index], | |
239 | info->control_index, info->control_type, | |
240 | info->size_in32bit_words); | |
241 | ||
1528fbb5 EB |
242 | /* quit loop early if whole cache has been scanned. |
243 | * dwControlCount is the maximum possible entries | |
244 | * but some may be absent from the cache | |
245 | */ | |
3285ea10 EB |
246 | if (byte_count >= pC->cache_size_in_bytes) |
247 | break; | |
248 | /* have seen last control index */ | |
249 | if (info->control_index == pC->control_count - 1) | |
250 | break; | |
719f82d3 | 251 | } |
3285ea10 EB |
252 | |
253 | if (byte_count != pC->cache_size_in_bytes) | |
254 | HPI_DEBUG_LOG(WARNING, | |
1528fbb5 | 255 | "adap %d bytecount %d != cache size %d\n", |
ffdb5787 | 256 | pC->adap_idx, byte_count, |
3285ea10 EB |
257 | pC->cache_size_in_bytes); |
258 | else | |
259 | HPI_DEBUG_LOG(DEBUG, | |
1528fbb5 | 260 | "adap %d cache good, bytecount == cache size = %d\n", |
ffdb5787 | 261 | pC->adap_idx, byte_count); |
3285ea10 | 262 | |
1528fbb5 | 263 | pC->init = (u16)cached; |
719f82d3 EB |
264 | } |
265 | return pC->init; | |
266 | } | |
267 | ||
268 | /** Find a control. | |
269 | */ | |
3285ea10 EB |
270 | static short find_control(u16 control_index, |
271 | struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI) | |
719f82d3 | 272 | { |
719f82d3 EB |
273 | if (!control_cache_alloc_check(p_cache)) { |
274 | HPI_DEBUG_LOG(VERBOSE, | |
3285ea10 EB |
275 | "control_cache_alloc_check() failed %d\n", |
276 | control_index); | |
719f82d3 EB |
277 | return 0; |
278 | } | |
279 | ||
3285ea10 | 280 | *pI = p_cache->p_info[control_index]; |
719f82d3 | 281 | if (!*pI) { |
3285ea10 EB |
282 | HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", |
283 | control_index); | |
719f82d3 EB |
284 | return 0; |
285 | } else { | |
286 | HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", | |
287 | (*pI)->control_type); | |
288 | } | |
289 | return 1; | |
290 | } | |
291 | ||
719f82d3 EB |
292 | /* allow unified treatment of several string fields within struct */ |
293 | #define HPICMN_PAD_OFS_AND_SIZE(m) {\ | |
294 | offsetof(struct hpi_control_cache_pad, m), \ | |
295 | sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } | |
296 | ||
297 | struct pad_ofs_size { | |
298 | unsigned int offset; | |
299 | unsigned int field_size; | |
300 | }; | |
301 | ||
42258dab | 302 | static const struct pad_ofs_size pad_desc[] = { |
719f82d3 EB |
303 | HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ |
304 | HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ | |
305 | HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ | |
306 | HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ | |
307 | }; | |
308 | ||
309 | /** CheckControlCache checks the cache and fills the struct hpi_response | |
310 | * accordingly. It returns one if a cache hit occurred, zero otherwise. | |
311 | */ | |
312 | short hpi_check_control_cache(struct hpi_control_cache *p_cache, | |
313 | struct hpi_message *phm, struct hpi_response *phr) | |
314 | { | |
315 | short found = 1; | |
719f82d3 EB |
316 | struct hpi_control_cache_info *pI; |
317 | struct hpi_control_cache_single *pC; | |
3d0591ee | 318 | size_t response_size; |
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; | |
8637bc94 EB |
327 | phr->specific_error = 0; |
328 | phr->version = 0; | |
719f82d3 | 329 | |
c6c2c9ab EB |
330 | /* set the default response size */ |
331 | response_size = | |
332 | sizeof(struct hpi_response_header) + | |
333 | sizeof(struct hpi_control_res); | |
334 | ||
719f82d3 EB |
335 | /* pC is the default cached control strucure. May be cast to |
336 | something else in the following switch statement. | |
337 | */ | |
338 | pC = (struct hpi_control_cache_single *)pI; | |
719f82d3 EB |
339 | |
340 | switch (pI->control_type) { | |
341 | ||
342 | case HPI_CONTROL_METER: | |
343 | if (phm->u.c.attribute == HPI_METER_PEAK) { | |
3285ea10 EB |
344 | phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; |
345 | phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; | |
719f82d3 | 346 | } else if (phm->u.c.attribute == HPI_METER_RMS) { |
3285ea10 EB |
347 | if (pC->u.meter.an_logRMS[0] == |
348 | HPI_CACHE_INVALID_SHORT) { | |
349 | phr->error = | |
350 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
351 | phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; | |
352 | phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; | |
353 | } else { | |
354 | phr->u.c.an_log_value[0] = | |
355 | pC->u.meter.an_logRMS[0]; | |
356 | phr->u.c.an_log_value[1] = | |
357 | pC->u.meter.an_logRMS[1]; | |
358 | } | |
719f82d3 EB |
359 | } else |
360 | found = 0; | |
361 | break; | |
362 | case HPI_CONTROL_VOLUME: | |
363 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
364 | phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; |
365 | phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; | |
fc3a3990 EB |
366 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
367 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) { | |
368 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED) | |
369 | phr->u.c.param1 = | |
370 | HPI_BITMASK_ALL_CHANNELS; | |
371 | else | |
372 | phr->u.c.param1 = 0; | |
373 | } else { | |
374 | phr->error = | |
375 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
376 | phr->u.c.param1 = 0; | |
377 | } | |
378 | } else { | |
719f82d3 | 379 | found = 0; |
fc3a3990 | 380 | } |
719f82d3 EB |
381 | break; |
382 | case HPI_CONTROL_MULTIPLEXER: | |
383 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | |
3285ea10 EB |
384 | phr->u.c.param1 = pC->u.mux.source_node_type; |
385 | phr->u.c.param2 = pC->u.mux.source_node_index; | |
719f82d3 EB |
386 | } else { |
387 | found = 0; | |
388 | } | |
389 | break; | |
390 | case HPI_CONTROL_CHANNEL_MODE: | |
391 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | |
3285ea10 | 392 | phr->u.c.param1 = pC->u.mode.mode; |
719f82d3 EB |
393 | else |
394 | found = 0; | |
395 | break; | |
396 | case HPI_CONTROL_LEVEL: | |
397 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
398 | phr->u.c.an_log_value[0] = pC->u.level.an_log[0]; |
399 | phr->u.c.an_log_value[1] = pC->u.level.an_log[1]; | |
719f82d3 EB |
400 | } else |
401 | found = 0; | |
402 | break; | |
403 | case HPI_CONTROL_TUNER: | |
3ee317fe | 404 | if (phm->u.c.attribute == HPI_TUNER_FREQ) |
3285ea10 | 405 | phr->u.c.param1 = pC->u.tuner.freq_ink_hz; |
3ee317fe | 406 | else if (phm->u.c.attribute == HPI_TUNER_BAND) |
3285ea10 EB |
407 | phr->u.c.param1 = pC->u.tuner.band; |
408 | else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG) | |
409 | if (pC->u.tuner.s_level_avg == | |
410 | HPI_CACHE_INVALID_SHORT) { | |
411 | phr->u.cu.tuner.s_level = 0; | |
36ed8bdd EB |
412 | phr->error = |
413 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
414 | } else | |
3285ea10 EB |
415 | phr->u.cu.tuner.s_level = |
416 | pC->u.tuner.s_level_avg; | |
3ee317fe EB |
417 | else |
418 | found = 0; | |
719f82d3 EB |
419 | break; |
420 | case HPI_CONTROL_AESEBU_RECEIVER: | |
421 | if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) | |
422 | phr->u.c.param1 = pC->u.aes3rx.error_status; | |
423 | else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | |
3285ea10 | 424 | phr->u.c.param1 = pC->u.aes3rx.format; |
719f82d3 EB |
425 | else |
426 | found = 0; | |
427 | break; | |
428 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
429 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | |
430 | phr->u.c.param1 = pC->u.aes3tx.format; | |
431 | else | |
432 | found = 0; | |
433 | break; | |
434 | case HPI_CONTROL_TONEDETECTOR: | |
435 | if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) | |
436 | phr->u.c.param1 = pC->u.tone.state; | |
437 | else | |
438 | found = 0; | |
439 | break; | |
440 | case HPI_CONTROL_SILENCEDETECTOR: | |
441 | if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { | |
442 | phr->u.c.param1 = pC->u.silence.state; | |
719f82d3 EB |
443 | } else |
444 | found = 0; | |
445 | break; | |
446 | case HPI_CONTROL_MICROPHONE: | |
447 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 448 | phr->u.c.param1 = pC->u.microphone.phantom_state; |
719f82d3 EB |
449 | else |
450 | found = 0; | |
451 | break; | |
452 | case HPI_CONTROL_SAMPLECLOCK: | |
453 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | |
454 | phr->u.c.param1 = pC->u.clk.source; | |
455 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { | |
456 | if (pC->u.clk.source_index == | |
3285ea10 | 457 | HPI_CACHE_INVALID_UINT16) { |
719f82d3 | 458 | phr->u.c.param1 = 0; |
36ed8bdd EB |
459 | phr->error = |
460 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
719f82d3 EB |
461 | } else |
462 | phr->u.c.param1 = pC->u.clk.source_index; | |
463 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
464 | phr->u.c.param1 = pC->u.clk.sample_rate; | |
465 | else | |
466 | found = 0; | |
467 | break; | |
3285ea10 EB |
468 | case HPI_CONTROL_PAD:{ |
469 | struct hpi_control_cache_pad *p_pad; | |
470 | p_pad = (struct hpi_control_cache_pad *)pI; | |
719f82d3 | 471 | |
3285ea10 EB |
472 | if (!(p_pad->field_valid_flags & (1 << |
473 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
474 | attribute)))) { | |
719f82d3 EB |
475 | phr->error = |
476 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
477 | break; | |
478 | } | |
479 | ||
3285ea10 EB |
480 | if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) |
481 | phr->u.c.param1 = p_pad->pI; | |
482 | else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) | |
483 | phr->u.c.param1 = p_pad->pTY; | |
484 | else { | |
485 | unsigned int index = | |
486 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
487 | attribute) - 1; | |
488 | unsigned int offset = phm->u.c.param1; | |
489 | unsigned int pad_string_len, field_size; | |
490 | char *pad_string; | |
491 | unsigned int tocopy; | |
492 | ||
493 | if (index > ARRAY_SIZE(pad_desc) - 1) { | |
494 | phr->error = | |
495 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
496 | break; | |
497 | } | |
498 | ||
499 | pad_string = | |
500 | ((char *)p_pad) + | |
501 | pad_desc[index].offset; | |
502 | field_size = pad_desc[index].field_size; | |
503 | /* Ensure null terminator */ | |
504 | pad_string[field_size - 1] = 0; | |
505 | ||
506 | pad_string_len = strlen(pad_string) + 1; | |
507 | ||
508 | if (offset > pad_string_len) { | |
509 | phr->error = | |
510 | HPI_ERROR_INVALID_CONTROL_VALUE; | |
511 | break; | |
512 | } | |
513 | ||
514 | tocopy = pad_string_len - offset; | |
515 | if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) | |
516 | tocopy = sizeof(phr->u.cu.chars8. | |
517 | sz_data); | |
518 | ||
519 | memcpy(phr->u.cu.chars8.sz_data, | |
520 | &pad_string[offset], tocopy); | |
521 | ||
522 | phr->u.cu.chars8.remaining_chars = | |
523 | pad_string_len - offset - tocopy; | |
719f82d3 | 524 | } |
719f82d3 EB |
525 | } |
526 | break; | |
527 | default: | |
528 | found = 0; | |
529 | break; | |
530 | } | |
531 | ||
3285ea10 EB |
532 | HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", |
533 | found ? "Cached" : "Uncached", phm->adapter_index, | |
534 | pI->control_index, pI->control_type, phm->u.c.attribute); | |
719f82d3 | 535 | |
8637bc94 | 536 | if (found) { |
3d0591ee | 537 | phr->size = (u16)response_size; |
8637bc94 EB |
538 | phr->type = HPI_TYPE_RESPONSE; |
539 | phr->object = phm->object; | |
540 | phr->function = phm->function; | |
541 | } | |
719f82d3 EB |
542 | |
543 | return found; | |
544 | } | |
545 | ||
546 | /** Updates the cache with Set values. | |
547 | ||
548 | Only update if no error. | |
549 | Volume and Level return the limited values in the response, so use these | |
550 | Multiplexer does so use sent values | |
551 | */ | |
3285ea10 | 552 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, |
719f82d3 EB |
553 | struct hpi_message *phm, struct hpi_response *phr) |
554 | { | |
719f82d3 EB |
555 | struct hpi_control_cache_single *pC; |
556 | struct hpi_control_cache_info *pI; | |
557 | ||
3ee317fe EB |
558 | if (phr->error) |
559 | return; | |
560 | ||
3285ea10 EB |
561 | if (!find_control(phm->obj_index, p_cache, &pI)) { |
562 | HPI_DEBUG_LOG(VERBOSE, | |
563 | "HPICMN find_control() failed for adap %d\n", | |
564 | phm->adapter_index); | |
719f82d3 | 565 | return; |
3285ea10 | 566 | } |
719f82d3 EB |
567 | |
568 | /* pC is the default cached control strucure. | |
569 | May be cast to something else in the following switch statement. | |
570 | */ | |
571 | pC = (struct hpi_control_cache_single *)pI; | |
572 | ||
573 | switch (pI->control_type) { | |
574 | case HPI_CONTROL_VOLUME: | |
575 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
576 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
577 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
fc3a3990 EB |
578 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
579 | if (phm->u.c.param1) | |
580 | pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED; | |
581 | else | |
582 | pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED; | |
719f82d3 EB |
583 | } |
584 | break; | |
585 | case HPI_CONTROL_MULTIPLEXER: | |
586 | /* mux does not return its setting on Set command. */ | |
719f82d3 | 587 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { |
3285ea10 EB |
588 | pC->u.mux.source_node_type = (u16)phm->u.c.param1; |
589 | pC->u.mux.source_node_index = (u16)phm->u.c.param2; | |
719f82d3 EB |
590 | } |
591 | break; | |
592 | case HPI_CONTROL_CHANNEL_MODE: | |
593 | /* mode does not return its setting on Set command. */ | |
719f82d3 | 594 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) |
3285ea10 | 595 | pC->u.mode.mode = (u16)phm->u.c.param1; |
719f82d3 EB |
596 | break; |
597 | case HPI_CONTROL_LEVEL: | |
598 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
599 | pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; |
600 | pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; | |
719f82d3 EB |
601 | } |
602 | break; | |
603 | case HPI_CONTROL_MICROPHONE: | |
604 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 605 | pC->u.microphone.phantom_state = (u16)phm->u.c.param1; |
719f82d3 EB |
606 | break; |
607 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
719f82d3 EB |
608 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) |
609 | pC->u.aes3tx.format = phm->u.c.param1; | |
610 | break; | |
611 | case HPI_CONTROL_AESEBU_RECEIVER: | |
719f82d3 | 612 | if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) |
3285ea10 | 613 | pC->u.aes3rx.format = phm->u.c.param1; |
719f82d3 EB |
614 | break; |
615 | case HPI_CONTROL_SAMPLECLOCK: | |
719f82d3 EB |
616 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) |
617 | pC->u.clk.source = (u16)phm->u.c.param1; | |
618 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) | |
619 | pC->u.clk.source_index = (u16)phm->u.c.param1; | |
620 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
621 | pC->u.clk.sample_rate = phm->u.c.param1; | |
622 | break; | |
623 | default: | |
624 | break; | |
625 | } | |
626 | } | |
627 | ||
42258dab EB |
628 | /** Allocate control cache. |
629 | ||
630 | \return Cache pointer, or NULL if allocation fails. | |
631 | */ | |
4704998e EB |
632 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, |
633 | const u32 size_in_bytes, u8 *p_dsp_control_buffer) | |
719f82d3 EB |
634 | { |
635 | struct hpi_control_cache *p_cache = | |
636 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | |
fd0977d0 JJ |
637 | if (!p_cache) |
638 | return NULL; | |
4704998e | 639 | |
6d2d4313 | 640 | p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info), |
67ada836 | 641 | GFP_KERNEL); |
fd0977d0 JJ |
642 | if (!p_cache->p_info) { |
643 | kfree(p_cache); | |
644 | return NULL; | |
645 | } | |
719f82d3 | 646 | p_cache->cache_size_in_bytes = size_in_bytes; |
4704998e EB |
647 | p_cache->control_count = control_count; |
648 | p_cache->p_cache = p_dsp_control_buffer; | |
719f82d3 | 649 | p_cache->init = 0; |
719f82d3 EB |
650 | return p_cache; |
651 | } | |
652 | ||
653 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | |
654 | { | |
3285ea10 | 655 | if (p_cache) { |
719f82d3 | 656 | kfree(p_cache->p_info); |
719f82d3 EB |
657 | kfree(p_cache); |
658 | } | |
659 | } | |
660 | ||
661 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | |
662 | { | |
3285ea10 | 663 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0); |
719f82d3 EB |
664 | |
665 | switch (phm->function) { | |
666 | case HPI_SUBSYS_OPEN: | |
667 | case HPI_SUBSYS_CLOSE: | |
668 | case HPI_SUBSYS_DRIVER_UNLOAD: | |
719f82d3 EB |
669 | break; |
670 | case HPI_SUBSYS_DRIVER_LOAD: | |
671 | wipe_adapter_list(); | |
672 | hpios_alistlock_init(&adapters); | |
719f82d3 | 673 | break; |
3285ea10 EB |
674 | case HPI_SUBSYS_GET_ADAPTER: |
675 | subsys_get_adapter(phm, phr); | |
676 | break; | |
677 | case HPI_SUBSYS_GET_NUM_ADAPTERS: | |
678 | phr->u.s.num_adapters = adapters.gw_num_adapters; | |
719f82d3 EB |
679 | break; |
680 | case HPI_SUBSYS_CREATE_ADAPTER: | |
719f82d3 EB |
681 | break; |
682 | default: | |
683 | phr->error = HPI_ERROR_INVALID_FUNC; | |
684 | break; | |
685 | } | |
686 | } | |
687 | ||
688 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | |
689 | { | |
690 | switch (phm->type) { | |
82b5774f | 691 | case HPI_TYPE_REQUEST: |
719f82d3 EB |
692 | switch (phm->object) { |
693 | case HPI_OBJ_SUBSYSTEM: | |
694 | subsys_message(phm, phr); | |
695 | break; | |
696 | } | |
697 | break; | |
698 | ||
699 | default: | |
700 | phr->error = HPI_ERROR_INVALID_TYPE; | |
701 | break; | |
702 | } | |
703 | } |