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) { |
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; | |
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++; |
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; | |
c6c2c9ab | 318 | u16 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; | |
327 | ||
c6c2c9ab EB |
328 | /* set the default response size */ |
329 | response_size = | |
330 | sizeof(struct hpi_response_header) + | |
331 | sizeof(struct hpi_control_res); | |
332 | ||
719f82d3 EB |
333 | /* pC is the default cached control strucure. May be cast to |
334 | something else in the following switch statement. | |
335 | */ | |
336 | pC = (struct hpi_control_cache_single *)pI; | |
719f82d3 EB |
337 | |
338 | switch (pI->control_type) { | |
339 | ||
340 | case HPI_CONTROL_METER: | |
341 | if (phm->u.c.attribute == HPI_METER_PEAK) { | |
3285ea10 EB |
342 | phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; |
343 | phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; | |
719f82d3 | 344 | } else if (phm->u.c.attribute == HPI_METER_RMS) { |
3285ea10 EB |
345 | if (pC->u.meter.an_logRMS[0] == |
346 | HPI_CACHE_INVALID_SHORT) { | |
347 | phr->error = | |
348 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
349 | phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; | |
350 | phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; | |
351 | } else { | |
352 | phr->u.c.an_log_value[0] = | |
353 | pC->u.meter.an_logRMS[0]; | |
354 | phr->u.c.an_log_value[1] = | |
355 | pC->u.meter.an_logRMS[1]; | |
356 | } | |
719f82d3 EB |
357 | } else |
358 | found = 0; | |
359 | break; | |
360 | case HPI_CONTROL_VOLUME: | |
361 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | |
3285ea10 EB |
362 | phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; |
363 | phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; | |
fc3a3990 EB |
364 | } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { |
365 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) { | |
366 | if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED) | |
367 | phr->u.c.param1 = | |
368 | HPI_BITMASK_ALL_CHANNELS; | |
369 | else | |
370 | phr->u.c.param1 = 0; | |
371 | } else { | |
372 | phr->error = | |
373 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
374 | phr->u.c.param1 = 0; | |
375 | } | |
376 | } else { | |
719f82d3 | 377 | found = 0; |
fc3a3990 | 378 | } |
719f82d3 EB |
379 | break; |
380 | case HPI_CONTROL_MULTIPLEXER: | |
381 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | |
3285ea10 EB |
382 | phr->u.c.param1 = pC->u.mux.source_node_type; |
383 | phr->u.c.param2 = pC->u.mux.source_node_index; | |
719f82d3 EB |
384 | } else { |
385 | found = 0; | |
386 | } | |
387 | break; | |
388 | case HPI_CONTROL_CHANNEL_MODE: | |
389 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | |
3285ea10 | 390 | phr->u.c.param1 = pC->u.mode.mode; |
719f82d3 EB |
391 | else |
392 | found = 0; | |
393 | break; | |
394 | case HPI_CONTROL_LEVEL: | |
395 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | |
3285ea10 EB |
396 | phr->u.c.an_log_value[0] = pC->u.level.an_log[0]; |
397 | phr->u.c.an_log_value[1] = pC->u.level.an_log[1]; | |
719f82d3 EB |
398 | } else |
399 | found = 0; | |
400 | break; | |
401 | case HPI_CONTROL_TUNER: | |
3ee317fe | 402 | if (phm->u.c.attribute == HPI_TUNER_FREQ) |
3285ea10 | 403 | phr->u.c.param1 = pC->u.tuner.freq_ink_hz; |
3ee317fe | 404 | else if (phm->u.c.attribute == HPI_TUNER_BAND) |
3285ea10 EB |
405 | phr->u.c.param1 = pC->u.tuner.band; |
406 | else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG) | |
407 | if (pC->u.tuner.s_level_avg == | |
408 | HPI_CACHE_INVALID_SHORT) { | |
409 | phr->u.cu.tuner.s_level = 0; | |
36ed8bdd EB |
410 | phr->error = |
411 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
412 | } else | |
3285ea10 EB |
413 | phr->u.cu.tuner.s_level = |
414 | pC->u.tuner.s_level_avg; | |
3ee317fe EB |
415 | else |
416 | found = 0; | |
719f82d3 EB |
417 | break; |
418 | case HPI_CONTROL_AESEBU_RECEIVER: | |
419 | if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) | |
420 | phr->u.c.param1 = pC->u.aes3rx.error_status; | |
421 | else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | |
3285ea10 | 422 | phr->u.c.param1 = pC->u.aes3rx.format; |
719f82d3 EB |
423 | else |
424 | found = 0; | |
425 | break; | |
426 | case HPI_CONTROL_AESEBU_TRANSMITTER: | |
427 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | |
428 | phr->u.c.param1 = pC->u.aes3tx.format; | |
429 | else | |
430 | found = 0; | |
431 | break; | |
432 | case HPI_CONTROL_TONEDETECTOR: | |
433 | if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) | |
434 | phr->u.c.param1 = pC->u.tone.state; | |
435 | else | |
436 | found = 0; | |
437 | break; | |
438 | case HPI_CONTROL_SILENCEDETECTOR: | |
439 | if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { | |
440 | phr->u.c.param1 = pC->u.silence.state; | |
719f82d3 EB |
441 | } else |
442 | found = 0; | |
443 | break; | |
444 | case HPI_CONTROL_MICROPHONE: | |
445 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | |
3285ea10 | 446 | phr->u.c.param1 = pC->u.microphone.phantom_state; |
719f82d3 EB |
447 | else |
448 | found = 0; | |
449 | break; | |
450 | case HPI_CONTROL_SAMPLECLOCK: | |
451 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | |
452 | phr->u.c.param1 = pC->u.clk.source; | |
453 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { | |
454 | if (pC->u.clk.source_index == | |
3285ea10 | 455 | HPI_CACHE_INVALID_UINT16) { |
719f82d3 | 456 | phr->u.c.param1 = 0; |
36ed8bdd EB |
457 | phr->error = |
458 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
719f82d3 EB |
459 | } else |
460 | phr->u.c.param1 = pC->u.clk.source_index; | |
461 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | |
462 | phr->u.c.param1 = pC->u.clk.sample_rate; | |
463 | else | |
464 | found = 0; | |
465 | break; | |
3285ea10 EB |
466 | case HPI_CONTROL_PAD:{ |
467 | struct hpi_control_cache_pad *p_pad; | |
468 | p_pad = (struct hpi_control_cache_pad *)pI; | |
719f82d3 | 469 | |
3285ea10 EB |
470 | if (!(p_pad->field_valid_flags & (1 << |
471 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
472 | attribute)))) { | |
719f82d3 EB |
473 | phr->error = |
474 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
475 | break; | |
476 | } | |
477 | ||
3285ea10 EB |
478 | if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) |
479 | phr->u.c.param1 = p_pad->pI; | |
480 | else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) | |
481 | phr->u.c.param1 = p_pad->pTY; | |
482 | else { | |
483 | unsigned int index = | |
484 | HPI_CTL_ATTR_INDEX(phm->u.c. | |
485 | attribute) - 1; | |
486 | unsigned int offset = phm->u.c.param1; | |
487 | unsigned int pad_string_len, field_size; | |
488 | char *pad_string; | |
489 | unsigned int tocopy; | |
490 | ||
491 | if (index > ARRAY_SIZE(pad_desc) - 1) { | |
492 | phr->error = | |
493 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | |
494 | break; | |
495 | } | |
496 | ||
497 | pad_string = | |
498 | ((char *)p_pad) + | |
499 | pad_desc[index].offset; | |
500 | field_size = pad_desc[index].field_size; | |
501 | /* Ensure null terminator */ | |
502 | pad_string[field_size - 1] = 0; | |
503 | ||
504 | pad_string_len = strlen(pad_string) + 1; | |
505 | ||
506 | if (offset > pad_string_len) { | |
507 | phr->error = | |
508 | HPI_ERROR_INVALID_CONTROL_VALUE; | |
509 | break; | |
510 | } | |
511 | ||
512 | tocopy = pad_string_len - offset; | |
513 | if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) | |
514 | tocopy = sizeof(phr->u.cu.chars8. | |
515 | sz_data); | |
516 | ||
517 | memcpy(phr->u.cu.chars8.sz_data, | |
518 | &pad_string[offset], tocopy); | |
519 | ||
520 | phr->u.cu.chars8.remaining_chars = | |
521 | pad_string_len - offset - tocopy; | |
719f82d3 | 522 | } |
719f82d3 EB |
523 | } |
524 | break; | |
525 | default: | |
526 | found = 0; | |
527 | break; | |
528 | } | |
529 | ||
3285ea10 EB |
530 | HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", |
531 | found ? "Cached" : "Uncached", phm->adapter_index, | |
532 | pI->control_index, pI->control_type, phm->u.c.attribute); | |
719f82d3 EB |
533 | |
534 | if (found) | |
c6c2c9ab | 535 | phr->size = response_size; |
719f82d3 EB |
536 | |
537 | return found; | |
538 | } | |
539 | ||
540 | /** Updates the cache with Set values. | |
541 | ||
542 | Only update if no error. | |
543 | Volume and Level return the limited values in the response, so use these | |
544 | Multiplexer does so use sent values | |
545 | */ | |
3285ea10 | 546 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, |
719f82d3 EB |
547 | struct hpi_message *phm, struct hpi_response *phr) |
548 | { | |
719f82d3 EB |
549 | struct hpi_control_cache_single *pC; |
550 | struct hpi_control_cache_info *pI; | |
551 | ||
3ee317fe EB |
552 | if (phr->error) |
553 | return; | |
554 | ||
3285ea10 EB |
555 | if (!find_control(phm->obj_index, p_cache, &pI)) { |
556 | HPI_DEBUG_LOG(VERBOSE, | |
557 | "HPICMN find_control() failed for adap %d\n", | |
558 | phm->adapter_index); | |
719f82d3 | 559 | return; |
3285ea10 | 560 | } |
719f82d3 EB |
561 | |
562 | /* pC is the default cached control strucure. | |
563 | May be cast to something else in the following switch statement. | |
564 | */ | |
565 | pC = (struct hpi_control_cache_single *)pI; | |
566 | ||
567 | switch (pI->control_type) { | |
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 | ||
42258dab EB |
622 | /** Allocate control cache. |
623 | ||
624 | \return Cache pointer, or NULL if allocation fails. | |
625 | */ | |
4704998e EB |
626 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, |
627 | const u32 size_in_bytes, u8 *p_dsp_control_buffer) | |
719f82d3 EB |
628 | { |
629 | struct hpi_control_cache *p_cache = | |
630 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | |
fd0977d0 JJ |
631 | if (!p_cache) |
632 | return NULL; | |
4704998e | 633 | |
fd0977d0 | 634 | p_cache->p_info = |
4704998e | 635 | kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL); |
fd0977d0 JJ |
636 | if (!p_cache->p_info) { |
637 | kfree(p_cache); | |
638 | return NULL; | |
639 | } | |
4704998e | 640 | memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count); |
719f82d3 | 641 | p_cache->cache_size_in_bytes = size_in_bytes; |
4704998e EB |
642 | p_cache->control_count = control_count; |
643 | p_cache->p_cache = p_dsp_control_buffer; | |
719f82d3 | 644 | p_cache->init = 0; |
719f82d3 EB |
645 | return p_cache; |
646 | } | |
647 | ||
648 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | |
649 | { | |
3285ea10 | 650 | if (p_cache) { |
719f82d3 | 651 | kfree(p_cache->p_info); |
719f82d3 EB |
652 | kfree(p_cache); |
653 | } | |
654 | } | |
655 | ||
656 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | |
657 | { | |
3285ea10 | 658 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0); |
719f82d3 EB |
659 | |
660 | switch (phm->function) { | |
661 | case HPI_SUBSYS_OPEN: | |
662 | case HPI_SUBSYS_CLOSE: | |
663 | case HPI_SUBSYS_DRIVER_UNLOAD: | |
719f82d3 EB |
664 | break; |
665 | case HPI_SUBSYS_DRIVER_LOAD: | |
666 | wipe_adapter_list(); | |
667 | hpios_alistlock_init(&adapters); | |
719f82d3 | 668 | break; |
3285ea10 EB |
669 | case HPI_SUBSYS_GET_ADAPTER: |
670 | subsys_get_adapter(phm, phr); | |
671 | break; | |
672 | case HPI_SUBSYS_GET_NUM_ADAPTERS: | |
673 | phr->u.s.num_adapters = adapters.gw_num_adapters; | |
719f82d3 EB |
674 | break; |
675 | case HPI_SUBSYS_CREATE_ADAPTER: | |
719f82d3 EB |
676 | break; |
677 | default: | |
678 | phr->error = HPI_ERROR_INVALID_FUNC; | |
679 | break; | |
680 | } | |
681 | } | |
682 | ||
683 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | |
684 | { | |
685 | switch (phm->type) { | |
82b5774f | 686 | case HPI_TYPE_REQUEST: |
719f82d3 EB |
687 | switch (phm->object) { |
688 | case HPI_OBJ_SUBSYSTEM: | |
689 | subsys_message(phm, phr); | |
690 | break; | |
691 | } | |
692 | break; | |
693 | ||
694 | default: | |
695 | phr->error = HPI_ERROR_INVALID_TYPE; | |
696 | break; | |
697 | } | |
698 | } |