| Eliot Blennerhassett | 719f82d | 2010-04-21 18:17:39 +0200 | [diff] [blame] | 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 | } |