Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / sound / pci / asihpi / hpicmn.c
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 }