]> Pileus Git - ~andy/linux/blob - drivers/staging/tidspbridge/rmgr/dbdcd.c
Merge branch 'slab/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penber...
[~andy/linux] / drivers / staging / tidspbridge / rmgr / dbdcd.c
1 /*
2  * dbdcd.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * This file contains the implementation of the DSP/BIOS Bridge
7  * Configuration Database (DCD).
8  *
9  * Notes:
10  *   The fxn dcd_get_objects can apply a callback fxn to each DCD object
11  *   that is located in a specified COFF file.  At the moment,
12  *   dcd_auto_register, dcd_auto_unregister, and NLDR module all use
13  *   dcd_get_objects.
14  *
15  * Copyright (C) 2005-2006 Texas Instruments, Inc.
16  *
17  * This package is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License version 2 as
19  * published by the Free Software Foundation.
20  *
21  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24  */
25 #include <linux/types.h>
26
27 /*  ----------------------------------- Host OS */
28 #include <dspbridge/host_os.h>
29
30 /*  ----------------------------------- DSP/BIOS Bridge */
31 #include <dspbridge/dbdefs.h>
32
33 /*  ----------------------------------- Platform Manager */
34 #include <dspbridge/cod.h>
35
36 /*  ----------------------------------- Others */
37 #include <dspbridge/uuidutil.h>
38
39 /*  ----------------------------------- This */
40 #include <dspbridge/dbdcd.h>
41
42 /*  ----------------------------------- Global defines. */
43 #define MAX_INT2CHAR_LENGTH     16      /* Max int2char len of 32 bit int */
44
45 /* Name of section containing dependent libraries */
46 #define DEPLIBSECT              ".dspbridge_deplibs"
47
48 /* DCD specific structures. */
49 struct dcd_manager {
50         struct cod_manager *cod_mgr;    /* Handle to COD manager object. */
51 };
52
53 /*  Pointer to the registry support key */
54 static struct list_head reg_key_list;
55 static DEFINE_SPINLOCK(dbdcd_lock);
56
57 /* Global reference variables. */
58 static u32 refs;
59 static u32 enum_refs;
60
61 /* Helper function prototypes. */
62 static s32 atoi(char *psz_buf);
63 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
64                                      enum dsp_dcdobjtype obj_type,
65                                      struct dcd_genericobj *gen_obj);
66 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
67 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
68 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
69                                    struct dsp_uuid *uuid_obj,
70                                    u16 *num_libs,
71                                    u16 *num_pers_libs,
72                                    struct dsp_uuid *dep_lib_uuids,
73                                    bool *prstnt_dep_libs,
74                                    enum nldr_phase phase);
75
76 /*
77  *  ======== dcd_auto_register ========
78  *  Purpose:
79  *      Parses the supplied image and resigsters with DCD.
80  */
81 int dcd_auto_register(struct dcd_manager *hdcd_mgr,
82                              char *sz_coff_path)
83 {
84         int status = 0;
85
86         if (hdcd_mgr)
87                 status = dcd_get_objects(hdcd_mgr, sz_coff_path,
88                                          (dcd_registerfxn) dcd_register_object,
89                                          (void *)sz_coff_path);
90         else
91                 status = -EFAULT;
92
93         return status;
94 }
95
96 /*
97  *  ======== dcd_auto_unregister ========
98  *  Purpose:
99  *      Parses the supplied DSP image and unresiters from DCD.
100  */
101 int dcd_auto_unregister(struct dcd_manager *hdcd_mgr,
102                                char *sz_coff_path)
103 {
104         int status = 0;
105
106         if (hdcd_mgr)
107                 status = dcd_get_objects(hdcd_mgr, sz_coff_path,
108                                          (dcd_registerfxn) dcd_register_object,
109                                          NULL);
110         else
111                 status = -EFAULT;
112
113         return status;
114 }
115
116 /*
117  *  ======== dcd_create_manager ========
118  *  Purpose:
119  *      Creates DCD manager.
120  */
121 int dcd_create_manager(char *sz_zl_dll_name,
122                               struct dcd_manager **dcd_mgr)
123 {
124         struct cod_manager *cod_mgr;    /* COD manager handle */
125         struct dcd_manager *dcd_mgr_obj = NULL; /* DCD Manager pointer */
126         int status = 0;
127
128         status = cod_create(&cod_mgr, sz_zl_dll_name);
129         if (status)
130                 goto func_end;
131
132         /* Create a DCD object. */
133         dcd_mgr_obj = kzalloc(sizeof(struct dcd_manager), GFP_KERNEL);
134         if (dcd_mgr_obj != NULL) {
135                 /* Fill out the object. */
136                 dcd_mgr_obj->cod_mgr = cod_mgr;
137
138                 /* Return handle to this DCD interface. */
139                 *dcd_mgr = dcd_mgr_obj;
140         } else {
141                 status = -ENOMEM;
142
143                 /*
144                  * If allocation of DcdManager object failed, delete the
145                  * COD manager.
146                  */
147                 cod_delete(cod_mgr);
148         }
149
150 func_end:
151         return status;
152 }
153
154 /*
155  *  ======== dcd_destroy_manager ========
156  *  Purpose:
157  *      Frees DCD Manager object.
158  */
159 int dcd_destroy_manager(struct dcd_manager *hdcd_mgr)
160 {
161         struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
162         int status = -EFAULT;
163
164         if (hdcd_mgr) {
165                 /* Delete the COD manager. */
166                 cod_delete(dcd_mgr_obj->cod_mgr);
167
168                 /* Deallocate a DCD manager object. */
169                 kfree(dcd_mgr_obj);
170
171                 status = 0;
172         }
173
174         return status;
175 }
176
177 /*
178  *  ======== dcd_enumerate_object ========
179  *  Purpose:
180  *      Enumerates objects in the DCD.
181  */
182 int dcd_enumerate_object(s32 index, enum dsp_dcdobjtype obj_type,
183                                 struct dsp_uuid *uuid_obj)
184 {
185         int status = 0;
186         char sz_reg_key[DCD_MAXPATHLENGTH];
187         char sz_value[DCD_MAXPATHLENGTH];
188         struct dsp_uuid dsp_uuid_obj;
189         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
190         u32 dw_key_len = 0;
191         struct dcd_key_elem *dcd_key;
192         int len;
193
194         if ((index != 0) && (enum_refs == 0)) {
195                 /*
196                  * If an enumeration is being performed on an index greater
197                  * than zero, then the current enum_refs must have been
198                  * incremented to greater than zero.
199                  */
200                 status = -EIDRM;
201         } else {
202                 /*
203                  * Pre-determine final key length. It's length of DCD_REGKEY +
204                  *  "_\0" + length of sz_obj_type string + terminating NULL.
205                  */
206                 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
207
208                 /* Create proper REG key; concatenate DCD_REGKEY with
209                  * obj_type. */
210                 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
211                 if ((strlen(sz_reg_key) + strlen("_\0")) <
212                     DCD_MAXPATHLENGTH) {
213                         strncat(sz_reg_key, "_\0", 2);
214                 } else {
215                         status = -EPERM;
216                 }
217
218                 /* This snprintf is guaranteed not to exceed max size of an
219                  * integer. */
220                 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d",
221                                   obj_type);
222
223                 if (status == -1) {
224                         status = -EPERM;
225                 } else {
226                         status = 0;
227                         if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
228                             DCD_MAXPATHLENGTH) {
229                                 strncat(sz_reg_key, sz_obj_type,
230                                         strlen(sz_obj_type) + 1);
231                         } else {
232                                 status = -EPERM;
233                         }
234                 }
235
236                 if (!status) {
237                         len = strlen(sz_reg_key);
238                         spin_lock(&dbdcd_lock);
239                         list_for_each_entry(dcd_key, &reg_key_list, link) {
240                                 if (!strncmp(dcd_key->name, sz_reg_key, len)
241                                                 && !index--) {
242                                         strncpy(sz_value, &dcd_key->name[len],
243                                                strlen(&dcd_key->name[len]) + 1);
244                                                 break;
245                                 }
246                         }
247                         spin_unlock(&dbdcd_lock);
248
249                         if (&dcd_key->link == &reg_key_list)
250                                 status = -ENODATA;
251                 }
252
253                 if (!status) {
254                         /* Create UUID value using string retrieved from
255                          * registry. */
256                         uuid_uuid_from_string(sz_value, &dsp_uuid_obj);
257
258                         *uuid_obj = dsp_uuid_obj;
259
260                         /* Increment enum_refs to update reference count. */
261                         enum_refs++;
262
263                         status = 0;
264                 } else if (status == -ENODATA) {
265                         /* At the end of enumeration. Reset enum_refs. */
266                         enum_refs = 0;
267
268                         /*
269                          * TODO: Revisit, this is not an error case but code
270                          * expects non-zero value.
271                          */
272                         status = ENODATA;
273                 } else {
274                         status = -EPERM;
275                 }
276         }
277
278         return status;
279 }
280
281 /*
282  *  ======== dcd_exit ========
283  *  Purpose:
284  *      Discontinue usage of the DCD module.
285  */
286 void dcd_exit(void)
287 {
288         struct dcd_key_elem *rv, *rv_tmp;
289
290         refs--;
291         if (refs == 0) {
292                 list_for_each_entry_safe(rv, rv_tmp, &reg_key_list, link) {
293                         list_del(&rv->link);
294                         kfree(rv->path);
295                         kfree(rv);
296                 }
297         }
298
299 }
300
301 /*
302  *  ======== dcd_get_dep_libs ========
303  */
304 int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr,
305                             struct dsp_uuid *uuid_obj,
306                             u16 num_libs, struct dsp_uuid *dep_lib_uuids,
307                             bool *prstnt_dep_libs,
308                             enum nldr_phase phase)
309 {
310         int status = 0;
311
312         status =
313             get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
314                              prstnt_dep_libs, phase);
315
316         return status;
317 }
318
319 /*
320  *  ======== dcd_get_num_dep_libs ========
321  */
322 int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr,
323                                 struct dsp_uuid *uuid_obj,
324                                 u16 *num_libs, u16 *num_pers_libs,
325                                 enum nldr_phase phase)
326 {
327         int status = 0;
328
329         status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs,
330                                   NULL, NULL, phase);
331
332         return status;
333 }
334
335 /*
336  *  ======== dcd_get_object_def ========
337  *  Purpose:
338  *      Retrieves the properties of a node or processor based on the UUID and
339  *      object type.
340  */
341 int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
342                               struct dsp_uuid *obj_uuid,
343                               enum dsp_dcdobjtype obj_type,
344                               struct dcd_genericobj *obj_def)
345 {
346         struct dcd_manager *dcd_mgr_obj = hdcd_mgr;     /* ptr to DCD mgr */
347         struct cod_libraryobj *lib = NULL;
348         int status = 0;
349         int len;
350         u32 ul_addr = 0;        /* Used by cod_get_section */
351         u32 ul_len = 0;         /* Used by cod_get_section */
352         u32 dw_buf_size;        /* Used by REG functions */
353         char sz_reg_key[DCD_MAXPATHLENGTH];
354         char *sz_uuid;          /*[MAXUUIDLEN]; */
355         char *tmp;
356         struct dcd_key_elem *dcd_key = NULL;
357         char sz_sect_name[MAXUUIDLEN + 2];      /* ".[UUID]\0" */
358         char *psz_coff_buf;
359         u32 dw_key_len;         /* Len of REG key. */
360         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
361
362         sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
363         if (!sz_uuid) {
364                 status = -ENOMEM;
365                 goto func_end;
366         }
367
368         if (!hdcd_mgr) {
369                 status = -EFAULT;
370                 goto func_end;
371         }
372
373         /* Pre-determine final key length. It's length of DCD_REGKEY +
374          *  "_\0" + length of sz_obj_type string + terminating NULL */
375         dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
376
377         /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
378         strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
379
380         if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
381                 strncat(sz_reg_key, "_\0", 2);
382         else
383                 status = -EPERM;
384
385         status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
386         if (status == -1) {
387                 status = -EPERM;
388         } else {
389                 status = 0;
390
391                 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
392                     DCD_MAXPATHLENGTH) {
393                         strncat(sz_reg_key, sz_obj_type,
394                                 strlen(sz_obj_type) + 1);
395                 } else {
396                         status = -EPERM;
397                 }
398
399                 /* Create UUID value to set in registry. */
400                 snprintf(sz_uuid, MAXUUIDLEN, "%pUL", obj_uuid);
401
402                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
403                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
404                 else
405                         status = -EPERM;
406
407                 /* Retrieve paths from the registry based on struct dsp_uuid */
408                 dw_buf_size = DCD_MAXPATHLENGTH;
409         }
410         if (!status) {
411                 spin_lock(&dbdcd_lock);
412                 list_for_each_entry(dcd_key, &reg_key_list, link) {
413                         if (!strncmp(dcd_key->name, sz_reg_key,
414                                                 strlen(sz_reg_key) + 1))
415                                 break;
416                 }
417                 spin_unlock(&dbdcd_lock);
418                 if (&dcd_key->link == &reg_key_list) {
419                         status = -ENOKEY;
420                         goto func_end;
421                 }
422         }
423
424
425         /* Open COFF file. */
426         status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
427                                                         COD_NOLOAD, &lib);
428         if (status) {
429                 status = -EACCES;
430                 goto func_end;
431         }
432
433         /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
434         len = strlen(sz_uuid);
435         if (len + 1 > sizeof(sz_sect_name)) {
436                 status = -EPERM;
437                 goto func_end;
438         }
439
440         /* Create section name based on node UUID. A period is
441          * pre-pended to the UUID string to form the section name.
442          * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
443
444         len -= 4;       /* uuid has 4 delimiters '-' */
445         tmp = sz_uuid;
446
447         strncpy(sz_sect_name, ".", 2);
448         do {
449                 char *uuid = strsep(&tmp, "-");
450                 if (!uuid)
451                         break;
452                 len -= strlen(uuid);
453                 strncat(sz_sect_name, uuid, strlen(uuid) + 1);
454         } while (len && strncat(sz_sect_name, "_", 2));
455
456         /* Get section information. */
457         status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
458         if (status) {
459                 status = -EACCES;
460                 goto func_end;
461         }
462
463         /* Allocate zeroed buffer. */
464         psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
465         if (psz_coff_buf == NULL) {
466                 status = -ENOMEM;
467                 goto func_end;
468         }
469 #ifdef _DB_TIOMAP
470         if (strstr(dcd_key->path, "iva") == NULL) {
471                 /* Locate section by objectID and read its content. */
472                 status =
473                     cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
474         } else {
475                 status =
476                     cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
477                 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
478         }
479 #else
480         status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
481 #endif
482         if (!status) {
483                 /* Compress DSP buffer to conform to PC format. */
484                 if (strstr(dcd_key->path, "iva") == NULL) {
485                         compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
486                 } else {
487                         compress_buf(psz_coff_buf, ul_len, 1);
488                         dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
489                                 "for IVA!!\n", __func__);
490                 }
491
492                 /* Parse the content of the COFF buffer. */
493                 status =
494                     get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
495                 if (status)
496                         status = -EACCES;
497         } else {
498                 status = -EACCES;
499         }
500
501         /* Free the previously allocated dynamic buffer. */
502         kfree(psz_coff_buf);
503 func_end:
504         if (lib)
505                 cod_close(lib);
506
507         kfree(sz_uuid);
508
509         return status;
510 }
511
512 /*
513  *  ======== dcd_get_objects ========
514  */
515 int dcd_get_objects(struct dcd_manager *hdcd_mgr,
516                            char *sz_coff_path, dcd_registerfxn register_fxn,
517                            void *handle)
518 {
519         struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
520         int status = 0;
521         char *psz_coff_buf;
522         char *psz_cur;
523         struct cod_libraryobj *lib = NULL;
524         u32 ul_addr = 0;        /* Used by cod_get_section */
525         u32 ul_len = 0;         /* Used by cod_get_section */
526         char seps[] = ":, ";
527         char *token = NULL;
528         struct dsp_uuid dsp_uuid_obj;
529         s32 object_type;
530
531         if (!hdcd_mgr) {
532                 status = -EFAULT;
533                 goto func_end;
534         }
535
536         /* Open DSP coff file, don't load symbols. */
537         status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
538         if (status) {
539                 status = -EACCES;
540                 goto func_cont;
541         }
542
543         /* Get DCD_RESIGER_SECTION section information. */
544         status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
545         if (status || !(ul_len > 0)) {
546                 status = -EACCES;
547                 goto func_cont;
548         }
549
550         /* Allocate zeroed buffer. */
551         psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
552         if (psz_coff_buf == NULL) {
553                 status = -ENOMEM;
554                 goto func_cont;
555         }
556 #ifdef _DB_TIOMAP
557         if (strstr(sz_coff_path, "iva") == NULL) {
558                 /* Locate section by objectID and read its content. */
559                 status = cod_read_section(lib, DCD_REGISTER_SECTION,
560                                           psz_coff_buf, ul_len);
561         } else {
562                 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
563                 status = cod_read_section(lib, DCD_REGISTER_SECTION,
564                                           psz_coff_buf, ul_len);
565         }
566 #else
567         status =
568             cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
569 #endif
570         if (!status) {
571                 /* Compress DSP buffer to conform to PC format. */
572                 if (strstr(sz_coff_path, "iva") == NULL) {
573                         compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
574                 } else {
575                         compress_buf(psz_coff_buf, ul_len, 1);
576                         dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
577                                 "for IVA!!\n", __func__);
578                 }
579
580                 /* Read from buffer and register object in buffer. */
581                 psz_cur = psz_coff_buf;
582                 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
583                         /*  Retrieve UUID string. */
584                         uuid_uuid_from_string(token, &dsp_uuid_obj);
585
586                         /*  Retrieve object type */
587                         token = strsep(&psz_cur, seps);
588
589                         /*  Retrieve object type */
590                         object_type = atoi(token);
591
592                         /*
593                          *  Apply register_fxn to the found DCD object.
594                          *  Possible actions include:
595                          *
596                          *  1) Register found DCD object.
597                          *  2) Unregister found DCD object (when handle == NULL)
598                          *  3) Add overlay node.
599                          */
600                         status =
601                             register_fxn(&dsp_uuid_obj, object_type, handle);
602                         if (status) {
603                                 /* if error occurs, break from while loop. */
604                                 break;
605                         }
606                 }
607         } else {
608                 status = -EACCES;
609         }
610
611         /* Free the previously allocated dynamic buffer. */
612         kfree(psz_coff_buf);
613 func_cont:
614         if (lib)
615                 cod_close(lib);
616
617 func_end:
618         return status;
619 }
620
621 /*
622  *  ======== dcd_get_library_name ========
623  *  Purpose:
624  *      Retrieves the library name for the given UUID.
625  *
626  */
627 int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
628                                 struct dsp_uuid *uuid_obj,
629                                 char *str_lib_name,
630                                 u32 *buff_size,
631                                 enum nldr_phase phase, bool *phase_split)
632 {
633         char sz_reg_key[DCD_MAXPATHLENGTH];
634         char sz_uuid[MAXUUIDLEN];
635         u32 dw_key_len;         /* Len of REG key. */
636         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
637         int status = 0;
638         struct dcd_key_elem *dcd_key = NULL;
639
640         dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
641                 " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
642                 buff_size);
643
644         /*
645          *  Pre-determine final key length. It's length of DCD_REGKEY +
646          *  "_\0" + length of sz_obj_type string + terminating NULL.
647          */
648         dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
649
650         /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
651         strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
652         if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
653                 strncat(sz_reg_key, "_\0", 2);
654         else
655                 status = -EPERM;
656
657         switch (phase) {
658         case NLDR_CREATE:
659                 /* create phase type */
660                 sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
661                 break;
662         case NLDR_EXECUTE:
663                 /* execute phase type */
664                 sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
665                 break;
666         case NLDR_DELETE:
667                 /* delete phase type */
668                 sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
669                 break;
670         case NLDR_NOPHASE:
671                 /* known to be a dependent library */
672                 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
673                 break;
674         default:
675                 status = -EINVAL;
676         }
677         if (!status) {
678                 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
679                     DCD_MAXPATHLENGTH) {
680                         strncat(sz_reg_key, sz_obj_type,
681                                 strlen(sz_obj_type) + 1);
682                 } else {
683                         status = -EPERM;
684                 }
685                 /* Create UUID value to find match in registry. */
686                 snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj);
687                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
688                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
689                 else
690                         status = -EPERM;
691         }
692         if (!status) {
693                 spin_lock(&dbdcd_lock);
694                 list_for_each_entry(dcd_key, &reg_key_list, link) {
695                         /*  See if the name matches. */
696                         if (!strncmp(dcd_key->name, sz_reg_key,
697                                                 strlen(sz_reg_key) + 1))
698                                 break;
699                 }
700                 spin_unlock(&dbdcd_lock);
701         }
702
703         if (&dcd_key->link == &reg_key_list)
704                 status = -ENOKEY;
705
706         /* If can't find, phases might be registered as generic LIBRARYTYPE */
707         if (status && phase != NLDR_NOPHASE) {
708                 if (phase_split)
709                         *phase_split = false;
710
711                 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
712                 if ((strlen(sz_reg_key) + strlen("_\0")) <
713                     DCD_MAXPATHLENGTH) {
714                         strncat(sz_reg_key, "_\0", 2);
715                 } else {
716                         status = -EPERM;
717                 }
718                 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
719                 if ((strlen(sz_reg_key) + strlen(sz_obj_type))
720                     < DCD_MAXPATHLENGTH) {
721                         strncat(sz_reg_key, sz_obj_type,
722                                 strlen(sz_obj_type) + 1);
723                 } else {
724                         status = -EPERM;
725                 }
726                 snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj);
727                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
728                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
729                 else
730                         status = -EPERM;
731
732                 spin_lock(&dbdcd_lock);
733                 list_for_each_entry(dcd_key, &reg_key_list, link) {
734                         /*  See if the name matches. */
735                         if (!strncmp(dcd_key->name, sz_reg_key,
736                                                 strlen(sz_reg_key) + 1))
737                                 break;
738                 }
739                 spin_unlock(&dbdcd_lock);
740
741                 status = (&dcd_key->link != &reg_key_list) ?
742                                                 0 : -ENOKEY;
743         }
744
745         if (!status)
746                 memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
747         return status;
748 }
749
750 /*
751  *  ======== dcd_init ========
752  *  Purpose:
753  *      Initialize the DCD module.
754  */
755 bool dcd_init(void)
756 {
757         bool ret = true;
758
759         if (refs == 0)
760                 INIT_LIST_HEAD(&reg_key_list);
761
762         if (ret)
763                 refs++;
764
765         return ret;
766 }
767
768 /*
769  *  ======== dcd_register_object ========
770  *  Purpose:
771  *      Registers a node or a processor with the DCD.
772  *      If psz_path_name == NULL, unregister the specified DCD object.
773  */
774 int dcd_register_object(struct dsp_uuid *uuid_obj,
775                                enum dsp_dcdobjtype obj_type,
776                                char *psz_path_name)
777 {
778         int status = 0;
779         char sz_reg_key[DCD_MAXPATHLENGTH];
780         char sz_uuid[MAXUUIDLEN + 1];
781         u32 dw_path_size = 0;
782         u32 dw_key_len;         /* Len of REG key. */
783         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
784         struct dcd_key_elem *dcd_key = NULL;
785
786         dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
787                 __func__, uuid_obj, obj_type, psz_path_name);
788
789         /*
790          * Pre-determine final key length. It's length of DCD_REGKEY +
791          *  "_\0" + length of sz_obj_type string + terminating NULL.
792          */
793         dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
794
795         /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
796         strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
797         if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
798                 strncat(sz_reg_key, "_\0", 2);
799         else {
800                 status = -EPERM;
801                 goto func_end;
802         }
803
804         status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
805         if (status == -1) {
806                 status = -EPERM;
807         } else {
808                 status = 0;
809                 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
810                     DCD_MAXPATHLENGTH) {
811                         strncat(sz_reg_key, sz_obj_type,
812                                 strlen(sz_obj_type) + 1);
813                 } else
814                         status = -EPERM;
815
816                 /* Create UUID value to set in registry. */
817                 snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj);
818                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
819                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
820                 else
821                         status = -EPERM;
822         }
823
824         if (status)
825                 goto func_end;
826
827         /*
828          * If psz_path_name != NULL, perform registration, otherwise,
829          * perform unregistration.
830          */
831
832         if (psz_path_name) {
833                 dw_path_size = strlen(psz_path_name) + 1;
834                 spin_lock(&dbdcd_lock);
835                 list_for_each_entry(dcd_key, &reg_key_list, link) {
836                         /*  See if the name matches. */
837                         if (!strncmp(dcd_key->name, sz_reg_key,
838                                                 strlen(sz_reg_key) + 1))
839                                 break;
840                 }
841                 spin_unlock(&dbdcd_lock);
842                 if (&dcd_key->link == &reg_key_list) {
843                         /*
844                          * Add new reg value (UUID+obj_type)
845                          * with COFF path info
846                          */
847
848                         dcd_key = kmalloc(sizeof(struct dcd_key_elem),
849                                                                 GFP_KERNEL);
850                         if (!dcd_key) {
851                                 status = -ENOMEM;
852                                 goto func_end;
853                         }
854
855                         dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
856                                                                 GFP_KERNEL);
857
858                         if (!dcd_key->path) {
859                                 kfree(dcd_key);
860                                 status = -ENOMEM;
861                                 goto func_end;
862                         }
863
864                         strncpy(dcd_key->name, sz_reg_key,
865                                                 strlen(sz_reg_key) + 1);
866                         strncpy(dcd_key->path, psz_path_name ,
867                                                 dw_path_size);
868                         spin_lock(&dbdcd_lock);
869                         list_add_tail(&dcd_key->link, &reg_key_list);
870                         spin_unlock(&dbdcd_lock);
871                 } else {
872                         /*  Make sure the new data is the same. */
873                         if (strncmp(dcd_key->path, psz_path_name,
874                                                         dw_path_size)) {
875                                 /*  The caller needs a different data size! */
876                                 kfree(dcd_key->path);
877                                 dcd_key->path = kmalloc(dw_path_size,
878                                                                 GFP_KERNEL);
879                                 if (dcd_key->path == NULL) {
880                                         status = -ENOMEM;
881                                         goto func_end;
882                                 }
883                         }
884
885                         /*  We have a match!  Copy out the data. */
886                         memcpy(dcd_key->path, psz_path_name, dw_path_size);
887                 }
888                 dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
889                         __func__, psz_path_name, dw_path_size);
890         } else {
891                 /* Deregister an existing object */
892                 spin_lock(&dbdcd_lock);
893                 list_for_each_entry(dcd_key, &reg_key_list, link) {
894                         if (!strncmp(dcd_key->name, sz_reg_key,
895                                                 strlen(sz_reg_key) + 1)) {
896                                 list_del(&dcd_key->link);
897                                 kfree(dcd_key->path);
898                                 kfree(dcd_key);
899                                 break;
900                         }
901                 }
902                 spin_unlock(&dbdcd_lock);
903                 if (&dcd_key->link == &reg_key_list)
904                         status = -EPERM;
905         }
906
907         if (!status) {
908                 /*
909                  *  Because the node database has been updated through a
910                  *  successful object registration/de-registration operation,
911                  *  we need to reset the object enumeration counter to allow
912                  *  current enumerations to reflect this update in the node
913                  *  database.
914                  */
915                 enum_refs = 0;
916         }
917 func_end:
918         return status;
919 }
920
921 /*
922  *  ======== dcd_unregister_object ========
923  *  Call DCD_Register object with psz_path_name set to NULL to
924  *  perform actual object de-registration.
925  */
926 int dcd_unregister_object(struct dsp_uuid *uuid_obj,
927                                  enum dsp_dcdobjtype obj_type)
928 {
929         int status = 0;
930
931         /*
932          *  When dcd_register_object is called with NULL as pathname,
933          *  it indicates an unregister object operation.
934          */
935         status = dcd_register_object(uuid_obj, obj_type, NULL);
936
937         return status;
938 }
939
940 /*
941  **********************************************************************
942  * DCD Helper Functions
943  **********************************************************************
944  */
945
946 /*
947  *  ======== atoi ========
948  *  Purpose:
949  *      This function converts strings in decimal or hex format to integers.
950  */
951 static s32 atoi(char *psz_buf)
952 {
953         char *pch = psz_buf;
954         s32 base = 0;
955
956         while (isspace(*pch))
957                 pch++;
958
959         if (*pch == '-' || *pch == '+') {
960                 base = 10;
961                 pch++;
962         } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
963                 base = 16;
964         }
965
966         return simple_strtoul(pch, NULL, base);
967 }
968
969 /*
970  *  ======== get_attrs_from_buf ========
971  *  Purpose:
972  *      Parse the content of a buffer filled with DSP-side data and
973  *      retrieve an object's attributes from it. IMPORTANT: Assume the
974  *      buffer has been converted from DSP format to GPP format.
975  */
976 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
977                                      enum dsp_dcdobjtype obj_type,
978                                      struct dcd_genericobj *gen_obj)
979 {
980         int status = 0;
981         char seps[] = ", ";
982         char *psz_cur;
983         char *token;
984         s32 token_len = 0;
985         u32 i = 0;
986 #ifdef _DB_TIOMAP
987         s32 entry_id;
988 #endif
989
990         switch (obj_type) {
991         case DSP_DCDNODETYPE:
992                 /*
993                  * Parse COFF sect buffer to retrieve individual tokens used
994                  * to fill in object attrs.
995                  */
996                 psz_cur = psz_buf;
997                 token = strsep(&psz_cur, seps);
998
999                 /* u32 cb_struct */
1000                 gen_obj->obj_data.node_obj.ndb_props.cb_struct =
1001                     (u32) atoi(token);
1002                 token = strsep(&psz_cur, seps);
1003
1004                 /* dsp_uuid ui_node_id */
1005                 uuid_uuid_from_string(token,
1006                                       &gen_obj->obj_data.node_obj.ndb_props.
1007                                       ui_node_id);
1008                 token = strsep(&psz_cur, seps);
1009
1010                 /* ac_name */
1011                 token_len = strlen(token);
1012                 if (token_len > DSP_MAXNAMELEN - 1)
1013                         token_len = DSP_MAXNAMELEN - 1;
1014
1015                 strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
1016                         token, token_len);
1017                 gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1018                 token = strsep(&psz_cur, seps);
1019                 /* u32 ntype */
1020                 gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1021                 token = strsep(&psz_cur, seps);
1022                 /* u32 cache_on_gpp */
1023                 gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1024                 token = strsep(&psz_cur, seps);
1025                 /* dsp_resourcereqmts dsp_resource_reqmts */
1026                 gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1027                     cb_struct = (u32) atoi(token);
1028                 token = strsep(&psz_cur, seps);
1029
1030                 gen_obj->obj_data.node_obj.ndb_props.
1031                     dsp_resource_reqmts.static_data_size = atoi(token);
1032                 token = strsep(&psz_cur, seps);
1033                 gen_obj->obj_data.node_obj.ndb_props.
1034                     dsp_resource_reqmts.global_data_size = atoi(token);
1035                 token = strsep(&psz_cur, seps);
1036                 gen_obj->obj_data.node_obj.ndb_props.
1037                     dsp_resource_reqmts.program_mem_size = atoi(token);
1038                 token = strsep(&psz_cur, seps);
1039                 gen_obj->obj_data.node_obj.ndb_props.
1040                     dsp_resource_reqmts.wc_execution_time = atoi(token);
1041                 token = strsep(&psz_cur, seps);
1042                 gen_obj->obj_data.node_obj.ndb_props.
1043                     dsp_resource_reqmts.wc_period = atoi(token);
1044                 token = strsep(&psz_cur, seps);
1045
1046                 gen_obj->obj_data.node_obj.ndb_props.
1047                     dsp_resource_reqmts.wc_deadline = atoi(token);
1048                 token = strsep(&psz_cur, seps);
1049
1050                 gen_obj->obj_data.node_obj.ndb_props.
1051                     dsp_resource_reqmts.avg_exection_time = atoi(token);
1052                 token = strsep(&psz_cur, seps);
1053
1054                 gen_obj->obj_data.node_obj.ndb_props.
1055                     dsp_resource_reqmts.minimum_period = atoi(token);
1056                 token = strsep(&psz_cur, seps);
1057
1058                 /* s32 prio */
1059                 gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1060                 token = strsep(&psz_cur, seps);
1061
1062                 /* u32 stack_size */
1063                 gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1064                 token = strsep(&psz_cur, seps);
1065
1066                 /* u32 sys_stack_size */
1067                 gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1068                     atoi(token);
1069                 token = strsep(&psz_cur, seps);
1070
1071                 /* u32 stack_seg */
1072                 gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1073                 token = strsep(&psz_cur, seps);
1074
1075                 /* u32 message_depth */
1076                 gen_obj->obj_data.node_obj.ndb_props.message_depth =
1077                     atoi(token);
1078                 token = strsep(&psz_cur, seps);
1079
1080                 /* u32 num_input_streams */
1081                 gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1082                     atoi(token);
1083                 token = strsep(&psz_cur, seps);
1084
1085                 /* u32 num_output_streams */
1086                 gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1087                     atoi(token);
1088                 token = strsep(&psz_cur, seps);
1089
1090                 /* u32 timeout */
1091                 gen_obj->obj_data.node_obj.ndb_props.timeout = atoi(token);
1092                 token = strsep(&psz_cur, seps);
1093
1094                 /* char *str_create_phase_fxn */
1095                 token_len = strlen(token);
1096                 gen_obj->obj_data.node_obj.str_create_phase_fxn =
1097                                         kzalloc(token_len + 1, GFP_KERNEL);
1098                 strncpy(gen_obj->obj_data.node_obj.str_create_phase_fxn,
1099                         token, token_len);
1100                 gen_obj->obj_data.node_obj.str_create_phase_fxn[token_len] =
1101                     '\0';
1102                 token = strsep(&psz_cur, seps);
1103
1104                 /* char *str_execute_phase_fxn */
1105                 token_len = strlen(token);
1106                 gen_obj->obj_data.node_obj.str_execute_phase_fxn =
1107                                         kzalloc(token_len + 1, GFP_KERNEL);
1108                 strncpy(gen_obj->obj_data.node_obj.str_execute_phase_fxn,
1109                         token, token_len);
1110                 gen_obj->obj_data.node_obj.str_execute_phase_fxn[token_len] =
1111                     '\0';
1112                 token = strsep(&psz_cur, seps);
1113
1114                 /* char *str_delete_phase_fxn */
1115                 token_len = strlen(token);
1116                 gen_obj->obj_data.node_obj.str_delete_phase_fxn =
1117                                         kzalloc(token_len + 1, GFP_KERNEL);
1118                 strncpy(gen_obj->obj_data.node_obj.str_delete_phase_fxn,
1119                         token, token_len);
1120                 gen_obj->obj_data.node_obj.str_delete_phase_fxn[token_len] =
1121                     '\0';
1122                 token = strsep(&psz_cur, seps);
1123
1124                 /* Segment id for message buffers */
1125                 gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1126                 token = strsep(&psz_cur, seps);
1127
1128                 /* Message notification type */
1129                 gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1130                 token = strsep(&psz_cur, seps);
1131
1132                 /* char *str_i_alg_name */
1133                 if (token) {
1134                         token_len = strlen(token);
1135                         gen_obj->obj_data.node_obj.str_i_alg_name =
1136                                         kzalloc(token_len + 1, GFP_KERNEL);
1137                         strncpy(gen_obj->obj_data.node_obj.str_i_alg_name,
1138                                 token, token_len);
1139                         gen_obj->obj_data.node_obj.str_i_alg_name[token_len] =
1140                             '\0';
1141                         token = strsep(&psz_cur, seps);
1142                 }
1143
1144                 /* Load type (static, dynamic, or overlay) */
1145                 if (token) {
1146                         gen_obj->obj_data.node_obj.load_type = atoi(token);
1147                         token = strsep(&psz_cur, seps);
1148                 }
1149
1150                 /* Dynamic load data requirements */
1151                 if (token) {
1152                         gen_obj->obj_data.node_obj.data_mem_seg_mask =
1153                             atoi(token);
1154                         token = strsep(&psz_cur, seps);
1155                 }
1156
1157                 /* Dynamic load code requirements */
1158                 if (token) {
1159                         gen_obj->obj_data.node_obj.code_mem_seg_mask =
1160                             atoi(token);
1161                         token = strsep(&psz_cur, seps);
1162                 }
1163
1164                 /* Extract node profiles into node properties */
1165                 if (token) {
1166
1167                         gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1168                             atoi(token);
1169                         for (i = 0;
1170                              i <
1171                              gen_obj->obj_data.node_obj.
1172                              ndb_props.count_profiles; i++) {
1173                                 token = strsep(&psz_cur, seps);
1174                                 if (token) {
1175                                         /* Heap Size for the node */
1176                                         gen_obj->obj_data.node_obj.
1177                                             ndb_props.node_profiles[i].
1178                                             heap_size = atoi(token);
1179                                 }
1180                         }
1181                 }
1182                 token = strsep(&psz_cur, seps);
1183                 if (token) {
1184                         gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1185                             (u32) (token);
1186                 }
1187
1188                 break;
1189
1190         case DSP_DCDPROCESSORTYPE:
1191                 /*
1192                  * Parse COFF sect buffer to retrieve individual tokens used
1193                  * to fill in object attrs.
1194                  */
1195                 psz_cur = psz_buf;
1196                 token = strsep(&psz_cur, seps);
1197
1198                 gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1199                 token = strsep(&psz_cur, seps);
1200
1201                 gen_obj->obj_data.proc_info.processor_family = atoi(token);
1202                 token = strsep(&psz_cur, seps);
1203
1204                 gen_obj->obj_data.proc_info.processor_type = atoi(token);
1205                 token = strsep(&psz_cur, seps);
1206
1207                 gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1208                 token = strsep(&psz_cur, seps);
1209
1210                 gen_obj->obj_data.proc_info.internal_mem_size = atoi(token);
1211                 token = strsep(&psz_cur, seps);
1212
1213                 gen_obj->obj_data.proc_info.external_mem_size = atoi(token);
1214                 token = strsep(&psz_cur, seps);
1215
1216                 gen_obj->obj_data.proc_info.processor_id = atoi(token);
1217                 token = strsep(&psz_cur, seps);
1218
1219                 gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1220                 token = strsep(&psz_cur, seps);
1221
1222                 gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1223                 token = strsep(&psz_cur, seps);
1224
1225                 gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1226
1227 #ifdef _DB_TIOMAP
1228                 /* Proc object may contain additional(extended) attributes. */
1229                 /* attr must match proc.hxx */
1230                 for (entry_id = 0; entry_id < 7; entry_id++) {
1231                         token = strsep(&psz_cur, seps);
1232                         gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1233                             gpp_phys = atoi(token);
1234
1235                         token = strsep(&psz_cur, seps);
1236                         gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1237                             dsp_virt = atoi(token);
1238                 }
1239 #endif
1240
1241                 break;
1242
1243         default:
1244                 status = -EPERM;
1245                 break;
1246         }
1247
1248         return status;
1249 }
1250
1251 /*
1252  *  ======== CompressBuffer ========
1253  *  Purpose:
1254  *      Compress the DSP buffer, if necessary, to conform to PC format.
1255  */
1256 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1257 {
1258         char *p;
1259         char ch;
1260         char *q;
1261
1262         p = psz_buf;
1263         if (p == NULL)
1264                 return;
1265
1266         for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1267                 ch = dsp_char2_gpp_char(q, char_size);
1268                 if (ch == '\\') {
1269                         q += char_size;
1270                         ch = dsp_char2_gpp_char(q, char_size);
1271                         switch (ch) {
1272                         case 't':
1273                                 *p = '\t';
1274                                 break;
1275
1276                         case 'n':
1277                                 *p = '\n';
1278                                 break;
1279
1280                         case 'r':
1281                                 *p = '\r';
1282                                 break;
1283
1284                         case '0':
1285                                 *p = '\0';
1286                                 break;
1287
1288                         default:
1289                                 *p = ch;
1290                                 break;
1291                         }
1292                 } else {
1293                         *p = ch;
1294                 }
1295                 p++;
1296                 q += char_size;
1297         }
1298
1299         /* NULL out remainder of buffer. */
1300         while (p < q)
1301                 *p++ = '\0';
1302 }
1303
1304 /*
1305  *  ======== dsp_char2_gpp_char ========
1306  *  Purpose:
1307  *      Convert DSP char to host GPP char in a portable manner
1308  */
1309 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
1310 {
1311         char ch = '\0';
1312         char *ch_src;
1313         s32 i;
1314
1315         for (ch_src = word, i = dsp_char_size; i > 0; i--)
1316                 ch |= *ch_src++;
1317
1318         return ch;
1319 }
1320
1321 /*
1322  *  ======== get_dep_lib_info ========
1323  */
1324 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
1325                                    struct dsp_uuid *uuid_obj,
1326                                    u16 *num_libs,
1327                                    u16 *num_pers_libs,
1328                                    struct dsp_uuid *dep_lib_uuids,
1329                                    bool *prstnt_dep_libs,
1330                                    enum nldr_phase phase)
1331 {
1332         struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1333         char *psz_coff_buf = NULL;
1334         char *psz_cur;
1335         char *psz_file_name = NULL;
1336         struct cod_libraryobj *lib = NULL;
1337         u32 ul_addr = 0;        /* Used by cod_get_section */
1338         u32 ul_len = 0;         /* Used by cod_get_section */
1339         u32 dw_data_size = COD_MAXPATHLENGTH;
1340         char seps[] = ", ";
1341         char *token = NULL;
1342         bool get_uuids = (dep_lib_uuids != NULL);
1343         u16 dep_libs = 0;
1344         int status = 0;
1345
1346         /*  Initialize to 0 dependent libraries, if only counting number of
1347          *  dependent libraries */
1348         if (!get_uuids) {
1349                 *num_libs = 0;
1350                 *num_pers_libs = 0;
1351         }
1352
1353         /* Allocate a buffer for file name */
1354         psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1355         if (psz_file_name == NULL) {
1356                 status = -ENOMEM;
1357         } else {
1358                 /* Get the name of the library */
1359                 status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1360                                               &dw_data_size, phase, NULL);
1361         }
1362
1363         /* Open the library */
1364         if (!status) {
1365                 status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1366                                   COD_NOLOAD, &lib);
1367         }
1368         if (!status) {
1369                 /* Get dependent library section information. */
1370                 status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1371
1372                 if (status) {
1373                         /* Ok, no dependent libraries */
1374                         ul_len = 0;
1375                         status = 0;
1376                 }
1377         }
1378
1379         if (status || !(ul_len > 0))
1380                 goto func_cont;
1381
1382         /* Allocate zeroed buffer. */
1383         psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1384         if (psz_coff_buf == NULL)
1385                 status = -ENOMEM;
1386
1387         /* Read section contents. */
1388         status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1389         if (status)
1390                 goto func_cont;
1391
1392         /* Compress and format DSP buffer to conform to PC format. */
1393         compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1394
1395         /* Read from buffer */
1396         psz_cur = psz_coff_buf;
1397         while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1398                 if (get_uuids) {
1399                         if (dep_libs >= *num_libs) {
1400                                 /* Gone beyond the limit */
1401                                 break;
1402                         } else {
1403                                 /* Retrieve UUID string. */
1404                                 uuid_uuid_from_string(token,
1405                                                       &(dep_lib_uuids
1406                                                         [dep_libs]));
1407                                 /* Is this library persistent? */
1408                                 token = strsep(&psz_cur, seps);
1409                                 prstnt_dep_libs[dep_libs] = atoi(token);
1410                                 dep_libs++;
1411                         }
1412                 } else {
1413                         /* Advanc to next token */
1414                         token = strsep(&psz_cur, seps);
1415                         if (atoi(token))
1416                                 (*num_pers_libs)++;
1417
1418                         /* Just counting number of dependent libraries */
1419                         (*num_libs)++;
1420                 }
1421         }
1422 func_cont:
1423         if (lib)
1424                 cod_close(lib);
1425
1426         /* Free previously allocated dynamic buffers. */
1427         kfree(psz_file_name);
1428
1429         kfree(psz_coff_buf);
1430
1431         return status;
1432 }