]> Pileus Git - ~andy/linux/blob - drivers/staging/tidspbridge/rmgr/dbdcd.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[~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         u32 ul_addr = 0;        /* Used by cod_get_section */
350         u32 ul_len = 0;         /* Used by cod_get_section */
351         u32 dw_buf_size;        /* Used by REG functions */
352         char sz_reg_key[DCD_MAXPATHLENGTH];
353         char *sz_uuid;          /*[MAXUUIDLEN]; */
354         struct dcd_key_elem *dcd_key = NULL;
355         char sz_sect_name[MAXUUIDLEN + 2];      /* ".[UUID]\0" */
356         char *psz_coff_buf;
357         u32 dw_key_len;         /* Len of REG key. */
358         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
359
360         sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
361         if (!sz_uuid) {
362                 status = -ENOMEM;
363                 goto func_end;
364         }
365
366         if (!hdcd_mgr) {
367                 status = -EFAULT;
368                 goto func_end;
369         }
370
371         /* Pre-determine final key length. It's length of DCD_REGKEY +
372          *  "_\0" + length of sz_obj_type string + terminating NULL */
373         dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
374
375         /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
376         strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
377
378         if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
379                 strncat(sz_reg_key, "_\0", 2);
380         else
381                 status = -EPERM;
382
383         status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
384         if (status == -1) {
385                 status = -EPERM;
386         } else {
387                 status = 0;
388
389                 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
390                     DCD_MAXPATHLENGTH) {
391                         strncat(sz_reg_key, sz_obj_type,
392                                 strlen(sz_obj_type) + 1);
393                 } else {
394                         status = -EPERM;
395                 }
396
397                 /* Create UUID value to set in registry. */
398                 uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
399
400                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
401                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
402                 else
403                         status = -EPERM;
404
405                 /* Retrieve paths from the registry based on struct dsp_uuid */
406                 dw_buf_size = DCD_MAXPATHLENGTH;
407         }
408         if (!status) {
409                 spin_lock(&dbdcd_lock);
410                 list_for_each_entry(dcd_key, &reg_key_list, link) {
411                         if (!strncmp(dcd_key->name, sz_reg_key,
412                                                 strlen(sz_reg_key) + 1))
413                                 break;
414                 }
415                 spin_unlock(&dbdcd_lock);
416                 if (&dcd_key->link == &reg_key_list) {
417                         status = -ENOKEY;
418                         goto func_end;
419                 }
420         }
421
422
423         /* Open COFF file. */
424         status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
425                                                         COD_NOLOAD, &lib);
426         if (status) {
427                 status = -EACCES;
428                 goto func_end;
429         }
430
431         /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
432
433         /* Create section name based on node UUID. A period is
434          * pre-pended to the UUID string to form the section name.
435          * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
436         strncpy(sz_sect_name, ".", 2);
437         strncat(sz_sect_name, sz_uuid, strlen(sz_uuid));
438
439         /* Get section information. */
440         status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
441         if (status) {
442                 status = -EACCES;
443                 goto func_end;
444         }
445
446         /* Allocate zeroed buffer. */
447         psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
448         if (psz_coff_buf == NULL) {
449                 status = -ENOMEM;
450                 goto func_end;
451         }
452 #ifdef _DB_TIOMAP
453         if (strstr(dcd_key->path, "iva") == NULL) {
454                 /* Locate section by objectID and read its content. */
455                 status =
456                     cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
457         } else {
458                 status =
459                     cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
460                 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
461         }
462 #else
463         status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
464 #endif
465         if (!status) {
466                 /* Compres DSP buffer to conform to PC format. */
467                 if (strstr(dcd_key->path, "iva") == NULL) {
468                         compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
469                 } else {
470                         compress_buf(psz_coff_buf, ul_len, 1);
471                         dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
472                                 "for IVA!!\n", __func__);
473                 }
474
475                 /* Parse the content of the COFF buffer. */
476                 status =
477                     get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
478                 if (status)
479                         status = -EACCES;
480         } else {
481                 status = -EACCES;
482         }
483
484         /* Free the previously allocated dynamic buffer. */
485         kfree(psz_coff_buf);
486 func_end:
487         if (lib)
488                 cod_close(lib);
489
490         kfree(sz_uuid);
491
492         return status;
493 }
494
495 /*
496  *  ======== dcd_get_objects ========
497  */
498 int dcd_get_objects(struct dcd_manager *hdcd_mgr,
499                            char *sz_coff_path, dcd_registerfxn register_fxn,
500                            void *handle)
501 {
502         struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
503         int status = 0;
504         char *psz_coff_buf;
505         char *psz_cur;
506         struct cod_libraryobj *lib = NULL;
507         u32 ul_addr = 0;        /* Used by cod_get_section */
508         u32 ul_len = 0;         /* Used by cod_get_section */
509         char seps[] = ":, ";
510         char *token = NULL;
511         struct dsp_uuid dsp_uuid_obj;
512         s32 object_type;
513
514         if (!hdcd_mgr) {
515                 status = -EFAULT;
516                 goto func_end;
517         }
518
519         /* Open DSP coff file, don't load symbols. */
520         status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
521         if (status) {
522                 status = -EACCES;
523                 goto func_cont;
524         }
525
526         /* Get DCD_RESIGER_SECTION section information. */
527         status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
528         if (status || !(ul_len > 0)) {
529                 status = -EACCES;
530                 goto func_cont;
531         }
532
533         /* Allocate zeroed buffer. */
534         psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
535         if (psz_coff_buf == NULL) {
536                 status = -ENOMEM;
537                 goto func_cont;
538         }
539 #ifdef _DB_TIOMAP
540         if (strstr(sz_coff_path, "iva") == NULL) {
541                 /* Locate section by objectID and read its content. */
542                 status = cod_read_section(lib, DCD_REGISTER_SECTION,
543                                           psz_coff_buf, ul_len);
544         } else {
545                 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
546                 status = cod_read_section(lib, DCD_REGISTER_SECTION,
547                                           psz_coff_buf, ul_len);
548         }
549 #else
550         status =
551             cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
552 #endif
553         if (!status) {
554                 /* Compress DSP buffer to conform to PC format. */
555                 if (strstr(sz_coff_path, "iva") == NULL) {
556                         compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
557                 } else {
558                         compress_buf(psz_coff_buf, ul_len, 1);
559                         dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
560                                 "for IVA!!\n", __func__);
561                 }
562
563                 /* Read from buffer and register object in buffer. */
564                 psz_cur = psz_coff_buf;
565                 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
566                         /*  Retrieve UUID string. */
567                         uuid_uuid_from_string(token, &dsp_uuid_obj);
568
569                         /*  Retrieve object type */
570                         token = strsep(&psz_cur, seps);
571
572                         /*  Retrieve object type */
573                         object_type = atoi(token);
574
575                         /*
576                          *  Apply register_fxn to the found DCD object.
577                          *  Possible actions include:
578                          *
579                          *  1) Register found DCD object.
580                          *  2) Unregister found DCD object (when handle == NULL)
581                          *  3) Add overlay node.
582                          */
583                         status =
584                             register_fxn(&dsp_uuid_obj, object_type, handle);
585                         if (status) {
586                                 /* if error occurs, break from while loop. */
587                                 break;
588                         }
589                 }
590         } else {
591                 status = -EACCES;
592         }
593
594         /* Free the previously allocated dynamic buffer. */
595         kfree(psz_coff_buf);
596 func_cont:
597         if (lib)
598                 cod_close(lib);
599
600 func_end:
601         return status;
602 }
603
604 /*
605  *  ======== dcd_get_library_name ========
606  *  Purpose:
607  *      Retrieves the library name for the given UUID.
608  *
609  */
610 int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
611                                 struct dsp_uuid *uuid_obj,
612                                 char *str_lib_name,
613                                 u32 *buff_size,
614                                 enum nldr_phase phase, bool *phase_split)
615 {
616         char sz_reg_key[DCD_MAXPATHLENGTH];
617         char sz_uuid[MAXUUIDLEN];
618         u32 dw_key_len;         /* Len of REG key. */
619         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
620         int status = 0;
621         struct dcd_key_elem *dcd_key = NULL;
622
623         dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
624                 " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
625                 buff_size);
626
627         /*
628          *  Pre-determine final key length. It's length of DCD_REGKEY +
629          *  "_\0" + length of sz_obj_type string + terminating NULL.
630          */
631         dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
632
633         /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
634         strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
635         if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
636                 strncat(sz_reg_key, "_\0", 2);
637         else
638                 status = -EPERM;
639
640         switch (phase) {
641         case NLDR_CREATE:
642                 /* create phase type */
643                 sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
644                 break;
645         case NLDR_EXECUTE:
646                 /* execute phase type */
647                 sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
648                 break;
649         case NLDR_DELETE:
650                 /* delete phase type */
651                 sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
652                 break;
653         case NLDR_NOPHASE:
654                 /* known to be a dependent library */
655                 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
656                 break;
657         default:
658                 status = -EINVAL;
659         }
660         if (!status) {
661                 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
662                     DCD_MAXPATHLENGTH) {
663                         strncat(sz_reg_key, sz_obj_type,
664                                 strlen(sz_obj_type) + 1);
665                 } else {
666                         status = -EPERM;
667                 }
668                 /* Create UUID value to find match in registry. */
669                 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
670                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
671                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
672                 else
673                         status = -EPERM;
674         }
675         if (!status) {
676                 spin_lock(&dbdcd_lock);
677                 list_for_each_entry(dcd_key, &reg_key_list, link) {
678                         /*  See if the name matches. */
679                         if (!strncmp(dcd_key->name, sz_reg_key,
680                                                 strlen(sz_reg_key) + 1))
681                                 break;
682                 }
683                 spin_unlock(&dbdcd_lock);
684         }
685
686         if (&dcd_key->link == &reg_key_list)
687                 status = -ENOKEY;
688
689         /* If can't find, phases might be registered as generic LIBRARYTYPE */
690         if (status && phase != NLDR_NOPHASE) {
691                 if (phase_split)
692                         *phase_split = false;
693
694                 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
695                 if ((strlen(sz_reg_key) + strlen("_\0")) <
696                     DCD_MAXPATHLENGTH) {
697                         strncat(sz_reg_key, "_\0", 2);
698                 } else {
699                         status = -EPERM;
700                 }
701                 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
702                 if ((strlen(sz_reg_key) + strlen(sz_obj_type))
703                     < DCD_MAXPATHLENGTH) {
704                         strncat(sz_reg_key, sz_obj_type,
705                                 strlen(sz_obj_type) + 1);
706                 } else {
707                         status = -EPERM;
708                 }
709                 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
710                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
711                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
712                 else
713                         status = -EPERM;
714
715                 spin_lock(&dbdcd_lock);
716                 list_for_each_entry(dcd_key, &reg_key_list, link) {
717                         /*  See if the name matches. */
718                         if (!strncmp(dcd_key->name, sz_reg_key,
719                                                 strlen(sz_reg_key) + 1))
720                                 break;
721                 }
722                 spin_unlock(&dbdcd_lock);
723
724                 status = (&dcd_key->link != &reg_key_list) ?
725                                                 0 : -ENOKEY;
726         }
727
728         if (!status)
729                 memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
730         return status;
731 }
732
733 /*
734  *  ======== dcd_init ========
735  *  Purpose:
736  *      Initialize the DCD module.
737  */
738 bool dcd_init(void)
739 {
740         bool ret = true;
741
742         if (refs == 0)
743                 INIT_LIST_HEAD(&reg_key_list);
744
745         if (ret)
746                 refs++;
747
748         return ret;
749 }
750
751 /*
752  *  ======== dcd_register_object ========
753  *  Purpose:
754  *      Registers a node or a processor with the DCD.
755  *      If psz_path_name == NULL, unregister the specified DCD object.
756  */
757 int dcd_register_object(struct dsp_uuid *uuid_obj,
758                                enum dsp_dcdobjtype obj_type,
759                                char *psz_path_name)
760 {
761         int status = 0;
762         char sz_reg_key[DCD_MAXPATHLENGTH];
763         char sz_uuid[MAXUUIDLEN + 1];
764         u32 dw_path_size = 0;
765         u32 dw_key_len;         /* Len of REG key. */
766         char sz_obj_type[MAX_INT2CHAR_LENGTH];  /* str. rep. of obj_type. */
767         struct dcd_key_elem *dcd_key = NULL;
768
769         dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
770                 __func__, uuid_obj, obj_type, psz_path_name);
771
772         /*
773          * Pre-determine final key length. It's length of DCD_REGKEY +
774          *  "_\0" + length of sz_obj_type string + terminating NULL.
775          */
776         dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
777
778         /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
779         strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
780         if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
781                 strncat(sz_reg_key, "_\0", 2);
782         else {
783                 status = -EPERM;
784                 goto func_end;
785         }
786
787         status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
788         if (status == -1) {
789                 status = -EPERM;
790         } else {
791                 status = 0;
792                 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
793                     DCD_MAXPATHLENGTH) {
794                         strncat(sz_reg_key, sz_obj_type,
795                                 strlen(sz_obj_type) + 1);
796                 } else
797                         status = -EPERM;
798
799                 /* Create UUID value to set in registry. */
800                 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
801                 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
802                         strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
803                 else
804                         status = -EPERM;
805         }
806
807         if (status)
808                 goto func_end;
809
810         /*
811          * If psz_path_name != NULL, perform registration, otherwise,
812          * perform unregistration.
813          */
814
815         if (psz_path_name) {
816                 dw_path_size = strlen(psz_path_name) + 1;
817                 spin_lock(&dbdcd_lock);
818                 list_for_each_entry(dcd_key, &reg_key_list, link) {
819                         /*  See if the name matches. */
820                         if (!strncmp(dcd_key->name, sz_reg_key,
821                                                 strlen(sz_reg_key) + 1))
822                                 break;
823                 }
824                 spin_unlock(&dbdcd_lock);
825                 if (&dcd_key->link == &reg_key_list) {
826                         /*
827                          * Add new reg value (UUID+obj_type)
828                          * with COFF path info
829                          */
830
831                         dcd_key = kmalloc(sizeof(struct dcd_key_elem),
832                                                                 GFP_KERNEL);
833                         if (!dcd_key) {
834                                 status = -ENOMEM;
835                                 goto func_end;
836                         }
837
838                         dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
839                                                                 GFP_KERNEL);
840
841                         if (!dcd_key->path) {
842                                 kfree(dcd_key);
843                                 status = -ENOMEM;
844                                 goto func_end;
845                         }
846
847                         strncpy(dcd_key->name, sz_reg_key,
848                                                 strlen(sz_reg_key) + 1);
849                         strncpy(dcd_key->path, psz_path_name ,
850                                                 dw_path_size);
851                         spin_lock(&dbdcd_lock);
852                         list_add_tail(&dcd_key->link, &reg_key_list);
853                         spin_unlock(&dbdcd_lock);
854                 } else {
855                         /*  Make sure the new data is the same. */
856                         if (strncmp(dcd_key->path, psz_path_name,
857                                                         dw_path_size)) {
858                                 /*  The caller needs a different data size! */
859                                 kfree(dcd_key->path);
860                                 dcd_key->path = kmalloc(dw_path_size,
861                                                                 GFP_KERNEL);
862                                 if (dcd_key->path == NULL) {
863                                         status = -ENOMEM;
864                                         goto func_end;
865                                 }
866                         }
867
868                         /*  We have a match!  Copy out the data. */
869                         memcpy(dcd_key->path, psz_path_name, dw_path_size);
870                 }
871                 dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
872                         __func__, psz_path_name, dw_path_size);
873         } else {
874                 /* Deregister an existing object */
875                 spin_lock(&dbdcd_lock);
876                 list_for_each_entry(dcd_key, &reg_key_list, link) {
877                         if (!strncmp(dcd_key->name, sz_reg_key,
878                                                 strlen(sz_reg_key) + 1)) {
879                                 list_del(&dcd_key->link);
880                                 kfree(dcd_key->path);
881                                 kfree(dcd_key);
882                                 break;
883                         }
884                 }
885                 spin_unlock(&dbdcd_lock);
886                 if (&dcd_key->link == &reg_key_list)
887                         status = -EPERM;
888         }
889
890         if (!status) {
891                 /*
892                  *  Because the node database has been updated through a
893                  *  successful object registration/de-registration operation,
894                  *  we need to reset the object enumeration counter to allow
895                  *  current enumerations to reflect this update in the node
896                  *  database.
897                  */
898                 enum_refs = 0;
899         }
900 func_end:
901         return status;
902 }
903
904 /*
905  *  ======== dcd_unregister_object ========
906  *  Call DCD_Register object with psz_path_name set to NULL to
907  *  perform actual object de-registration.
908  */
909 int dcd_unregister_object(struct dsp_uuid *uuid_obj,
910                                  enum dsp_dcdobjtype obj_type)
911 {
912         int status = 0;
913
914         /*
915          *  When dcd_register_object is called with NULL as pathname,
916          *  it indicates an unregister object operation.
917          */
918         status = dcd_register_object(uuid_obj, obj_type, NULL);
919
920         return status;
921 }
922
923 /*
924  **********************************************************************
925  * DCD Helper Functions
926  **********************************************************************
927  */
928
929 /*
930  *  ======== atoi ========
931  *  Purpose:
932  *      This function converts strings in decimal or hex format to integers.
933  */
934 static s32 atoi(char *psz_buf)
935 {
936         char *pch = psz_buf;
937         s32 base = 0;
938
939         while (isspace(*pch))
940                 pch++;
941
942         if (*pch == '-' || *pch == '+') {
943                 base = 10;
944                 pch++;
945         } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
946                 base = 16;
947         }
948
949         return simple_strtoul(pch, NULL, base);
950 }
951
952 /*
953  *  ======== get_attrs_from_buf ========
954  *  Purpose:
955  *      Parse the content of a buffer filled with DSP-side data and
956  *      retrieve an object's attributes from it. IMPORTANT: Assume the
957  *      buffer has been converted from DSP format to GPP format.
958  */
959 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
960                                      enum dsp_dcdobjtype obj_type,
961                                      struct dcd_genericobj *gen_obj)
962 {
963         int status = 0;
964         char seps[] = ", ";
965         char *psz_cur;
966         char *token;
967         s32 token_len = 0;
968         u32 i = 0;
969 #ifdef _DB_TIOMAP
970         s32 entry_id;
971 #endif
972
973         switch (obj_type) {
974         case DSP_DCDNODETYPE:
975                 /*
976                  * Parse COFF sect buffer to retrieve individual tokens used
977                  * to fill in object attrs.
978                  */
979                 psz_cur = psz_buf;
980                 token = strsep(&psz_cur, seps);
981
982                 /* u32 cb_struct */
983                 gen_obj->obj_data.node_obj.ndb_props.cb_struct =
984                     (u32) atoi(token);
985                 token = strsep(&psz_cur, seps);
986
987                 /* dsp_uuid ui_node_id */
988                 uuid_uuid_from_string(token,
989                                       &gen_obj->obj_data.node_obj.ndb_props.
990                                       ui_node_id);
991                 token = strsep(&psz_cur, seps);
992
993                 /* ac_name */
994                 token_len = strlen(token);
995                 if (token_len > DSP_MAXNAMELEN - 1)
996                         token_len = DSP_MAXNAMELEN - 1;
997
998                 strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
999                         token, token_len);
1000                 gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1001                 token = strsep(&psz_cur, seps);
1002                 /* u32 ntype */
1003                 gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1004                 token = strsep(&psz_cur, seps);
1005                 /* u32 cache_on_gpp */
1006                 gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1007                 token = strsep(&psz_cur, seps);
1008                 /* dsp_resourcereqmts dsp_resource_reqmts */
1009                 gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1010                     cb_struct = (u32) atoi(token);
1011                 token = strsep(&psz_cur, seps);
1012
1013                 gen_obj->obj_data.node_obj.ndb_props.
1014                     dsp_resource_reqmts.static_data_size = atoi(token);
1015                 token = strsep(&psz_cur, seps);
1016                 gen_obj->obj_data.node_obj.ndb_props.
1017                     dsp_resource_reqmts.global_data_size = atoi(token);
1018                 token = strsep(&psz_cur, seps);
1019                 gen_obj->obj_data.node_obj.ndb_props.
1020                     dsp_resource_reqmts.program_mem_size = atoi(token);
1021                 token = strsep(&psz_cur, seps);
1022                 gen_obj->obj_data.node_obj.ndb_props.
1023                     dsp_resource_reqmts.wc_execution_time = atoi(token);
1024                 token = strsep(&psz_cur, seps);
1025                 gen_obj->obj_data.node_obj.ndb_props.
1026                     dsp_resource_reqmts.wc_period = atoi(token);
1027                 token = strsep(&psz_cur, seps);
1028
1029                 gen_obj->obj_data.node_obj.ndb_props.
1030                     dsp_resource_reqmts.wc_deadline = atoi(token);
1031                 token = strsep(&psz_cur, seps);
1032
1033                 gen_obj->obj_data.node_obj.ndb_props.
1034                     dsp_resource_reqmts.avg_exection_time = atoi(token);
1035                 token = strsep(&psz_cur, seps);
1036
1037                 gen_obj->obj_data.node_obj.ndb_props.
1038                     dsp_resource_reqmts.minimum_period = atoi(token);
1039                 token = strsep(&psz_cur, seps);
1040
1041                 /* s32 prio */
1042                 gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1043                 token = strsep(&psz_cur, seps);
1044
1045                 /* u32 stack_size */
1046                 gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1047                 token = strsep(&psz_cur, seps);
1048
1049                 /* u32 sys_stack_size */
1050                 gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1051                     atoi(token);
1052                 token = strsep(&psz_cur, seps);
1053
1054                 /* u32 stack_seg */
1055                 gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1056                 token = strsep(&psz_cur, seps);
1057
1058                 /* u32 message_depth */
1059                 gen_obj->obj_data.node_obj.ndb_props.message_depth =
1060                     atoi(token);
1061                 token = strsep(&psz_cur, seps);
1062
1063                 /* u32 num_input_streams */
1064                 gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1065                     atoi(token);
1066                 token = strsep(&psz_cur, seps);
1067
1068                 /* u32 num_output_streams */
1069                 gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1070                     atoi(token);
1071                 token = strsep(&psz_cur, seps);
1072
1073                 /* u32 timeout */
1074                 gen_obj->obj_data.node_obj.ndb_props.timeout = atoi(token);
1075                 token = strsep(&psz_cur, seps);
1076
1077                 /* char *str_create_phase_fxn */
1078                 token_len = strlen(token);
1079                 gen_obj->obj_data.node_obj.str_create_phase_fxn =
1080                                         kzalloc(token_len + 1, GFP_KERNEL);
1081                 strncpy(gen_obj->obj_data.node_obj.str_create_phase_fxn,
1082                         token, token_len);
1083                 gen_obj->obj_data.node_obj.str_create_phase_fxn[token_len] =
1084                     '\0';
1085                 token = strsep(&psz_cur, seps);
1086
1087                 /* char *str_execute_phase_fxn */
1088                 token_len = strlen(token);
1089                 gen_obj->obj_data.node_obj.str_execute_phase_fxn =
1090                                         kzalloc(token_len + 1, GFP_KERNEL);
1091                 strncpy(gen_obj->obj_data.node_obj.str_execute_phase_fxn,
1092                         token, token_len);
1093                 gen_obj->obj_data.node_obj.str_execute_phase_fxn[token_len] =
1094                     '\0';
1095                 token = strsep(&psz_cur, seps);
1096
1097                 /* char *str_delete_phase_fxn */
1098                 token_len = strlen(token);
1099                 gen_obj->obj_data.node_obj.str_delete_phase_fxn =
1100                                         kzalloc(token_len + 1, GFP_KERNEL);
1101                 strncpy(gen_obj->obj_data.node_obj.str_delete_phase_fxn,
1102                         token, token_len);
1103                 gen_obj->obj_data.node_obj.str_delete_phase_fxn[token_len] =
1104                     '\0';
1105                 token = strsep(&psz_cur, seps);
1106
1107                 /* Segment id for message buffers */
1108                 gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1109                 token = strsep(&psz_cur, seps);
1110
1111                 /* Message notification type */
1112                 gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1113                 token = strsep(&psz_cur, seps);
1114
1115                 /* char *str_i_alg_name */
1116                 if (token) {
1117                         token_len = strlen(token);
1118                         gen_obj->obj_data.node_obj.str_i_alg_name =
1119                                         kzalloc(token_len + 1, GFP_KERNEL);
1120                         strncpy(gen_obj->obj_data.node_obj.str_i_alg_name,
1121                                 token, token_len);
1122                         gen_obj->obj_data.node_obj.str_i_alg_name[token_len] =
1123                             '\0';
1124                         token = strsep(&psz_cur, seps);
1125                 }
1126
1127                 /* Load type (static, dynamic, or overlay) */
1128                 if (token) {
1129                         gen_obj->obj_data.node_obj.load_type = atoi(token);
1130                         token = strsep(&psz_cur, seps);
1131                 }
1132
1133                 /* Dynamic load data requirements */
1134                 if (token) {
1135                         gen_obj->obj_data.node_obj.data_mem_seg_mask =
1136                             atoi(token);
1137                         token = strsep(&psz_cur, seps);
1138                 }
1139
1140                 /* Dynamic load code requirements */
1141                 if (token) {
1142                         gen_obj->obj_data.node_obj.code_mem_seg_mask =
1143                             atoi(token);
1144                         token = strsep(&psz_cur, seps);
1145                 }
1146
1147                 /* Extract node profiles into node properties */
1148                 if (token) {
1149
1150                         gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1151                             atoi(token);
1152                         for (i = 0;
1153                              i <
1154                              gen_obj->obj_data.node_obj.
1155                              ndb_props.count_profiles; i++) {
1156                                 token = strsep(&psz_cur, seps);
1157                                 if (token) {
1158                                         /* Heap Size for the node */
1159                                         gen_obj->obj_data.node_obj.
1160                                             ndb_props.node_profiles[i].
1161                                             heap_size = atoi(token);
1162                                 }
1163                         }
1164                 }
1165                 token = strsep(&psz_cur, seps);
1166                 if (token) {
1167                         gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1168                             (u32) (token);
1169                 }
1170
1171                 break;
1172
1173         case DSP_DCDPROCESSORTYPE:
1174                 /*
1175                  * Parse COFF sect buffer to retrieve individual tokens used
1176                  * to fill in object attrs.
1177                  */
1178                 psz_cur = psz_buf;
1179                 token = strsep(&psz_cur, seps);
1180
1181                 gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1182                 token = strsep(&psz_cur, seps);
1183
1184                 gen_obj->obj_data.proc_info.processor_family = atoi(token);
1185                 token = strsep(&psz_cur, seps);
1186
1187                 gen_obj->obj_data.proc_info.processor_type = atoi(token);
1188                 token = strsep(&psz_cur, seps);
1189
1190                 gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1191                 token = strsep(&psz_cur, seps);
1192
1193                 gen_obj->obj_data.proc_info.internal_mem_size = atoi(token);
1194                 token = strsep(&psz_cur, seps);
1195
1196                 gen_obj->obj_data.proc_info.external_mem_size = atoi(token);
1197                 token = strsep(&psz_cur, seps);
1198
1199                 gen_obj->obj_data.proc_info.processor_id = atoi(token);
1200                 token = strsep(&psz_cur, seps);
1201
1202                 gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1203                 token = strsep(&psz_cur, seps);
1204
1205                 gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1206                 token = strsep(&psz_cur, seps);
1207
1208                 gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1209
1210 #ifdef _DB_TIOMAP
1211                 /* Proc object may contain additional(extended) attributes. */
1212                 /* attr must match proc.hxx */
1213                 for (entry_id = 0; entry_id < 7; entry_id++) {
1214                         token = strsep(&psz_cur, seps);
1215                         gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1216                             gpp_phys = atoi(token);
1217
1218                         token = strsep(&psz_cur, seps);
1219                         gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1220                             dsp_virt = atoi(token);
1221                 }
1222 #endif
1223
1224                 break;
1225
1226         default:
1227                 status = -EPERM;
1228                 break;
1229         }
1230
1231         return status;
1232 }
1233
1234 /*
1235  *  ======== CompressBuffer ========
1236  *  Purpose:
1237  *      Compress the DSP buffer, if necessary, to conform to PC format.
1238  */
1239 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1240 {
1241         char *p;
1242         char ch;
1243         char *q;
1244
1245         p = psz_buf;
1246         if (p == NULL)
1247                 return;
1248
1249         for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1250                 ch = dsp_char2_gpp_char(q, char_size);
1251                 if (ch == '\\') {
1252                         q += char_size;
1253                         ch = dsp_char2_gpp_char(q, char_size);
1254                         switch (ch) {
1255                         case 't':
1256                                 *p = '\t';
1257                                 break;
1258
1259                         case 'n':
1260                                 *p = '\n';
1261                                 break;
1262
1263                         case 'r':
1264                                 *p = '\r';
1265                                 break;
1266
1267                         case '0':
1268                                 *p = '\0';
1269                                 break;
1270
1271                         default:
1272                                 *p = ch;
1273                                 break;
1274                         }
1275                 } else {
1276                         *p = ch;
1277                 }
1278                 p++;
1279                 q += char_size;
1280         }
1281
1282         /* NULL out remainder of buffer. */
1283         while (p < q)
1284                 *p++ = '\0';
1285 }
1286
1287 /*
1288  *  ======== dsp_char2_gpp_char ========
1289  *  Purpose:
1290  *      Convert DSP char to host GPP char in a portable manner
1291  */
1292 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
1293 {
1294         char ch = '\0';
1295         char *ch_src;
1296         s32 i;
1297
1298         for (ch_src = word, i = dsp_char_size; i > 0; i--)
1299                 ch |= *ch_src++;
1300
1301         return ch;
1302 }
1303
1304 /*
1305  *  ======== get_dep_lib_info ========
1306  */
1307 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
1308                                    struct dsp_uuid *uuid_obj,
1309                                    u16 *num_libs,
1310                                    u16 *num_pers_libs,
1311                                    struct dsp_uuid *dep_lib_uuids,
1312                                    bool *prstnt_dep_libs,
1313                                    enum nldr_phase phase)
1314 {
1315         struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1316         char *psz_coff_buf = NULL;
1317         char *psz_cur;
1318         char *psz_file_name = NULL;
1319         struct cod_libraryobj *lib = NULL;
1320         u32 ul_addr = 0;        /* Used by cod_get_section */
1321         u32 ul_len = 0;         /* Used by cod_get_section */
1322         u32 dw_data_size = COD_MAXPATHLENGTH;
1323         char seps[] = ", ";
1324         char *token = NULL;
1325         bool get_uuids = (dep_lib_uuids != NULL);
1326         u16 dep_libs = 0;
1327         int status = 0;
1328
1329         /*  Initialize to 0 dependent libraries, if only counting number of
1330          *  dependent libraries */
1331         if (!get_uuids) {
1332                 *num_libs = 0;
1333                 *num_pers_libs = 0;
1334         }
1335
1336         /* Allocate a buffer for file name */
1337         psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1338         if (psz_file_name == NULL) {
1339                 status = -ENOMEM;
1340         } else {
1341                 /* Get the name of the library */
1342                 status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1343                                               &dw_data_size, phase, NULL);
1344         }
1345
1346         /* Open the library */
1347         if (!status) {
1348                 status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1349                                   COD_NOLOAD, &lib);
1350         }
1351         if (!status) {
1352                 /* Get dependent library section information. */
1353                 status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1354
1355                 if (status) {
1356                         /* Ok, no dependent libraries */
1357                         ul_len = 0;
1358                         status = 0;
1359                 }
1360         }
1361
1362         if (status || !(ul_len > 0))
1363                 goto func_cont;
1364
1365         /* Allocate zeroed buffer. */
1366         psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1367         if (psz_coff_buf == NULL)
1368                 status = -ENOMEM;
1369
1370         /* Read section contents. */
1371         status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1372         if (status)
1373                 goto func_cont;
1374
1375         /* Compress and format DSP buffer to conform to PC format. */
1376         compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1377
1378         /* Read from buffer */
1379         psz_cur = psz_coff_buf;
1380         while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1381                 if (get_uuids) {
1382                         if (dep_libs >= *num_libs) {
1383                                 /* Gone beyond the limit */
1384                                 break;
1385                         } else {
1386                                 /* Retrieve UUID string. */
1387                                 uuid_uuid_from_string(token,
1388                                                       &(dep_lib_uuids
1389                                                         [dep_libs]));
1390                                 /* Is this library persistent? */
1391                                 token = strsep(&psz_cur, seps);
1392                                 prstnt_dep_libs[dep_libs] = atoi(token);
1393                                 dep_libs++;
1394                         }
1395                 } else {
1396                         /* Advanc to next token */
1397                         token = strsep(&psz_cur, seps);
1398                         if (atoi(token))
1399                                 (*num_pers_libs)++;
1400
1401                         /* Just counting number of dependent libraries */
1402                         (*num_libs)++;
1403                 }
1404         }
1405 func_cont:
1406         if (lib)
1407                 cod_close(lib);
1408
1409         /* Free previously allocated dynamic buffers. */
1410         kfree(psz_file_name);
1411
1412         kfree(psz_coff_buf);
1413
1414         return status;
1415 }