diff options
author | Eliot Blennerhassett <eblennerhassett@audioscience.com> | 2010-04-21 12:17:39 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-04-22 01:21:53 -0400 |
commit | 719f82d3987aad4cc9f46d19c35f362672545cad (patch) | |
tree | 3f9edf749da5e5d11bfa82336db99a01dd489979 /sound/pci/asihpi/hpicmn.c | |
parent | cf0dbba515415bb19b11f9323d5f7bebd7f24fd6 (diff) |
ALSA: Add support of AudioScience ASI boards
Added the support of AudioScience ASI boards.
The driver has been tested for years on alsa-driver external tree,
now finally got merged to the kernel.
Signed-off-by: Eliot Blennerhassett <eblennerhassett@audioscience.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/asihpi/hpicmn.c')
-rw-r--r-- | sound/pci/asihpi/hpicmn.c | 643 |
1 files changed, 643 insertions, 0 deletions
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c new file mode 100644 index 000000000000..565102cae4f8 --- /dev/null +++ b/sound/pci/asihpi/hpicmn.c | |||
@@ -0,0 +1,643 @@ | |||
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" | ||
29 | #include "hpicmn.h" | ||
30 | |||
31 | struct hpi_adapters_list { | ||
32 | struct hpios_spinlock list_lock; | ||
33 | struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS]; | ||
34 | u16 gw_num_adapters; | ||
35 | }; | ||
36 | |||
37 | static struct hpi_adapters_list adapters; | ||
38 | |||
39 | /** | ||
40 | * Given an HPI Message that was sent out and a response that was received, | ||
41 | * validate that the response has the correct fields filled in, | ||
42 | * i.e ObjectType, Function etc | ||
43 | **/ | ||
44 | u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) | ||
45 | { | ||
46 | u16 error = 0; | ||
47 | |||
48 | if ((phr->type != HPI_TYPE_RESPONSE) | ||
49 | || (phr->object != phm->object) | ||
50 | || (phr->function != phm->function)) | ||
51 | error = HPI_ERROR_INVALID_RESPONSE; | ||
52 | |||
53 | return error; | ||
54 | } | ||
55 | |||
56 | u16 hpi_add_adapter(struct hpi_adapter_obj *pao) | ||
57 | { | ||
58 | u16 retval = 0; | ||
59 | /*HPI_ASSERT(pao->wAdapterType); */ | ||
60 | |||
61 | hpios_alistlock_lock(&adapters); | ||
62 | |||
63 | if (pao->index >= HPI_MAX_ADAPTERS) { | ||
64 | retval = HPI_ERROR_BAD_ADAPTER_NUMBER; | ||
65 | goto unlock; | ||
66 | } | ||
67 | |||
68 | if (adapters.adapter[pao->index].adapter_type) { | ||
69 | { | ||
70 | retval = HPI_DUPLICATE_ADAPTER_NUMBER; | ||
71 | goto unlock; | ||
72 | } | ||
73 | } | ||
74 | adapters.adapter[pao->index] = *pao; | ||
75 | hpios_dsplock_init(&adapters.adapter[pao->index]); | ||
76 | adapters.gw_num_adapters++; | ||
77 | |||
78 | unlock: | ||
79 | hpios_alistlock_un_lock(&adapters); | ||
80 | return retval; | ||
81 | } | ||
82 | |||
83 | void hpi_delete_adapter(struct hpi_adapter_obj *pao) | ||
84 | { | ||
85 | memset(pao, 0, sizeof(struct hpi_adapter_obj)); | ||
86 | |||
87 | hpios_alistlock_lock(&adapters); | ||
88 | adapters.gw_num_adapters--; /* dec the number of adapters */ | ||
89 | hpios_alistlock_un_lock(&adapters); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * FindAdapter returns a pointer to the struct hpi_adapter_obj with | ||
94 | * index wAdapterIndex in an HPI_ADAPTERS_LIST structure. | ||
95 | * | ||
96 | */ | ||
97 | struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index) | ||
98 | { | ||
99 | struct hpi_adapter_obj *pao = NULL; | ||
100 | |||
101 | if (adapter_index >= HPI_MAX_ADAPTERS) { | ||
102 | HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d ", | ||
103 | adapter_index); | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | pao = &adapters.adapter[adapter_index]; | ||
108 | if (pao->adapter_type != 0) { | ||
109 | /* | ||
110 | HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n", | ||
111 | wAdapterIndex); | ||
112 | */ | ||
113 | return pao; | ||
114 | } else { | ||
115 | /* | ||
116 | HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n", | ||
117 | wAdapterIndex); | ||
118 | */ | ||
119 | return NULL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * | ||
125 | * wipe an HPI_ADAPTERS_LIST structure. | ||
126 | * | ||
127 | **/ | ||
128 | static void wipe_adapter_list(void | ||
129 | ) | ||
130 | { | ||
131 | memset(&adapters, 0, sizeof(adapters)); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * SubSysGetAdapters fills awAdapterList in an struct hpi_response structure | ||
136 | * with all adapters in the given HPI_ADAPTERS_LIST. | ||
137 | * | ||
138 | */ | ||
139 | static void subsys_get_adapters(struct hpi_response *phr) | ||
140 | { | ||
141 | /* fill in the response adapter array with the position */ | ||
142 | /* identified by the adapter number/index of the adapters in */ | ||
143 | /* this HPI */ | ||
144 | /* i.e. if we have an A120 with it's jumper set to */ | ||
145 | /* Adapter Number 2 then put an Adapter type A120 in the */ | ||
146 | /* array in position 1 */ | ||
147 | /* NOTE: AdapterNumber is 1..N, Index is 0..N-1 */ | ||
148 | |||
149 | /* input: NONE */ | ||
150 | /* output: wNumAdapters */ | ||
151 | /* awAdapter[] */ | ||
152 | /* */ | ||
153 | |||
154 | short i; | ||
155 | struct hpi_adapter_obj *pao = NULL; | ||
156 | |||
157 | HPI_DEBUG_LOG(VERBOSE, "subsys_get_adapters\n"); | ||
158 | |||
159 | /* for each adapter, place it's type in the position of the array */ | ||
160 | /* corresponding to it's adapter number */ | ||
161 | for (i = 0; i < adapters.gw_num_adapters; i++) { | ||
162 | pao = &adapters.adapter[i]; | ||
163 | if (phr->u.s.aw_adapter_list[pao->index] != 0) { | ||
164 | phr->error = HPI_DUPLICATE_ADAPTER_NUMBER; | ||
165 | phr->specific_error = pao->index; | ||
166 | return; | ||
167 | } | ||
168 | phr->u.s.aw_adapter_list[pao->index] = pao->adapter_type; | ||
169 | } | ||
170 | |||
171 | phr->u.s.num_adapters = adapters.gw_num_adapters; | ||
172 | phr->error = 0; /* the function completed OK; */ | ||
173 | } | ||
174 | |||
175 | static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) | ||
176 | { | ||
177 | unsigned int i; | ||
178 | int cached = 0; | ||
179 | if (!pC) | ||
180 | return 0; | ||
181 | if ((!pC->init) && (pC->p_cache != NULL) && (pC->control_count) | ||
182 | && (pC->cache_size_in_bytes) | ||
183 | ) { | ||
184 | u32 *p_master_cache; | ||
185 | pC->init = 1; | ||
186 | |||
187 | p_master_cache = (u32 *)pC->p_cache; | ||
188 | HPI_DEBUG_LOG(VERBOSE, "check %d controls\n", | ||
189 | pC->control_count); | ||
190 | for (i = 0; i < pC->control_count; i++) { | ||
191 | struct hpi_control_cache_info *info = | ||
192 | (struct hpi_control_cache_info *) | ||
193 | p_master_cache; | ||
194 | |||
195 | if (info->control_type) { | ||
196 | pC->p_info[i] = info; | ||
197 | cached++; | ||
198 | } else | ||
199 | pC->p_info[i] = NULL; | ||
200 | |||
201 | if (info->size_in32bit_words) | ||
202 | p_master_cache += info->size_in32bit_words; | ||
203 | else | ||
204 | p_master_cache += | ||
205 | sizeof(struct | ||
206 | hpi_control_cache_single) / | ||
207 | sizeof(u32); | ||
208 | |||
209 | HPI_DEBUG_LOG(VERBOSE, | ||
210 | "cached %d, pinfo %p index %d type %d\n", | ||
211 | cached, pC->p_info[i], info->control_index, | ||
212 | info->control_type); | ||
213 | } | ||
214 | /* | ||
215 | We didn't find anything to cache, so try again later ! | ||
216 | */ | ||
217 | if (!cached) | ||
218 | pC->init = 0; | ||
219 | } | ||
220 | return pC->init; | ||
221 | } | ||
222 | |||
223 | /** Find a control. | ||
224 | */ | ||
225 | static short find_control(struct hpi_message *phm, | ||
226 | struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI, | ||
227 | u16 *pw_control_index) | ||
228 | { | ||
229 | *pw_control_index = phm->obj_index; | ||
230 | |||
231 | if (!control_cache_alloc_check(p_cache)) { | ||
232 | HPI_DEBUG_LOG(VERBOSE, | ||
233 | "control_cache_alloc_check() failed. adap%d ci%d\n", | ||
234 | phm->adapter_index, *pw_control_index); | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | *pI = p_cache->p_info[*pw_control_index]; | ||
239 | if (!*pI) { | ||
240 | HPI_DEBUG_LOG(VERBOSE, "uncached adap %d, control %d\n", | ||
241 | phm->adapter_index, *pw_control_index); | ||
242 | return 0; | ||
243 | } else { | ||
244 | HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", | ||
245 | (*pI)->control_type); | ||
246 | } | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | /** Used by the kernel driver to figure out if a buffer needs mapping. | ||
251 | */ | ||
252 | short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache, | ||
253 | struct hpi_message *phm, void **p, unsigned int *pN) | ||
254 | { | ||
255 | *pN = 0; | ||
256 | *p = NULL; | ||
257 | if ((phm->function == HPI_CONTROL_GET_STATE) | ||
258 | && (phm->object == HPI_OBJ_CONTROLEX) | ||
259 | ) { | ||
260 | u16 control_index; | ||
261 | struct hpi_control_cache_info *pI; | ||
262 | |||
263 | if (!find_control(phm, p_cache, &pI, &control_index)) | ||
264 | return 0; | ||
265 | } | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* allow unified treatment of several string fields within struct */ | ||
270 | #define HPICMN_PAD_OFS_AND_SIZE(m) {\ | ||
271 | offsetof(struct hpi_control_cache_pad, m), \ | ||
272 | sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } | ||
273 | |||
274 | struct pad_ofs_size { | ||
275 | unsigned int offset; | ||
276 | unsigned int field_size; | ||
277 | }; | ||
278 | |||
279 | static struct pad_ofs_size pad_desc[] = { | ||
280 | HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ | ||
281 | HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ | ||
282 | HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ | ||
283 | HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ | ||
284 | }; | ||
285 | |||
286 | /** CheckControlCache checks the cache and fills the struct hpi_response | ||
287 | * accordingly. It returns one if a cache hit occurred, zero otherwise. | ||
288 | */ | ||
289 | short hpi_check_control_cache(struct hpi_control_cache *p_cache, | ||
290 | struct hpi_message *phm, struct hpi_response *phr) | ||
291 | { | ||
292 | short found = 1; | ||
293 | u16 control_index; | ||
294 | struct hpi_control_cache_info *pI; | ||
295 | struct hpi_control_cache_single *pC; | ||
296 | struct hpi_control_cache_pad *p_pad; | ||
297 | |||
298 | if (!find_control(phm, p_cache, &pI, &control_index)) | ||
299 | return 0; | ||
300 | |||
301 | phr->error = 0; | ||
302 | |||
303 | /* pC is the default cached control strucure. May be cast to | ||
304 | something else in the following switch statement. | ||
305 | */ | ||
306 | pC = (struct hpi_control_cache_single *)pI; | ||
307 | p_pad = (struct hpi_control_cache_pad *)pI; | ||
308 | |||
309 | switch (pI->control_type) { | ||
310 | |||
311 | case HPI_CONTROL_METER: | ||
312 | if (phm->u.c.attribute == HPI_METER_PEAK) { | ||
313 | phr->u.c.an_log_value[0] = pC->u.p.an_log_peak[0]; | ||
314 | phr->u.c.an_log_value[1] = pC->u.p.an_log_peak[1]; | ||
315 | } else if (phm->u.c.attribute == HPI_METER_RMS) { | ||
316 | phr->u.c.an_log_value[0] = pC->u.p.an_logRMS[0]; | ||
317 | phr->u.c.an_log_value[1] = pC->u.p.an_logRMS[1]; | ||
318 | } else | ||
319 | found = 0; | ||
320 | break; | ||
321 | case HPI_CONTROL_VOLUME: | ||
322 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | ||
323 | phr->u.c.an_log_value[0] = pC->u.v.an_log[0]; | ||
324 | phr->u.c.an_log_value[1] = pC->u.v.an_log[1]; | ||
325 | } else | ||
326 | found = 0; | ||
327 | break; | ||
328 | case HPI_CONTROL_MULTIPLEXER: | ||
329 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | ||
330 | phr->u.c.param1 = pC->u.x.source_node_type; | ||
331 | phr->u.c.param2 = pC->u.x.source_node_index; | ||
332 | } else { | ||
333 | found = 0; | ||
334 | } | ||
335 | break; | ||
336 | case HPI_CONTROL_CHANNEL_MODE: | ||
337 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | ||
338 | phr->u.c.param1 = pC->u.m.mode; | ||
339 | else | ||
340 | found = 0; | ||
341 | break; | ||
342 | case HPI_CONTROL_LEVEL: | ||
343 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | ||
344 | phr->u.c.an_log_value[0] = pC->u.l.an_log[0]; | ||
345 | phr->u.c.an_log_value[1] = pC->u.l.an_log[1]; | ||
346 | } else | ||
347 | found = 0; | ||
348 | break; | ||
349 | case HPI_CONTROL_TUNER: | ||
350 | { | ||
351 | struct hpi_control_cache_single *pCT = | ||
352 | (struct hpi_control_cache_single *)pI; | ||
353 | if (phm->u.c.attribute == HPI_TUNER_FREQ) | ||
354 | phr->u.c.param1 = pCT->u.t.freq_ink_hz; | ||
355 | else if (phm->u.c.attribute == HPI_TUNER_BAND) | ||
356 | phr->u.c.param1 = pCT->u.t.band; | ||
357 | else if ((phm->u.c.attribute == HPI_TUNER_LEVEL) | ||
358 | && (phm->u.c.param1 == | ||
359 | HPI_TUNER_LEVEL_AVERAGE)) | ||
360 | phr->u.c.param1 = pCT->u.t.level; | ||
361 | else | ||
362 | found = 0; | ||
363 | } | ||
364 | break; | ||
365 | case HPI_CONTROL_AESEBU_RECEIVER: | ||
366 | if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) | ||
367 | phr->u.c.param1 = pC->u.aes3rx.error_status; | ||
368 | else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | ||
369 | phr->u.c.param1 = pC->u.aes3rx.source; | ||
370 | else | ||
371 | found = 0; | ||
372 | break; | ||
373 | case HPI_CONTROL_AESEBU_TRANSMITTER: | ||
374 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | ||
375 | phr->u.c.param1 = pC->u.aes3tx.format; | ||
376 | else | ||
377 | found = 0; | ||
378 | break; | ||
379 | case HPI_CONTROL_TONEDETECTOR: | ||
380 | if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) | ||
381 | phr->u.c.param1 = pC->u.tone.state; | ||
382 | else | ||
383 | found = 0; | ||
384 | break; | ||
385 | case HPI_CONTROL_SILENCEDETECTOR: | ||
386 | if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { | ||
387 | phr->u.c.param1 = pC->u.silence.state; | ||
388 | phr->u.c.param2 = pC->u.silence.count; | ||
389 | } else | ||
390 | found = 0; | ||
391 | break; | ||
392 | case HPI_CONTROL_MICROPHONE: | ||
393 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | ||
394 | phr->u.c.param1 = pC->u.phantom_power.state; | ||
395 | else | ||
396 | found = 0; | ||
397 | break; | ||
398 | case HPI_CONTROL_SAMPLECLOCK: | ||
399 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | ||
400 | phr->u.c.param1 = pC->u.clk.source; | ||
401 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { | ||
402 | if (pC->u.clk.source_index == | ||
403 | HPI_ERROR_ILLEGAL_CACHE_VALUE) { | ||
404 | phr->u.c.param1 = 0; | ||
405 | phr->error = HPI_ERROR_INVALID_OPERATION; | ||
406 | } else | ||
407 | phr->u.c.param1 = pC->u.clk.source_index; | ||
408 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | ||
409 | phr->u.c.param1 = pC->u.clk.sample_rate; | ||
410 | else | ||
411 | found = 0; | ||
412 | break; | ||
413 | case HPI_CONTROL_PAD: | ||
414 | |||
415 | if (!(p_pad->field_valid_flags & (1 << | ||
416 | HPI_CTL_ATTR_INDEX(phm->u.c. | ||
417 | attribute)))) { | ||
418 | phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) | ||
423 | phr->u.c.param1 = p_pad->pI; | ||
424 | else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) | ||
425 | phr->u.c.param1 = p_pad->pTY; | ||
426 | else { | ||
427 | unsigned int index = | ||
428 | HPI_CTL_ATTR_INDEX(phm->u.c.attribute) - 1; | ||
429 | unsigned int offset = phm->u.c.param1; | ||
430 | unsigned int pad_string_len, field_size; | ||
431 | char *pad_string; | ||
432 | unsigned int tocopy; | ||
433 | |||
434 | HPI_DEBUG_LOG(VERBOSE, "PADS HPI_PADS_ %d\n", | ||
435 | phm->u.c.attribute); | ||
436 | |||
437 | if (index > ARRAY_SIZE(pad_desc) - 1) { | ||
438 | phr->error = | ||
439 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | pad_string = ((char *)p_pad) + pad_desc[index].offset; | ||
444 | field_size = pad_desc[index].field_size; | ||
445 | /* Ensure null terminator */ | ||
446 | pad_string[field_size - 1] = 0; | ||
447 | |||
448 | pad_string_len = strlen(pad_string) + 1; | ||
449 | |||
450 | if (offset > pad_string_len) { | ||
451 | phr->error = HPI_ERROR_INVALID_CONTROL_VALUE; | ||
452 | break; | ||
453 | } | ||
454 | |||
455 | tocopy = pad_string_len - offset; | ||
456 | if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) | ||
457 | tocopy = sizeof(phr->u.cu.chars8.sz_data); | ||
458 | |||
459 | HPI_DEBUG_LOG(VERBOSE, | ||
460 | "PADS memcpy(%d), offset %d \n", tocopy, | ||
461 | offset); | ||
462 | memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset], | ||
463 | tocopy); | ||
464 | |||
465 | phr->u.cu.chars8.remaining_chars = | ||
466 | pad_string_len - offset - tocopy; | ||
467 | } | ||
468 | break; | ||
469 | default: | ||
470 | found = 0; | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | if (found) | ||
475 | HPI_DEBUG_LOG(VERBOSE, | ||
476 | "cached adap %d, ctl %d, type %d, attr %d\n", | ||
477 | phm->adapter_index, pI->control_index, | ||
478 | pI->control_type, phm->u.c.attribute); | ||
479 | else | ||
480 | HPI_DEBUG_LOG(VERBOSE, | ||
481 | "uncached adap %d, ctl %d, ctl type %d\n", | ||
482 | phm->adapter_index, pI->control_index, | ||
483 | pI->control_type); | ||
484 | |||
485 | if (found) | ||
486 | phr->size = | ||
487 | sizeof(struct hpi_response_header) + | ||
488 | sizeof(struct hpi_control_res); | ||
489 | |||
490 | return found; | ||
491 | } | ||
492 | |||
493 | /** Updates the cache with Set values. | ||
494 | |||
495 | Only update if no error. | ||
496 | Volume and Level return the limited values in the response, so use these | ||
497 | Multiplexer does so use sent values | ||
498 | */ | ||
499 | void hpi_sync_control_cache(struct hpi_control_cache *p_cache, | ||
500 | struct hpi_message *phm, struct hpi_response *phr) | ||
501 | { | ||
502 | u16 control_index; | ||
503 | struct hpi_control_cache_single *pC; | ||
504 | struct hpi_control_cache_info *pI; | ||
505 | |||
506 | if (!find_control(phm, p_cache, &pI, &control_index)) | ||
507 | return; | ||
508 | |||
509 | /* pC is the default cached control strucure. | ||
510 | May be cast to something else in the following switch statement. | ||
511 | */ | ||
512 | pC = (struct hpi_control_cache_single *)pI; | ||
513 | |||
514 | switch (pI->control_type) { | ||
515 | case HPI_CONTROL_VOLUME: | ||
516 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | ||
517 | pC->u.v.an_log[0] = phr->u.c.an_log_value[0]; | ||
518 | pC->u.v.an_log[1] = phr->u.c.an_log_value[1]; | ||
519 | } | ||
520 | break; | ||
521 | case HPI_CONTROL_MULTIPLEXER: | ||
522 | /* mux does not return its setting on Set command. */ | ||
523 | if (phr->error) | ||
524 | return; | ||
525 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | ||
526 | pC->u.x.source_node_type = (u16)phm->u.c.param1; | ||
527 | pC->u.x.source_node_index = (u16)phm->u.c.param2; | ||
528 | } | ||
529 | break; | ||
530 | case HPI_CONTROL_CHANNEL_MODE: | ||
531 | /* mode does not return its setting on Set command. */ | ||
532 | if (phr->error) | ||
533 | return; | ||
534 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | ||
535 | pC->u.m.mode = (u16)phm->u.c.param1; | ||
536 | break; | ||
537 | case HPI_CONTROL_LEVEL: | ||
538 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | ||
539 | pC->u.v.an_log[0] = phr->u.c.an_log_value[0]; | ||
540 | pC->u.v.an_log[1] = phr->u.c.an_log_value[1]; | ||
541 | } | ||
542 | break; | ||
543 | case HPI_CONTROL_MICROPHONE: | ||
544 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | ||
545 | pC->u.phantom_power.state = (u16)phm->u.c.param1; | ||
546 | break; | ||
547 | case HPI_CONTROL_AESEBU_TRANSMITTER: | ||
548 | if (phr->error) | ||
549 | return; | ||
550 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | ||
551 | pC->u.aes3tx.format = phm->u.c.param1; | ||
552 | break; | ||
553 | case HPI_CONTROL_AESEBU_RECEIVER: | ||
554 | if (phr->error) | ||
555 | return; | ||
556 | if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | ||
557 | pC->u.aes3rx.source = phm->u.c.param1; | ||
558 | break; | ||
559 | case HPI_CONTROL_SAMPLECLOCK: | ||
560 | if (phr->error) | ||
561 | return; | ||
562 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | ||
563 | pC->u.clk.source = (u16)phm->u.c.param1; | ||
564 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) | ||
565 | pC->u.clk.source_index = (u16)phm->u.c.param1; | ||
566 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | ||
567 | pC->u.clk.sample_rate = phm->u.c.param1; | ||
568 | break; | ||
569 | default: | ||
570 | break; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 | ||
575 | number_of_controls, const u32 size_in_bytes, | ||
576 | struct hpi_control_cache_info *pDSP_control_buffer) | ||
577 | { | ||
578 | struct hpi_control_cache *p_cache = | ||
579 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | ||
580 | p_cache->cache_size_in_bytes = size_in_bytes; | ||
581 | p_cache->control_count = number_of_controls; | ||
582 | p_cache->p_cache = | ||
583 | (struct hpi_control_cache_single *)pDSP_control_buffer; | ||
584 | p_cache->init = 0; | ||
585 | p_cache->p_info = | ||
586 | kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count, | ||
587 | GFP_KERNEL); | ||
588 | return p_cache; | ||
589 | } | ||
590 | |||
591 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | ||
592 | { | ||
593 | if ((p_cache->init) && (p_cache->p_info)) { | ||
594 | kfree(p_cache->p_info); | ||
595 | p_cache->p_info = NULL; | ||
596 | p_cache->init = 0; | ||
597 | kfree(p_cache); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | ||
602 | { | ||
603 | |||
604 | switch (phm->function) { | ||
605 | case HPI_SUBSYS_OPEN: | ||
606 | case HPI_SUBSYS_CLOSE: | ||
607 | case HPI_SUBSYS_DRIVER_UNLOAD: | ||
608 | phr->error = 0; | ||
609 | break; | ||
610 | case HPI_SUBSYS_DRIVER_LOAD: | ||
611 | wipe_adapter_list(); | ||
612 | hpios_alistlock_init(&adapters); | ||
613 | phr->error = 0; | ||
614 | break; | ||
615 | case HPI_SUBSYS_GET_INFO: | ||
616 | subsys_get_adapters(phr); | ||
617 | break; | ||
618 | case HPI_SUBSYS_CREATE_ADAPTER: | ||
619 | case HPI_SUBSYS_DELETE_ADAPTER: | ||
620 | phr->error = 0; | ||
621 | break; | ||
622 | default: | ||
623 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | ||
629 | { | ||
630 | switch (phm->type) { | ||
631 | case HPI_TYPE_MESSAGE: | ||
632 | switch (phm->object) { | ||
633 | case HPI_OBJ_SUBSYSTEM: | ||
634 | subsys_message(phm, phr); | ||
635 | break; | ||
636 | } | ||
637 | break; | ||
638 | |||
639 | default: | ||
640 | phr->error = HPI_ERROR_INVALID_TYPE; | ||
641 | break; | ||
642 | } | ||
643 | } | ||