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