xref: /openbmc/linux/sound/pci/asihpi/hpicmn.c (revision 1fa6ac37)
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 		if (phm->u.c.attribute == HPI_TUNER_FREQ)
351 			phr->u.c.param1 = pC->u.t.freq_ink_hz;
352 		else if (phm->u.c.attribute == HPI_TUNER_BAND)
353 			phr->u.c.param1 = pC->u.t.band;
354 		else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
355 			&& (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
356 			phr->u.c.param1 = pC->u.t.level;
357 		else
358 			found = 0;
359 		break;
360 	case HPI_CONTROL_AESEBU_RECEIVER:
361 		if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
362 			phr->u.c.param1 = pC->u.aes3rx.error_status;
363 		else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
364 			phr->u.c.param1 = pC->u.aes3rx.source;
365 		else
366 			found = 0;
367 		break;
368 	case HPI_CONTROL_AESEBU_TRANSMITTER:
369 		if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
370 			phr->u.c.param1 = pC->u.aes3tx.format;
371 		else
372 			found = 0;
373 		break;
374 	case HPI_CONTROL_TONEDETECTOR:
375 		if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
376 			phr->u.c.param1 = pC->u.tone.state;
377 		else
378 			found = 0;
379 		break;
380 	case HPI_CONTROL_SILENCEDETECTOR:
381 		if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
382 			phr->u.c.param1 = pC->u.silence.state;
383 			phr->u.c.param2 = pC->u.silence.count;
384 		} else
385 			found = 0;
386 		break;
387 	case HPI_CONTROL_MICROPHONE:
388 		if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
389 			phr->u.c.param1 = pC->u.phantom_power.state;
390 		else
391 			found = 0;
392 		break;
393 	case HPI_CONTROL_SAMPLECLOCK:
394 		if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
395 			phr->u.c.param1 = pC->u.clk.source;
396 		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
397 			if (pC->u.clk.source_index ==
398 				HPI_ERROR_ILLEGAL_CACHE_VALUE) {
399 				phr->u.c.param1 = 0;
400 				phr->error = HPI_ERROR_INVALID_OPERATION;
401 			} else
402 				phr->u.c.param1 = pC->u.clk.source_index;
403 		} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
404 			phr->u.c.param1 = pC->u.clk.sample_rate;
405 		else
406 			found = 0;
407 		break;
408 	case HPI_CONTROL_PAD:
409 
410 		if (!(p_pad->field_valid_flags & (1 <<
411 					HPI_CTL_ATTR_INDEX(phm->u.c.
412 						attribute)))) {
413 			phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
414 			break;
415 		}
416 
417 		if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
418 			phr->u.c.param1 = p_pad->pI;
419 		else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
420 			phr->u.c.param1 = p_pad->pTY;
421 		else {
422 			unsigned int index =
423 				HPI_CTL_ATTR_INDEX(phm->u.c.attribute) - 1;
424 			unsigned int offset = phm->u.c.param1;
425 			unsigned int pad_string_len, field_size;
426 			char *pad_string;
427 			unsigned int tocopy;
428 
429 			HPI_DEBUG_LOG(VERBOSE, "PADS HPI_PADS_ %d\n",
430 				phm->u.c.attribute);
431 
432 			if (index > ARRAY_SIZE(pad_desc) - 1) {
433 				phr->error =
434 					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
435 				break;
436 			}
437 
438 			pad_string = ((char *)p_pad) + pad_desc[index].offset;
439 			field_size = pad_desc[index].field_size;
440 			/* Ensure null terminator */
441 			pad_string[field_size - 1] = 0;
442 
443 			pad_string_len = strlen(pad_string) + 1;
444 
445 			if (offset > pad_string_len) {
446 				phr->error = HPI_ERROR_INVALID_CONTROL_VALUE;
447 				break;
448 			}
449 
450 			tocopy = pad_string_len - offset;
451 			if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
452 				tocopy = sizeof(phr->u.cu.chars8.sz_data);
453 
454 			HPI_DEBUG_LOG(VERBOSE,
455 				"PADS memcpy(%d), offset %d \n", tocopy,
456 				offset);
457 			memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset],
458 				tocopy);
459 
460 			phr->u.cu.chars8.remaining_chars =
461 				pad_string_len - offset - tocopy;
462 		}
463 		break;
464 	default:
465 		found = 0;
466 		break;
467 	}
468 
469 	if (found)
470 		HPI_DEBUG_LOG(VERBOSE,
471 			"cached adap %d, ctl %d, type %d, attr %d\n",
472 			phm->adapter_index, pI->control_index,
473 			pI->control_type, phm->u.c.attribute);
474 	else
475 		HPI_DEBUG_LOG(VERBOSE,
476 			"uncached adap %d, ctl %d, ctl type %d\n",
477 			phm->adapter_index, pI->control_index,
478 			pI->control_type);
479 
480 	if (found)
481 		phr->size =
482 			sizeof(struct hpi_response_header) +
483 			sizeof(struct hpi_control_res);
484 
485 	return found;
486 }
487 
488 /** Updates the cache with Set values.
489 
490 Only update if no error.
491 Volume and Level return the limited values in the response, so use these
492 Multiplexer does so use sent values
493 */
494 void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
495 	struct hpi_message *phm, struct hpi_response *phr)
496 {
497 	u16 control_index;
498 	struct hpi_control_cache_single *pC;
499 	struct hpi_control_cache_info *pI;
500 
501 	if (phr->error)
502 		return;
503 
504 	if (!find_control(phm, p_cache, &pI, &control_index))
505 		return;
506 
507 	/* pC is the default cached control strucure.
508 	   May be cast to something else in the following switch statement.
509 	 */
510 	pC = (struct hpi_control_cache_single *)pI;
511 
512 	switch (pI->control_type) {
513 	case HPI_CONTROL_VOLUME:
514 		if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
515 			pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
516 			pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
517 		}
518 		break;
519 	case HPI_CONTROL_MULTIPLEXER:
520 		/* mux does not return its setting on Set command. */
521 		if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
522 			pC->u.x.source_node_type = (u16)phm->u.c.param1;
523 			pC->u.x.source_node_index = (u16)phm->u.c.param2;
524 		}
525 		break;
526 	case HPI_CONTROL_CHANNEL_MODE:
527 		/* mode does not return its setting on Set command. */
528 		if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
529 			pC->u.m.mode = (u16)phm->u.c.param1;
530 		break;
531 	case HPI_CONTROL_LEVEL:
532 		if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
533 			pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
534 			pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
535 		}
536 		break;
537 	case HPI_CONTROL_MICROPHONE:
538 		if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
539 			pC->u.phantom_power.state = (u16)phm->u.c.param1;
540 		break;
541 	case HPI_CONTROL_AESEBU_TRANSMITTER:
542 		if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
543 			pC->u.aes3tx.format = phm->u.c.param1;
544 		break;
545 	case HPI_CONTROL_AESEBU_RECEIVER:
546 		if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
547 			pC->u.aes3rx.source = phm->u.c.param1;
548 		break;
549 	case HPI_CONTROL_SAMPLECLOCK:
550 		if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
551 			pC->u.clk.source = (u16)phm->u.c.param1;
552 		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
553 			pC->u.clk.source_index = (u16)phm->u.c.param1;
554 		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
555 			pC->u.clk.sample_rate = phm->u.c.param1;
556 		break;
557 	default:
558 		break;
559 	}
560 }
561 
562 struct hpi_control_cache *hpi_alloc_control_cache(const u32
563 	number_of_controls, const u32 size_in_bytes,
564 	struct hpi_control_cache_info *pDSP_control_buffer)
565 {
566 	struct hpi_control_cache *p_cache =
567 		kmalloc(sizeof(*p_cache), GFP_KERNEL);
568 	p_cache->cache_size_in_bytes = size_in_bytes;
569 	p_cache->control_count = number_of_controls;
570 	p_cache->p_cache =
571 		(struct hpi_control_cache_single *)pDSP_control_buffer;
572 	p_cache->init = 0;
573 	p_cache->p_info =
574 		kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count,
575 		GFP_KERNEL);
576 	return p_cache;
577 }
578 
579 void hpi_free_control_cache(struct hpi_control_cache *p_cache)
580 {
581 	if (p_cache->init) {
582 		kfree(p_cache->p_info);
583 		p_cache->p_info = NULL;
584 		p_cache->init = 0;
585 		kfree(p_cache);
586 	}
587 }
588 
589 static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
590 {
591 
592 	switch (phm->function) {
593 	case HPI_SUBSYS_OPEN:
594 	case HPI_SUBSYS_CLOSE:
595 	case HPI_SUBSYS_DRIVER_UNLOAD:
596 		phr->error = 0;
597 		break;
598 	case HPI_SUBSYS_DRIVER_LOAD:
599 		wipe_adapter_list();
600 		hpios_alistlock_init(&adapters);
601 		phr->error = 0;
602 		break;
603 	case HPI_SUBSYS_GET_INFO:
604 		subsys_get_adapters(phr);
605 		break;
606 	case HPI_SUBSYS_CREATE_ADAPTER:
607 	case HPI_SUBSYS_DELETE_ADAPTER:
608 		phr->error = 0;
609 		break;
610 	default:
611 		phr->error = HPI_ERROR_INVALID_FUNC;
612 		break;
613 	}
614 }
615 
616 void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
617 {
618 	switch (phm->type) {
619 	case HPI_TYPE_MESSAGE:
620 		switch (phm->object) {
621 		case HPI_OBJ_SUBSYSTEM:
622 			subsys_message(phm, phr);
623 			break;
624 		}
625 		break;
626 
627 	default:
628 		phr->error = HPI_ERROR_INVALID_TYPE;
629 		break;
630 	}
631 }
632