1// SPDX-License-Identifier: GPL-2.0-only
2/******************************************************************************
3
4    AudioScience HPI driver
5    Copyright (C) 1997-2014  AudioScience Inc. <support@audioscience.com>
6
7
8\file hpicmn.c
9
10 Common functions used by hpixxxx.c modules
11
12(C) Copyright AudioScience Inc. 1998-2003
13*******************************************************************************/
14#define SOURCEFILE_NAME "hpicmn.c"
15
16#include "hpi_internal.h"
17#include "hpidebug.h"
18#include "hpimsginit.h"
19
20#include "hpicmn.h"
21
22struct hpi_adapters_list {
23	struct hpios_spinlock list_lock;
24	struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS];
25	u16 gw_num_adapters;
26};
27
28static struct hpi_adapters_list adapters;
29
30/**
31 * hpi_validate_response - Given an HPI Message that was sent out and
32 * a response that was received, validate that the response has the
33 * correct fields filled in, i.e ObjectType, Function etc
34 * @phm: message
35 * @phr: response
36 */
37u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
38{
39	if (phr->type != HPI_TYPE_RESPONSE) {
40		HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type);
41		return HPI_ERROR_INVALID_RESPONSE;
42	}
43
44	if (phr->object != phm->object) {
45		HPI_DEBUG_LOG(ERROR, "header object %d invalid\n",
46			phr->object);
47		return HPI_ERROR_INVALID_RESPONSE;
48	}
49
50	if (phr->function != phm->function) {
51		HPI_DEBUG_LOG(ERROR, "header function %d invalid\n",
52			phr->function);
53		return HPI_ERROR_INVALID_RESPONSE;
54	}
55
56	return 0;
57}
58
59u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
60{
61	u16 retval = 0;
62	/*HPI_ASSERT(pao->type); */
63
64	hpios_alistlock_lock(&adapters);
65
66	if (pao->index >= HPI_MAX_ADAPTERS) {
67		retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
68		goto unlock;
69	}
70
71	if (adapters.adapter[pao->index].type) {
72		int a;
73		for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
74			if (!adapters.adapter[a].type) {
75				HPI_DEBUG_LOG(WARNING,
76					"ASI%X duplicate index %d moved to %d\n",
77					pao->type, pao->index, a);
78				pao->index = a;
79				break;
80			}
81		}
82		if (a < 0) {
83			retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER;
84			goto unlock;
85		}
86	}
87	adapters.adapter[pao->index] = *pao;
88	hpios_dsplock_init(&adapters.adapter[pao->index]);
89	adapters.gw_num_adapters++;
90
91unlock:
92	hpios_alistlock_unlock(&adapters);
93	return retval;
94}
95
96void hpi_delete_adapter(struct hpi_adapter_obj *pao)
97{
98	if (!pao->type) {
99		HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
100		return;
101	}
102
103	hpios_alistlock_lock(&adapters);
104	if (adapters.adapter[pao->index].type)
105		adapters.gw_num_adapters--;
106	memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
107	hpios_alistlock_unlock(&adapters);
108}
109
110/**
111 * hpi_find_adapter - FindAdapter returns a pointer to the struct
112 * hpi_adapter_obj with index wAdapterIndex in an HPI_ADAPTERS_LIST
113 * structure.
114 * @adapter_index: value in [0, HPI_MAX_ADAPTERS[
115 */
116struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
117{
118	struct hpi_adapter_obj *pao = NULL;
119
120	if (adapter_index >= HPI_MAX_ADAPTERS) {
121		HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n",
122			adapter_index);
123		return NULL;
124	}
125
126	pao = &adapters.adapter[adapter_index];
127	if (pao->type != 0) {
128		/*
129		   HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
130		   wAdapterIndex);
131		 */
132		return pao;
133	} else {
134		/*
135		   HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
136		   wAdapterIndex);
137		 */
138		return NULL;
139	}
140}
141
142/**
143 * wipe_adapter_list - wipe an HPI_ADAPTERS_LIST structure.
144 *
145 */
146static void wipe_adapter_list(void)
147{
148	memset(&adapters, 0, sizeof(adapters));
149}
150
151static void subsys_get_adapter(struct hpi_message *phm,
152	struct hpi_response *phr)
153{
154	int count = phm->obj_index;
155	u16 index = 0;
156
157	/* find the nCount'th nonzero adapter in array */
158	for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
159		if (adapters.adapter[index].type) {
160			if (!count)
161				break;
162			count--;
163		}
164	}
165
166	if (index < HPI_MAX_ADAPTERS) {
167		phr->u.s.adapter_index = adapters.adapter[index].index;
168		phr->u.s.adapter_type = adapters.adapter[index].type;
169	} else {
170		phr->u.s.adapter_index = 0;
171		phr->u.s.adapter_type = 0;
172		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
173	}
174}
175
176static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
177{
178	unsigned int i;
179	int cached = 0;
180	if (!pC)
181		return 0;
182
183	if (pC->init)
184		return pC->init;
185
186	if (!pC->p_cache)
187		return 0;
188
189	if (pC->control_count && pC->cache_size_in_bytes) {
190		char *p_master_cache;
191		unsigned int byte_count = 0;
192
193		p_master_cache = (char *)pC->p_cache;
194		HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
195			pC->control_count);
196		for (i = 0; i < pC->control_count; i++) {
197			struct hpi_control_cache_info *info =
198				(struct hpi_control_cache_info *)
199				&p_master_cache[byte_count];
200			u16 control_index = info->control_index;
201
202			if (control_index >= pC->control_count) {
203				HPI_DEBUG_LOG(INFO,
204					"adap %d control index %d out of range, cache not ready?\n",
205					pC->adap_idx, control_index);
206				return 0;
207			}
208
209			if (!info->size_in32bit_words) {
210				if (!i) {
211					HPI_DEBUG_LOG(INFO,
212						"adap %d cache not ready?\n",
213						pC->adap_idx);
214					return 0;
215				}
216				/* The cache is invalid.
217				 * Minimum valid entry size is
218				 * sizeof(struct hpi_control_cache_info)
219				 */
220				HPI_DEBUG_LOG(ERROR,
221					"adap %d zero size cache entry %d\n",
222					pC->adap_idx, i);
223				break;
224			}
225
226			if (info->control_type) {
227				pC->p_info[control_index] = info;
228				cached++;
229			} else {	/* dummy cache entry */
230				pC->p_info[control_index] = NULL;
231			}
232
233			byte_count += info->size_in32bit_words * 4;
234
235			HPI_DEBUG_LOG(VERBOSE,
236				"cached %d, pinfo %p index %d type %d size %d\n",
237				cached, pC->p_info[info->control_index],
238				info->control_index, info->control_type,
239				info->size_in32bit_words);
240
241			/* quit loop early if whole cache has been scanned.
242			 * dwControlCount is the maximum possible entries
243			 * but some may be absent from the cache
244			 */
245			if (byte_count >= pC->cache_size_in_bytes)
246				break;
247			/* have seen last control index */
248			if (info->control_index == pC->control_count - 1)
249				break;
250		}
251
252		if (byte_count != pC->cache_size_in_bytes)
253			HPI_DEBUG_LOG(WARNING,
254				"adap %d bytecount %d != cache size %d\n",
255				pC->adap_idx, byte_count,
256				pC->cache_size_in_bytes);
257		else
258			HPI_DEBUG_LOG(DEBUG,
259				"adap %d cache good, bytecount == cache size = %d\n",
260				pC->adap_idx, byte_count);
261
262		pC->init = (u16)cached;
263	}
264	return pC->init;
265}
266
267/** Find a control.
268*/
269static short find_control(u16 control_index,
270	struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
271{
272	if (!control_cache_alloc_check(p_cache)) {
273		HPI_DEBUG_LOG(VERBOSE,
274			"control_cache_alloc_check() failed %d\n",
275			control_index);
276		return 0;
277	}
278
279	*pI = p_cache->p_info[control_index];
280	if (!*pI) {
281		HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
282			control_index);
283		return 0;
284	} else {
285		HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
286			(*pI)->control_type);
287	}
288	return 1;
289}
290
291/* allow unified treatment of several string fields within struct */
292#define HPICMN_PAD_OFS_AND_SIZE(m)  {\
293	offsetof(struct hpi_control_cache_pad, m), \
294	sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
295
296struct pad_ofs_size {
297	unsigned int offset;
298	unsigned int field_size;
299};
300
301static const struct pad_ofs_size pad_desc[] = {
302	HPICMN_PAD_OFS_AND_SIZE(c_channel),	/* HPI_PAD_CHANNEL_NAME */
303	HPICMN_PAD_OFS_AND_SIZE(c_artist),	/* HPI_PAD_ARTIST */
304	HPICMN_PAD_OFS_AND_SIZE(c_title),	/* HPI_PAD_TITLE */
305	HPICMN_PAD_OFS_AND_SIZE(c_comment),	/* HPI_PAD_COMMENT */
306};
307
308/** CheckControlCache checks the cache and fills the struct hpi_response
309 * accordingly. It returns one if a cache hit occurred, zero otherwise.
310 */
311short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
312	struct hpi_message *phm, struct hpi_response *phr)
313{
314	size_t response_size;
315	short found = 1;
316
317	/* set the default response size */
318	response_size =
319		sizeof(struct hpi_response_header) +
320		sizeof(struct hpi_control_res);
321
322	switch (pC->u.i.control_type) {
323
324	case HPI_CONTROL_METER:
325		if (phm->u.c.attribute == HPI_METER_PEAK) {
326			phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
327			phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
328		} else if (phm->u.c.attribute == HPI_METER_RMS) {
329			if (pC->u.meter.an_logRMS[0] ==
330				HPI_CACHE_INVALID_SHORT) {
331				phr->error =
332					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
333				phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
334				phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
335			} else {
336				phr->u.c.an_log_value[0] =
337					pC->u.meter.an_logRMS[0];
338				phr->u.c.an_log_value[1] =
339					pC->u.meter.an_logRMS[1];
340			}
341		} else
342			found = 0;
343		break;
344	case HPI_CONTROL_VOLUME:
345		if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
346			phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
347			phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
348		} else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
349			if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
350				if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
351					phr->u.c.param1 =
352						HPI_BITMASK_ALL_CHANNELS;
353				else
354					phr->u.c.param1 = 0;
355			} else {
356				phr->error =
357					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
358				phr->u.c.param1 = 0;
359			}
360		} else {
361			found = 0;
362		}
363		break;
364	case HPI_CONTROL_MULTIPLEXER:
365		if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
366			phr->u.c.param1 = pC->u.mux.source_node_type;
367			phr->u.c.param2 = pC->u.mux.source_node_index;
368		} else {
369			found = 0;
370		}
371		break;
372	case HPI_CONTROL_CHANNEL_MODE:
373		if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
374			phr->u.c.param1 = pC->u.mode.mode;
375		else
376			found = 0;
377		break;
378	case HPI_CONTROL_LEVEL:
379		if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
380			phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
381			phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
382		} else
383			found = 0;
384		break;
385	case HPI_CONTROL_TUNER:
386		if (phm->u.c.attribute == HPI_TUNER_FREQ)
387			phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
388		else if (phm->u.c.attribute == HPI_TUNER_BAND)
389			phr->u.c.param1 = pC->u.tuner.band;
390		else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
391			if (pC->u.tuner.s_level_avg ==
392				HPI_CACHE_INVALID_SHORT) {
393				phr->u.cu.tuner.s_level = 0;
394				phr->error =
395					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
396			} else
397				phr->u.cu.tuner.s_level =
398					pC->u.tuner.s_level_avg;
399		else
400			found = 0;
401		break;
402	case HPI_CONTROL_AESEBU_RECEIVER:
403		if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
404			phr->u.c.param1 = pC->u.aes3rx.error_status;
405		else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
406			phr->u.c.param1 = pC->u.aes3rx.format;
407		else
408			found = 0;
409		break;
410	case HPI_CONTROL_AESEBU_TRANSMITTER:
411		if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
412			phr->u.c.param1 = pC->u.aes3tx.format;
413		else
414			found = 0;
415		break;
416	case HPI_CONTROL_TONEDETECTOR:
417		if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
418			phr->u.c.param1 = pC->u.tone.state;
419		else
420			found = 0;
421		break;
422	case HPI_CONTROL_SILENCEDETECTOR:
423		if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
424			phr->u.c.param1 = pC->u.silence.state;
425		} else
426			found = 0;
427		break;
428	case HPI_CONTROL_MICROPHONE:
429		if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
430			phr->u.c.param1 = pC->u.microphone.phantom_state;
431		else
432			found = 0;
433		break;
434	case HPI_CONTROL_SAMPLECLOCK:
435		if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
436			phr->u.c.param1 = pC->u.clk.source;
437		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
438			if (pC->u.clk.source_index ==
439				HPI_CACHE_INVALID_UINT16) {
440				phr->u.c.param1 = 0;
441				phr->error =
442					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
443			} else
444				phr->u.c.param1 = pC->u.clk.source_index;
445		} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
446			phr->u.c.param1 = pC->u.clk.sample_rate;
447		else
448			found = 0;
449		break;
450	case HPI_CONTROL_PAD:{
451			struct hpi_control_cache_pad *p_pad;
452			p_pad = (struct hpi_control_cache_pad *)pC;
453
454			if (!(p_pad->field_valid_flags & (1 <<
455						HPI_CTL_ATTR_INDEX(phm->u.c.
456							attribute)))) {
457				phr->error =
458					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
459				break;
460			}
461
462			if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
463				phr->u.c.param1 = p_pad->pI;
464			else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
465				phr->u.c.param1 = p_pad->pTY;
466			else {
467				unsigned int index =
468					HPI_CTL_ATTR_INDEX(phm->u.c.
469					attribute) - 1;
470				unsigned int offset = phm->u.c.param1;
471				unsigned int pad_string_len, field_size;
472				char *pad_string;
473				unsigned int tocopy;
474
475				if (index > ARRAY_SIZE(pad_desc) - 1) {
476					phr->error =
477						HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
478					break;
479				}
480
481				pad_string =
482					((char *)p_pad) +
483					pad_desc[index].offset;
484				field_size = pad_desc[index].field_size;
485				/* Ensure null terminator */
486				pad_string[field_size - 1] = 0;
487
488				pad_string_len = strlen(pad_string) + 1;
489
490				if (offset > pad_string_len) {
491					phr->error =
492						HPI_ERROR_INVALID_CONTROL_VALUE;
493					break;
494				}
495
496				tocopy = pad_string_len - offset;
497				if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
498					tocopy = sizeof(phr->u.cu.chars8.
499						sz_data);
500
501				memcpy(phr->u.cu.chars8.sz_data,
502					&pad_string[offset], tocopy);
503
504				phr->u.cu.chars8.remaining_chars =
505					pad_string_len - offset - tocopy;
506			}
507		}
508		break;
509	default:
510		found = 0;
511		break;
512	}
513
514	HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
515		found ? "Cached" : "Uncached", phm->adapter_index,
516		pC->u.i.control_index, pC->u.i.control_type,
517		phm->u.c.attribute);
518
519	if (found) {
520		phr->size = (u16)response_size;
521		phr->type = HPI_TYPE_RESPONSE;
522		phr->object = phm->object;
523		phr->function = phm->function;
524	}
525
526	return found;
527}
528
529short hpi_check_control_cache(struct hpi_control_cache *p_cache,
530	struct hpi_message *phm, struct hpi_response *phr)
531{
532	struct hpi_control_cache_info *pI;
533
534	if (!find_control(phm->obj_index, p_cache, &pI)) {
535		HPI_DEBUG_LOG(VERBOSE,
536			"HPICMN find_control() failed for adap %d\n",
537			phm->adapter_index);
538		return 0;
539	}
540
541	phr->error = 0;
542	phr->specific_error = 0;
543	phr->version = 0;
544
545	return hpi_check_control_cache_single((struct hpi_control_cache_single
546			*)pI, phm, phr);
547}
548
549/** Updates the cache with Set values.
550
551Only update if no error.
552Volume and Level return the limited values in the response, so use these
553Multiplexer does so use sent values
554*/
555void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
556	*pC, struct hpi_message *phm, struct hpi_response *phr)
557{
558	switch (pC->u.i.control_type) {
559	case HPI_CONTROL_VOLUME:
560		if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
561			pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
562			pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
563		} else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
564			if (phm->u.c.param1)
565				pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
566			else
567				pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
568		}
569		break;
570	case HPI_CONTROL_MULTIPLEXER:
571		/* mux does not return its setting on Set command. */
572		if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
573			pC->u.mux.source_node_type = (u16)phm->u.c.param1;
574			pC->u.mux.source_node_index = (u16)phm->u.c.param2;
575		}
576		break;
577	case HPI_CONTROL_CHANNEL_MODE:
578		/* mode does not return its setting on Set command. */
579		if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
580			pC->u.mode.mode = (u16)phm->u.c.param1;
581		break;
582	case HPI_CONTROL_LEVEL:
583		if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
584			pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
585			pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
586		}
587		break;
588	case HPI_CONTROL_MICROPHONE:
589		if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
590			pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
591		break;
592	case HPI_CONTROL_AESEBU_TRANSMITTER:
593		if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
594			pC->u.aes3tx.format = phm->u.c.param1;
595		break;
596	case HPI_CONTROL_AESEBU_RECEIVER:
597		if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
598			pC->u.aes3rx.format = phm->u.c.param1;
599		break;
600	case HPI_CONTROL_SAMPLECLOCK:
601		if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
602			pC->u.clk.source = (u16)phm->u.c.param1;
603		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
604			pC->u.clk.source_index = (u16)phm->u.c.param1;
605		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
606			pC->u.clk.sample_rate = phm->u.c.param1;
607		break;
608	default:
609		break;
610	}
611}
612
613void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
614	struct hpi_message *phm, struct hpi_response *phr)
615{
616	struct hpi_control_cache_single *pC;
617	struct hpi_control_cache_info *pI;
618
619	if (phr->error)
620		return;
621
622	if (!find_control(phm->obj_index, p_cache, &pI)) {
623		HPI_DEBUG_LOG(VERBOSE,
624			"HPICMN find_control() failed for adap %d\n",
625			phm->adapter_index);
626		return;
627	}
628
629	/* pC is the default cached control strucure.
630	   May be cast to something else in the following switch statement.
631	 */
632	pC = (struct hpi_control_cache_single *)pI;
633
634	hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr);
635}
636
637/** Allocate control cache.
638
639\return Cache pointer, or NULL if allocation fails.
640*/
641struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
642	const u32 size_in_bytes, u8 *p_dsp_control_buffer)
643{
644	struct hpi_control_cache *p_cache =
645		kmalloc(sizeof(*p_cache), GFP_KERNEL);
646	if (!p_cache)
647		return NULL;
648
649	p_cache->p_info =
650		kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL);
651	if (!p_cache->p_info) {
652		kfree(p_cache);
653		return NULL;
654	}
655
656	p_cache->cache_size_in_bytes = size_in_bytes;
657	p_cache->control_count = control_count;
658	p_cache->p_cache = p_dsp_control_buffer;
659	p_cache->init = 0;
660	return p_cache;
661}
662
663void hpi_free_control_cache(struct hpi_control_cache *p_cache)
664{
665	if (p_cache) {
666		kfree(p_cache->p_info);
667		kfree(p_cache);
668	}
669}
670
671static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
672{
673	hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
674
675	switch (phm->function) {
676	case HPI_SUBSYS_OPEN:
677	case HPI_SUBSYS_CLOSE:
678	case HPI_SUBSYS_DRIVER_UNLOAD:
679		break;
680	case HPI_SUBSYS_DRIVER_LOAD:
681		wipe_adapter_list();
682		hpios_alistlock_init(&adapters);
683		break;
684	case HPI_SUBSYS_GET_ADAPTER:
685		subsys_get_adapter(phm, phr);
686		break;
687	case HPI_SUBSYS_GET_NUM_ADAPTERS:
688		phr->u.s.num_adapters = adapters.gw_num_adapters;
689		break;
690	case HPI_SUBSYS_CREATE_ADAPTER:
691		break;
692	default:
693		phr->error = HPI_ERROR_INVALID_FUNC;
694		break;
695	}
696}
697
698void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
699{
700	switch (phm->type) {
701	case HPI_TYPE_REQUEST:
702		switch (phm->object) {
703		case HPI_OBJ_SUBSYSTEM:
704			subsys_message(phm, phr);
705			break;
706		}
707		break;
708
709	default:
710		phr->error = HPI_ERROR_INVALID_TYPE;
711		break;
712	}
713}
714