staging: ti dspbridge: Rename words with camel case.
[linux-2.6/x86.git] / drivers / staging / tidspbridge / rmgr / dbdcd.c
blob595f9ecd0116921cdd263d287745d75e2959d027
1 /*
2 * dbdcd.c
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * This file contains the implementation of the DSP/BIOS Bridge
7 * Configuration Database (DCD).
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.
15 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
26 /* ----------------------------------- Host OS */
27 #include <dspbridge/host_os.h>
29 /* ----------------------------------- DSP/BIOS Bridge */
30 #include <dspbridge/std.h>
31 #include <dspbridge/dbdefs.h>
32 /* ----------------------------------- Trace & Debug */
33 #include <dspbridge/dbc.h>
35 /* ----------------------------------- Platform Manager */
36 #include <dspbridge/cod.h>
38 /* ----------------------------------- Others */
39 #include <dspbridge/uuidutil.h>
41 /* ----------------------------------- This */
42 #include <dspbridge/dbdcd.h>
44 /* ----------------------------------- Global defines. */
45 #define MAX_INT2CHAR_LENGTH 16 /* Max int2char len of 32 bit int */
47 /* Name of section containing dependent libraries */
48 #define DEPLIBSECT ".dspbridge_deplibs"
50 /* DCD specific structures. */
51 struct dcd_manager {
52 struct cod_manager *cod_mgr; /* Handle to COD manager object. */
55 /* Pointer to the registry support key */
56 static struct list_head reg_key_list;
57 static DEFINE_SPINLOCK(dbdcd_lock);
59 /* Global reference variables. */
60 static u32 refs;
61 static u32 enum_refs;
63 /* Helper function prototypes. */
64 static s32 atoi(char *psz_buf);
65 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
66 enum dsp_dcdobjtype obj_type,
67 struct dcd_genericobj *gen_obj);
68 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
69 static char dsp_char2_gpp_char(char *pWord, s32 dsp_char_size);
70 static int get_dep_lib_info(IN struct dcd_manager *hdcd_mgr,
71 IN struct dsp_uuid *uuid_obj,
72 IN OUT u16 *pNumLibs,
73 OPTIONAL OUT u16 *pNumPersLibs,
74 OPTIONAL OUT struct dsp_uuid *dep_lib_uuids,
75 OPTIONAL OUT bool *pPersistentDepLibs,
76 IN enum nldr_phase phase);
79 * ======== dcd_auto_register ========
80 * Purpose:
81 * Parses the supplied image and resigsters with DCD.
83 int dcd_auto_register(IN struct dcd_manager *hdcd_mgr,
84 IN char *pszCoffPath)
86 int status = 0;
88 DBC_REQUIRE(refs > 0);
90 if (hdcd_mgr)
91 status = dcd_get_objects(hdcd_mgr, pszCoffPath,
92 (dcd_registerfxn) dcd_register_object,
93 (void *)pszCoffPath);
94 else
95 status = -EFAULT;
97 return status;
101 * ======== dcd_auto_unregister ========
102 * Purpose:
103 * Parses the supplied DSP image and unresiters from DCD.
105 int dcd_auto_unregister(IN struct dcd_manager *hdcd_mgr,
106 IN char *pszCoffPath)
108 int status = 0;
110 DBC_REQUIRE(refs > 0);
112 if (hdcd_mgr)
113 status = dcd_get_objects(hdcd_mgr, pszCoffPath,
114 (dcd_registerfxn) dcd_register_object,
115 NULL);
116 else
117 status = -EFAULT;
119 return status;
123 * ======== dcd_create_manager ========
124 * Purpose:
125 * Creates DCD manager.
127 int dcd_create_manager(IN char *pszZlDllName,
128 OUT struct dcd_manager **dcd_mgr)
130 struct cod_manager *cod_mgr; /* COD manager handle */
131 struct dcd_manager *dcd_mgr_obj = NULL; /* DCD Manager pointer */
132 int status = 0;
134 DBC_REQUIRE(refs >= 0);
135 DBC_REQUIRE(dcd_mgr);
137 status = cod_create(&cod_mgr, pszZlDllName, NULL);
138 if (DSP_FAILED(status))
139 goto func_end;
141 /* Create a DCD object. */
142 dcd_mgr_obj = kzalloc(sizeof(struct dcd_manager), GFP_KERNEL);
143 if (dcd_mgr_obj != NULL) {
144 /* Fill out the object. */
145 dcd_mgr_obj->cod_mgr = cod_mgr;
147 /* Return handle to this DCD interface. */
148 *dcd_mgr = dcd_mgr_obj;
149 } else {
150 status = -ENOMEM;
153 * If allocation of DcdManager object failed, delete the
154 * COD manager.
156 cod_delete(cod_mgr);
159 DBC_ENSURE((DSP_SUCCEEDED(status)) ||
160 ((dcd_mgr_obj == NULL) && (status == -ENOMEM)));
162 func_end:
163 return status;
167 * ======== dcd_destroy_manager ========
168 * Purpose:
169 * Frees DCD Manager object.
171 int dcd_destroy_manager(IN struct dcd_manager *hdcd_mgr)
173 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
174 int status = -EFAULT;
176 DBC_REQUIRE(refs >= 0);
178 if (hdcd_mgr) {
179 /* Delete the COD manager. */
180 cod_delete(dcd_mgr_obj->cod_mgr);
182 /* Deallocate a DCD manager object. */
183 kfree(dcd_mgr_obj);
185 status = 0;
188 return status;
192 * ======== dcd_enumerate_object ========
193 * Purpose:
194 * Enumerates objects in the DCD.
196 int dcd_enumerate_object(IN s32 index, IN enum dsp_dcdobjtype obj_type,
197 OUT struct dsp_uuid *uuid_obj)
199 int status = 0;
200 char sz_reg_key[DCD_MAXPATHLENGTH];
201 char sz_value[DCD_MAXPATHLENGTH];
202 struct dsp_uuid dsp_uuid_obj;
203 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
204 u32 dw_key_len = 0;
205 struct dcd_key_elem *dcd_key;
206 int len;
208 DBC_REQUIRE(refs >= 0);
209 DBC_REQUIRE(index >= 0);
210 DBC_REQUIRE(uuid_obj != NULL);
212 if ((index != 0) && (enum_refs == 0)) {
214 * If an enumeration is being performed on an index greater
215 * than zero, then the current enum_refs must have been
216 * incremented to greater than zero.
218 status = -EIDRM;
219 } else {
221 * Pre-determine final key length. It's length of DCD_REGKEY +
222 * "_\0" + length of sz_obj_type string + terminating NULL.
224 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
225 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
227 /* Create proper REG key; concatenate DCD_REGKEY with
228 * obj_type. */
229 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
230 if ((strlen(sz_reg_key) + strlen("_\0")) <
231 DCD_MAXPATHLENGTH) {
232 strncat(sz_reg_key, "_\0", 2);
233 } else {
234 status = -EPERM;
237 /* This snprintf is guaranteed not to exceed max size of an
238 * integer. */
239 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d",
240 obj_type);
242 if (status == -1) {
243 status = -EPERM;
244 } else {
245 status = 0;
246 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
247 DCD_MAXPATHLENGTH) {
248 strncat(sz_reg_key, sz_obj_type,
249 strlen(sz_obj_type) + 1);
250 } else {
251 status = -EPERM;
255 if (DSP_SUCCEEDED(status)) {
256 len = strlen(sz_reg_key);
257 spin_lock(&dbdcd_lock);
258 list_for_each_entry(dcd_key, &reg_key_list, link) {
259 if (!strncmp(dcd_key->name, sz_reg_key, len)
260 && !index--) {
261 strncpy(sz_value, &dcd_key->name[len],
262 strlen(&dcd_key->name[len]) + 1);
263 break;
266 spin_unlock(&dbdcd_lock);
268 if (&dcd_key->link == &reg_key_list)
269 status = -ENODATA;
272 if (DSP_SUCCEEDED(status)) {
273 /* Create UUID value using string retrieved from
274 * registry. */
275 uuid_uuid_from_string(sz_value, &dsp_uuid_obj);
277 *uuid_obj = dsp_uuid_obj;
279 /* Increment enum_refs to update reference count. */
280 enum_refs++;
282 status = 0;
283 } else if (status == -ENODATA) {
284 /* At the end of enumeration. Reset enum_refs. */
285 enum_refs = 0;
288 * TODO: Revisit, this is not an errror case but code
289 * expects non-zero value.
291 status = ENODATA;
292 } else {
293 status = -EPERM;
297 DBC_ENSURE(uuid_obj || (status == -EPERM));
299 return status;
303 * ======== dcd_exit ========
304 * Purpose:
305 * Discontinue usage of the DCD module.
307 void dcd_exit(void)
309 struct dcd_key_elem *rv, *rv_tmp;
310 DBC_REQUIRE(refs > 0);
312 refs--;
313 if (refs == 0) {
314 cod_exit();
315 list_for_each_entry_safe(rv, rv_tmp, &reg_key_list, link) {
316 list_del(&rv->link);
317 kfree(rv->path);
318 kfree(rv);
322 DBC_ENSURE(refs >= 0);
326 * ======== dcd_get_dep_libs ========
328 int dcd_get_dep_libs(IN struct dcd_manager *hdcd_mgr,
329 IN struct dsp_uuid *uuid_obj,
330 u16 num_libs, OUT struct dsp_uuid *dep_lib_uuids,
331 OUT bool *pPersistentDepLibs,
332 IN enum nldr_phase phase)
334 int status = 0;
336 DBC_REQUIRE(refs > 0);
337 DBC_REQUIRE(hdcd_mgr);
338 DBC_REQUIRE(uuid_obj != NULL);
339 DBC_REQUIRE(dep_lib_uuids != NULL);
340 DBC_REQUIRE(pPersistentDepLibs != NULL);
342 status =
343 get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
344 pPersistentDepLibs, phase);
346 return status;
350 * ======== dcd_get_num_dep_libs ========
352 int dcd_get_num_dep_libs(IN struct dcd_manager *hdcd_mgr,
353 IN struct dsp_uuid *uuid_obj,
354 OUT u16 *pNumLibs, OUT u16 *pNumPersLibs,
355 IN enum nldr_phase phase)
357 int status = 0;
359 DBC_REQUIRE(refs > 0);
360 DBC_REQUIRE(hdcd_mgr);
361 DBC_REQUIRE(pNumLibs != NULL);
362 DBC_REQUIRE(pNumPersLibs != NULL);
363 DBC_REQUIRE(uuid_obj != NULL);
365 status = get_dep_lib_info(hdcd_mgr, uuid_obj, pNumLibs, pNumPersLibs,
366 NULL, NULL, phase);
368 return status;
372 * ======== dcd_get_object_def ========
373 * Purpose:
374 * Retrieves the properties of a node or processor based on the UUID and
375 * object type.
377 int dcd_get_object_def(IN struct dcd_manager *hdcd_mgr,
378 IN struct dsp_uuid *pObjUuid,
379 IN enum dsp_dcdobjtype obj_type,
380 OUT struct dcd_genericobj *pObjDef)
382 struct dcd_manager *dcd_mgr_obj = hdcd_mgr; /* ptr to DCD mgr */
383 struct cod_libraryobj *lib = NULL;
384 int status = 0;
385 u32 ul_addr = 0; /* Used by cod_get_section */
386 u32 ul_len = 0; /* Used by cod_get_section */
387 u32 dw_buf_size; /* Used by REG functions */
388 char sz_reg_key[DCD_MAXPATHLENGTH];
389 char *sz_uuid; /*[MAXUUIDLEN]; */
390 struct dcd_key_elem *dcd_key = NULL;
391 char sz_sect_name[MAXUUIDLEN + 2]; /* ".[UUID]\0" */
392 char *psz_coff_buf;
393 u32 dw_key_len; /* Len of REG key. */
394 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
396 DBC_REQUIRE(refs > 0);
397 DBC_REQUIRE(pObjDef != NULL);
398 DBC_REQUIRE(pObjUuid != NULL);
400 sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
401 if (!sz_uuid) {
402 status = -ENOMEM;
403 goto func_end;
406 if (!hdcd_mgr) {
407 status = -EFAULT;
408 goto func_end;
411 /* Pre-determine final key length. It's length of DCD_REGKEY +
412 * "_\0" + length of sz_obj_type string + terminating NULL */
413 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
414 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
416 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
417 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
419 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
420 strncat(sz_reg_key, "_\0", 2);
421 else
422 status = -EPERM;
424 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
425 if (status == -1) {
426 status = -EPERM;
427 } else {
428 status = 0;
430 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
431 DCD_MAXPATHLENGTH) {
432 strncat(sz_reg_key, sz_obj_type,
433 strlen(sz_obj_type) + 1);
434 } else {
435 status = -EPERM;
438 /* Create UUID value to set in registry. */
439 uuid_uuid_to_string(pObjUuid, sz_uuid, MAXUUIDLEN);
441 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
442 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
443 else
444 status = -EPERM;
446 /* Retrieve paths from the registry based on struct dsp_uuid */
447 dw_buf_size = DCD_MAXPATHLENGTH;
449 if (DSP_SUCCEEDED(status)) {
450 spin_lock(&dbdcd_lock);
451 list_for_each_entry(dcd_key, &reg_key_list, link) {
452 if (!strncmp(dcd_key->name, sz_reg_key,
453 strlen(sz_reg_key) + 1))
454 break;
456 spin_unlock(&dbdcd_lock);
457 if (&dcd_key->link == &reg_key_list) {
458 status = -ENOKEY;
459 goto func_end;
464 /* Open COFF file. */
465 status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
466 COD_NOLOAD, &lib);
467 if (DSP_FAILED(status)) {
468 status = -EACCES;
469 goto func_end;
472 /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
473 DBC_ASSERT((strlen(sz_uuid) + 1) < sizeof(sz_sect_name));
475 /* Create section name based on node UUID. A period is
476 * pre-pended to the UUID string to form the section name.
477 * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
478 strncpy(sz_sect_name, ".", 2);
479 strncat(sz_sect_name, sz_uuid, strlen(sz_uuid));
481 /* Get section information. */
482 status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
483 if (DSP_FAILED(status)) {
484 status = -EACCES;
485 goto func_end;
488 /* Allocate zeroed buffer. */
489 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
490 #ifdef _DB_TIOMAP
491 if (strstr(dcd_key->path, "iva") == NULL) {
492 /* Locate section by objectID and read its content. */
493 status =
494 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
495 } else {
496 status =
497 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
498 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
500 #else
501 status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
502 #endif
503 if (DSP_SUCCEEDED(status)) {
504 /* Compres DSP buffer to conform to PC format. */
505 if (strstr(dcd_key->path, "iva") == NULL) {
506 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
507 } else {
508 compress_buf(psz_coff_buf, ul_len, 1);
509 dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
510 "for IVA!!\n", __func__);
513 /* Parse the content of the COFF buffer. */
514 status =
515 get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, pObjDef);
516 if (DSP_FAILED(status))
517 status = -EACCES;
518 } else {
519 status = -EACCES;
522 /* Free the previously allocated dynamic buffer. */
523 kfree(psz_coff_buf);
524 func_end:
525 if (lib)
526 cod_close(lib);
528 kfree(sz_uuid);
530 return status;
534 * ======== dcd_get_objects ========
536 int dcd_get_objects(IN struct dcd_manager *hdcd_mgr,
537 IN char *pszCoffPath, dcd_registerfxn registerFxn,
538 void *handle)
540 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
541 int status = 0;
542 char *psz_coff_buf;
543 char *psz_cur;
544 struct cod_libraryobj *lib = NULL;
545 u32 ul_addr = 0; /* Used by cod_get_section */
546 u32 ul_len = 0; /* Used by cod_get_section */
547 char seps[] = ":, ";
548 char *token = NULL;
549 struct dsp_uuid dsp_uuid_obj;
550 s32 object_type;
552 DBC_REQUIRE(refs > 0);
553 if (!hdcd_mgr) {
554 status = -EFAULT;
555 goto func_end;
558 /* Open DSP coff file, don't load symbols. */
559 status = cod_open(dcd_mgr_obj->cod_mgr, pszCoffPath, COD_NOLOAD, &lib);
560 if (DSP_FAILED(status)) {
561 status = -EACCES;
562 goto func_cont;
565 /* Get DCD_RESIGER_SECTION section information. */
566 status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
567 if (DSP_FAILED(status) || !(ul_len > 0)) {
568 status = -EACCES;
569 goto func_cont;
572 /* Allocate zeroed buffer. */
573 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
574 #ifdef _DB_TIOMAP
575 if (strstr(pszCoffPath, "iva") == NULL) {
576 /* Locate section by objectID and read its content. */
577 status = cod_read_section(lib, DCD_REGISTER_SECTION,
578 psz_coff_buf, ul_len);
579 } else {
580 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
581 status = cod_read_section(lib, DCD_REGISTER_SECTION,
582 psz_coff_buf, ul_len);
584 #else
585 status =
586 cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
587 #endif
588 if (DSP_SUCCEEDED(status)) {
589 /* Compress DSP buffer to conform to PC format. */
590 if (strstr(pszCoffPath, "iva") == NULL) {
591 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
592 } else {
593 compress_buf(psz_coff_buf, ul_len, 1);
594 dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
595 "for IVA!!\n", __func__);
598 /* Read from buffer and register object in buffer. */
599 psz_cur = psz_coff_buf;
600 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
601 /* Retrieve UUID string. */
602 uuid_uuid_from_string(token, &dsp_uuid_obj);
604 /* Retrieve object type */
605 token = strsep(&psz_cur, seps);
607 /* Retrieve object type */
608 object_type = atoi(token);
611 * Apply registerFxn to the found DCD object.
612 * Possible actions include:
614 * 1) Register found DCD object.
615 * 2) Unregister found DCD object (when handle == NULL)
616 * 3) Add overlay node.
618 status =
619 registerFxn(&dsp_uuid_obj, object_type, handle);
620 if (DSP_FAILED(status)) {
621 /* if error occurs, break from while loop. */
622 break;
625 } else {
626 status = -EACCES;
629 /* Free the previously allocated dynamic buffer. */
630 kfree(psz_coff_buf);
631 func_cont:
632 if (lib)
633 cod_close(lib);
635 func_end:
636 return status;
640 * ======== dcd_get_library_name ========
641 * Purpose:
642 * Retrieves the library name for the given UUID.
645 int dcd_get_library_name(IN struct dcd_manager *hdcd_mgr,
646 IN struct dsp_uuid *uuid_obj,
647 IN OUT char *pstrLibName,
648 IN OUT u32 *buff_size,
649 enum nldr_phase phase, OUT bool *phase_split)
651 char sz_reg_key[DCD_MAXPATHLENGTH];
652 char sz_uuid[MAXUUIDLEN];
653 u32 dw_key_len; /* Len of REG key. */
654 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
655 int status = 0;
656 struct dcd_key_elem *dcd_key = NULL;
658 DBC_REQUIRE(uuid_obj != NULL);
659 DBC_REQUIRE(pstrLibName != NULL);
660 DBC_REQUIRE(buff_size != NULL);
661 DBC_REQUIRE(hdcd_mgr);
663 dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, pstrLibName %p,"
664 " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, pstrLibName,
665 buff_size);
668 * Pre-determine final key length. It's length of DCD_REGKEY +
669 * "_\0" + length of sz_obj_type string + terminating NULL.
671 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
672 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
674 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
675 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
676 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
677 strncat(sz_reg_key, "_\0", 2);
678 else
679 status = -EPERM;
681 switch (phase) {
682 case NLDR_CREATE:
683 /* create phase type */
684 sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
685 break;
686 case NLDR_EXECUTE:
687 /* execute phase type */
688 sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
689 break;
690 case NLDR_DELETE:
691 /* delete phase type */
692 sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
693 break;
694 case NLDR_NOPHASE:
695 /* known to be a dependent library */
696 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
697 break;
698 default:
699 status = -EINVAL;
700 DBC_ASSERT(false);
702 if (DSP_SUCCEEDED(status)) {
703 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
704 DCD_MAXPATHLENGTH) {
705 strncat(sz_reg_key, sz_obj_type,
706 strlen(sz_obj_type) + 1);
707 } else {
708 status = -EPERM;
710 /* Create UUID value to find match in registry. */
711 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
712 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
713 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
714 else
715 status = -EPERM;
717 if (DSP_SUCCEEDED(status)) {
718 spin_lock(&dbdcd_lock);
719 list_for_each_entry(dcd_key, &reg_key_list, link) {
720 /* See if the name matches. */
721 if (!strncmp(dcd_key->name, sz_reg_key,
722 strlen(sz_reg_key) + 1))
723 break;
725 spin_unlock(&dbdcd_lock);
728 if (&dcd_key->link == &reg_key_list)
729 status = -ENOKEY;
731 /* If can't find, phases might be registered as generic LIBRARYTYPE */
732 if (DSP_FAILED(status) && phase != NLDR_NOPHASE) {
733 if (phase_split)
734 *phase_split = false;
736 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
737 if ((strlen(sz_reg_key) + strlen("_\0")) <
738 DCD_MAXPATHLENGTH) {
739 strncat(sz_reg_key, "_\0", 2);
740 } else {
741 status = -EPERM;
743 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
744 if ((strlen(sz_reg_key) + strlen(sz_obj_type))
745 < DCD_MAXPATHLENGTH) {
746 strncat(sz_reg_key, sz_obj_type,
747 strlen(sz_obj_type) + 1);
748 } else {
749 status = -EPERM;
751 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
752 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
753 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
754 else
755 status = -EPERM;
757 spin_lock(&dbdcd_lock);
758 list_for_each_entry(dcd_key, &reg_key_list, link) {
759 /* See if the name matches. */
760 if (!strncmp(dcd_key->name, sz_reg_key,
761 strlen(sz_reg_key) + 1))
762 break;
764 spin_unlock(&dbdcd_lock);
766 status = (&dcd_key->link != &reg_key_list) ?
767 0 : -ENOKEY;
770 if (DSP_SUCCEEDED(status))
771 memcpy(pstrLibName, dcd_key->path, strlen(dcd_key->path) + 1);
772 return status;
776 * ======== dcd_init ========
777 * Purpose:
778 * Initialize the DCD module.
780 bool dcd_init(void)
782 bool init_cod;
783 bool ret = true;
785 DBC_REQUIRE(refs >= 0);
787 if (refs == 0) {
788 /* Initialize required modules. */
789 init_cod = cod_init();
791 if (!init_cod) {
792 ret = false;
793 /* Exit initialized modules. */
794 if (init_cod)
795 cod_exit();
798 INIT_LIST_HEAD(&reg_key_list);
801 if (ret)
802 refs++;
804 DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0)));
806 return ret;
810 * ======== dcd_register_object ========
811 * Purpose:
812 * Registers a node or a processor with the DCD.
813 * If psz_path_name == NULL, unregister the specified DCD object.
815 int dcd_register_object(IN struct dsp_uuid *uuid_obj,
816 IN enum dsp_dcdobjtype obj_type,
817 IN char *psz_path_name)
819 int status = 0;
820 char sz_reg_key[DCD_MAXPATHLENGTH];
821 char sz_uuid[MAXUUIDLEN + 1];
822 u32 dw_path_size = 0;
823 u32 dw_key_len; /* Len of REG key. */
824 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
825 struct dcd_key_elem *dcd_key = NULL;
827 DBC_REQUIRE(refs > 0);
828 DBC_REQUIRE(uuid_obj != NULL);
829 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
830 (obj_type == DSP_DCDPROCESSORTYPE) ||
831 (obj_type == DSP_DCDLIBRARYTYPE) ||
832 (obj_type == DSP_DCDCREATELIBTYPE) ||
833 (obj_type == DSP_DCDEXECUTELIBTYPE) ||
834 (obj_type == DSP_DCDDELETELIBTYPE));
836 dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
837 __func__, uuid_obj, obj_type, psz_path_name);
840 * Pre-determine final key length. It's length of DCD_REGKEY +
841 * "_\0" + length of sz_obj_type string + terminating NULL.
843 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
844 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
846 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
847 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
848 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
849 strncat(sz_reg_key, "_\0", 2);
850 else {
851 status = -EPERM;
852 goto func_end;
855 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
856 if (status == -1) {
857 status = -EPERM;
858 } else {
859 status = 0;
860 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
861 DCD_MAXPATHLENGTH) {
862 strncat(sz_reg_key, sz_obj_type,
863 strlen(sz_obj_type) + 1);
864 } else
865 status = -EPERM;
867 /* Create UUID value to set in registry. */
868 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
869 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
870 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
871 else
872 status = -EPERM;
875 if (DSP_FAILED(status))
876 goto func_end;
879 * If psz_path_name != NULL, perform registration, otherwise,
880 * perform unregistration.
883 if (psz_path_name) {
884 dw_path_size = strlen(psz_path_name) + 1;
885 spin_lock(&dbdcd_lock);
886 list_for_each_entry(dcd_key, &reg_key_list, link) {
887 /* See if the name matches. */
888 if (!strncmp(dcd_key->name, sz_reg_key,
889 strlen(sz_reg_key) + 1))
890 break;
892 spin_unlock(&dbdcd_lock);
893 if (&dcd_key->link == &reg_key_list) {
895 * Add new reg value (UUID+obj_type)
896 * with COFF path info
899 dcd_key = kmalloc(sizeof(struct dcd_key_elem),
900 GFP_KERNEL);
901 if (!dcd_key) {
902 status = -ENOMEM;
903 goto func_end;
906 dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
907 GFP_KERNEL);
909 if (!dcd_key->path) {
910 kfree(dcd_key);
911 status = -ENOMEM;
912 goto func_end;
915 strncpy(dcd_key->name, sz_reg_key,
916 strlen(sz_reg_key) + 1);
917 strncpy(dcd_key->path, psz_path_name ,
918 dw_path_size);
919 spin_lock(&dbdcd_lock);
920 list_add_tail(&dcd_key->link, &reg_key_list);
921 spin_unlock(&dbdcd_lock);
922 } else {
923 /* Make sure the new data is the same. */
924 if (strncmp(dcd_key->path, psz_path_name,
925 dw_path_size)) {
926 /* The caller needs a different data size! */
927 kfree(dcd_key->path);
928 dcd_key->path = kmalloc(dw_path_size,
929 GFP_KERNEL);
930 if (dcd_key->path == NULL) {
931 status = -ENOMEM;
932 goto func_end;
936 /* We have a match! Copy out the data. */
937 memcpy(dcd_key->path, psz_path_name, dw_path_size);
939 dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
940 __func__, psz_path_name, dw_path_size);
941 } else {
942 /* Deregister an existing object */
943 spin_lock(&dbdcd_lock);
944 list_for_each_entry(dcd_key, &reg_key_list, link) {
945 if (!strncmp(dcd_key->name, sz_reg_key,
946 strlen(sz_reg_key) + 1)) {
947 list_del(&dcd_key->link);
948 kfree(dcd_key->path);
949 kfree(dcd_key);
950 break;
953 spin_unlock(&dbdcd_lock);
954 if (&dcd_key->link == &reg_key_list)
955 status = -EPERM;
958 if (DSP_SUCCEEDED(status)) {
960 * Because the node database has been updated through a
961 * successful object registration/de-registration operation,
962 * we need to reset the object enumeration counter to allow
963 * current enumerations to reflect this update in the node
964 * database.
966 enum_refs = 0;
968 func_end:
969 return status;
973 * ======== dcd_unregister_object ========
974 * Call DCD_Register object with psz_path_name set to NULL to
975 * perform actual object de-registration.
977 int dcd_unregister_object(IN struct dsp_uuid *uuid_obj,
978 IN enum dsp_dcdobjtype obj_type)
980 int status = 0;
982 DBC_REQUIRE(refs > 0);
983 DBC_REQUIRE(uuid_obj != NULL);
984 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
985 (obj_type == DSP_DCDPROCESSORTYPE) ||
986 (obj_type == DSP_DCDLIBRARYTYPE) ||
987 (obj_type == DSP_DCDCREATELIBTYPE) ||
988 (obj_type == DSP_DCDEXECUTELIBTYPE) ||
989 (obj_type == DSP_DCDDELETELIBTYPE));
992 * When dcd_register_object is called with NULL as pathname,
993 * it indicates an unregister object operation.
995 status = dcd_register_object(uuid_obj, obj_type, NULL);
997 return status;
1001 **********************************************************************
1002 * DCD Helper Functions
1003 **********************************************************************
1007 * ======== atoi ========
1008 * Purpose:
1009 * This function converts strings in decimal or hex format to integers.
1011 static s32 atoi(char *psz_buf)
1013 char *pch = psz_buf;
1014 s32 base = 0;
1016 while (isspace(*pch))
1017 pch++;
1019 if (*pch == '-' || *pch == '+') {
1020 base = 10;
1021 pch++;
1022 } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
1023 base = 16;
1026 return simple_strtoul(pch, NULL, base);
1030 * ======== get_attrs_from_buf ========
1031 * Purpose:
1032 * Parse the content of a buffer filled with DSP-side data and
1033 * retrieve an object's attributes from it. IMPORTANT: Assume the
1034 * buffer has been converted from DSP format to GPP format.
1036 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
1037 enum dsp_dcdobjtype obj_type,
1038 struct dcd_genericobj *gen_obj)
1040 int status = 0;
1041 char seps[] = ", ";
1042 char *psz_cur;
1043 char *token;
1044 s32 token_len = 0;
1045 u32 i = 0;
1046 #ifdef _DB_TIOMAP
1047 s32 entry_id;
1048 #endif
1050 DBC_REQUIRE(psz_buf != NULL);
1051 DBC_REQUIRE(ul_buf_size != 0);
1052 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE)
1053 || (obj_type == DSP_DCDPROCESSORTYPE));
1054 DBC_REQUIRE(gen_obj != NULL);
1056 switch (obj_type) {
1057 case DSP_DCDNODETYPE:
1059 * Parse COFF sect buffer to retrieve individual tokens used
1060 * to fill in object attrs.
1062 psz_cur = psz_buf;
1063 token = strsep(&psz_cur, seps);
1065 /* u32 cb_struct */
1066 gen_obj->obj_data.node_obj.ndb_props.cb_struct =
1067 (u32) atoi(token);
1068 token = strsep(&psz_cur, seps);
1070 /* dsp_uuid ui_node_id */
1071 uuid_uuid_from_string(token,
1072 &gen_obj->obj_data.node_obj.ndb_props.
1073 ui_node_id);
1074 token = strsep(&psz_cur, seps);
1076 /* ac_name */
1077 DBC_REQUIRE(token);
1078 token_len = strlen(token);
1079 if (token_len > DSP_MAXNAMELEN - 1)
1080 token_len = DSP_MAXNAMELEN - 1;
1082 strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
1083 token, token_len);
1084 gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1085 token = strsep(&psz_cur, seps);
1086 /* u32 ntype */
1087 gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1088 token = strsep(&psz_cur, seps);
1089 /* u32 cache_on_gpp */
1090 gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1091 token = strsep(&psz_cur, seps);
1092 /* dsp_resourcereqmts dsp_resource_reqmts */
1093 gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1094 cb_struct = (u32) atoi(token);
1095 token = strsep(&psz_cur, seps);
1097 gen_obj->obj_data.node_obj.ndb_props.
1098 dsp_resource_reqmts.static_data_size = atoi(token);
1099 token = strsep(&psz_cur, seps);
1100 gen_obj->obj_data.node_obj.ndb_props.
1101 dsp_resource_reqmts.global_data_size = atoi(token);
1102 token = strsep(&psz_cur, seps);
1103 gen_obj->obj_data.node_obj.ndb_props.
1104 dsp_resource_reqmts.program_mem_size = atoi(token);
1105 token = strsep(&psz_cur, seps);
1106 gen_obj->obj_data.node_obj.ndb_props.
1107 dsp_resource_reqmts.uwc_execution_time = atoi(token);
1108 token = strsep(&psz_cur, seps);
1109 gen_obj->obj_data.node_obj.ndb_props.
1110 dsp_resource_reqmts.uwc_period = atoi(token);
1111 token = strsep(&psz_cur, seps);
1113 gen_obj->obj_data.node_obj.ndb_props.
1114 dsp_resource_reqmts.uwc_deadline = atoi(token);
1115 token = strsep(&psz_cur, seps);
1117 gen_obj->obj_data.node_obj.ndb_props.
1118 dsp_resource_reqmts.avg_exection_time = atoi(token);
1119 token = strsep(&psz_cur, seps);
1121 gen_obj->obj_data.node_obj.ndb_props.
1122 dsp_resource_reqmts.minimum_period = atoi(token);
1123 token = strsep(&psz_cur, seps);
1125 /* s32 prio */
1126 gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1127 token = strsep(&psz_cur, seps);
1129 /* u32 stack_size */
1130 gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1131 token = strsep(&psz_cur, seps);
1133 /* u32 sys_stack_size */
1134 gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1135 atoi(token);
1136 token = strsep(&psz_cur, seps);
1138 /* u32 stack_seg */
1139 gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1140 token = strsep(&psz_cur, seps);
1142 /* u32 message_depth */
1143 gen_obj->obj_data.node_obj.ndb_props.message_depth =
1144 atoi(token);
1145 token = strsep(&psz_cur, seps);
1147 /* u32 num_input_streams */
1148 gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1149 atoi(token);
1150 token = strsep(&psz_cur, seps);
1152 /* u32 num_output_streams */
1153 gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1154 atoi(token);
1155 token = strsep(&psz_cur, seps);
1157 /* u32 utimeout */
1158 gen_obj->obj_data.node_obj.ndb_props.utimeout = atoi(token);
1159 token = strsep(&psz_cur, seps);
1161 /* char *pstr_create_phase_fxn */
1162 DBC_REQUIRE(token);
1163 token_len = strlen(token);
1164 gen_obj->obj_data.node_obj.pstr_create_phase_fxn =
1165 kzalloc(token_len + 1, GFP_KERNEL);
1166 strncpy(gen_obj->obj_data.node_obj.pstr_create_phase_fxn,
1167 token, token_len);
1168 gen_obj->obj_data.node_obj.pstr_create_phase_fxn[token_len] =
1169 '\0';
1170 token = strsep(&psz_cur, seps);
1172 /* char *pstr_execute_phase_fxn */
1173 DBC_REQUIRE(token);
1174 token_len = strlen(token);
1175 gen_obj->obj_data.node_obj.pstr_execute_phase_fxn =
1176 kzalloc(token_len + 1, GFP_KERNEL);
1177 strncpy(gen_obj->obj_data.node_obj.pstr_execute_phase_fxn,
1178 token, token_len);
1179 gen_obj->obj_data.node_obj.pstr_execute_phase_fxn[token_len] =
1180 '\0';
1181 token = strsep(&psz_cur, seps);
1183 /* char *pstr_delete_phase_fxn */
1184 DBC_REQUIRE(token);
1185 token_len = strlen(token);
1186 gen_obj->obj_data.node_obj.pstr_delete_phase_fxn =
1187 kzalloc(token_len + 1, GFP_KERNEL);
1188 strncpy(gen_obj->obj_data.node_obj.pstr_delete_phase_fxn,
1189 token, token_len);
1190 gen_obj->obj_data.node_obj.pstr_delete_phase_fxn[token_len] =
1191 '\0';
1192 token = strsep(&psz_cur, seps);
1194 /* Segment id for message buffers */
1195 gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1196 token = strsep(&psz_cur, seps);
1198 /* Message notification type */
1199 gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1200 token = strsep(&psz_cur, seps);
1202 /* char *pstr_i_alg_name */
1203 if (token) {
1204 token_len = strlen(token);
1205 gen_obj->obj_data.node_obj.pstr_i_alg_name =
1206 kzalloc(token_len + 1, GFP_KERNEL);
1207 strncpy(gen_obj->obj_data.node_obj.pstr_i_alg_name,
1208 token, token_len);
1209 gen_obj->obj_data.node_obj.pstr_i_alg_name[token_len] =
1210 '\0';
1211 token = strsep(&psz_cur, seps);
1214 /* Load type (static, dynamic, or overlay) */
1215 if (token) {
1216 gen_obj->obj_data.node_obj.us_load_type = atoi(token);
1217 token = strsep(&psz_cur, seps);
1220 /* Dynamic load data requirements */
1221 if (token) {
1222 gen_obj->obj_data.node_obj.ul_data_mem_seg_mask =
1223 atoi(token);
1224 token = strsep(&psz_cur, seps);
1227 /* Dynamic load code requirements */
1228 if (token) {
1229 gen_obj->obj_data.node_obj.ul_code_mem_seg_mask =
1230 atoi(token);
1231 token = strsep(&psz_cur, seps);
1234 /* Extract node profiles into node properties */
1235 if (token) {
1237 gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1238 atoi(token);
1239 for (i = 0;
1241 gen_obj->obj_data.node_obj.
1242 ndb_props.count_profiles; i++) {
1243 token = strsep(&psz_cur, seps);
1244 if (token) {
1245 /* Heap Size for the node */
1246 gen_obj->obj_data.node_obj.
1247 ndb_props.node_profiles[i].
1248 ul_heap_size = atoi(token);
1252 token = strsep(&psz_cur, seps);
1253 if (token) {
1254 gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1255 (u32) (token);
1258 break;
1260 case DSP_DCDPROCESSORTYPE:
1262 * Parse COFF sect buffer to retrieve individual tokens used
1263 * to fill in object attrs.
1265 psz_cur = psz_buf;
1266 token = strsep(&psz_cur, seps);
1268 gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1269 token = strsep(&psz_cur, seps);
1271 gen_obj->obj_data.proc_info.processor_family = atoi(token);
1272 token = strsep(&psz_cur, seps);
1274 gen_obj->obj_data.proc_info.processor_type = atoi(token);
1275 token = strsep(&psz_cur, seps);
1277 gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1278 token = strsep(&psz_cur, seps);
1280 gen_obj->obj_data.proc_info.ul_internal_mem_size = atoi(token);
1281 token = strsep(&psz_cur, seps);
1283 gen_obj->obj_data.proc_info.ul_external_mem_size = atoi(token);
1284 token = strsep(&psz_cur, seps);
1286 gen_obj->obj_data.proc_info.processor_id = atoi(token);
1287 token = strsep(&psz_cur, seps);
1289 gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1290 token = strsep(&psz_cur, seps);
1292 gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1293 token = strsep(&psz_cur, seps);
1295 gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1297 #ifdef _DB_TIOMAP
1298 /* Proc object may contain additional(extended) attributes. */
1299 /* attr must match proc.hxx */
1300 for (entry_id = 0; entry_id < 7; entry_id++) {
1301 token = strsep(&psz_cur, seps);
1302 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1303 ul_gpp_phys = atoi(token);
1305 token = strsep(&psz_cur, seps);
1306 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1307 ul_dsp_virt = atoi(token);
1309 #endif
1311 break;
1313 default:
1314 status = -EPERM;
1315 break;
1318 return status;
1322 * ======== CompressBuffer ========
1323 * Purpose:
1324 * Compress the DSP buffer, if necessary, to conform to PC format.
1326 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1328 char *p;
1329 char ch;
1330 char *q;
1332 p = psz_buf;
1333 if (p == NULL)
1334 return;
1336 for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1337 ch = dsp_char2_gpp_char(q, char_size);
1338 if (ch == '\\') {
1339 q += char_size;
1340 ch = dsp_char2_gpp_char(q, char_size);
1341 switch (ch) {
1342 case 't':
1343 *p = '\t';
1344 break;
1346 case 'n':
1347 *p = '\n';
1348 break;
1350 case 'r':
1351 *p = '\r';
1352 break;
1354 case '0':
1355 *p = '\0';
1356 break;
1358 default:
1359 *p = ch;
1360 break;
1362 } else {
1363 *p = ch;
1365 p++;
1366 q += char_size;
1369 /* NULL out remainder of buffer. */
1370 while (p < q)
1371 *p++ = '\0';
1375 * ======== dsp_char2_gpp_char ========
1376 * Purpose:
1377 * Convert DSP char to host GPP char in a portable manner
1379 static char dsp_char2_gpp_char(char *pWord, s32 dsp_char_size)
1381 char ch = '\0';
1382 char *ch_src;
1383 s32 i;
1385 for (ch_src = pWord, i = dsp_char_size; i > 0; i--)
1386 ch |= *ch_src++;
1388 return ch;
1392 * ======== get_dep_lib_info ========
1394 static int get_dep_lib_info(IN struct dcd_manager *hdcd_mgr,
1395 IN struct dsp_uuid *uuid_obj,
1396 IN OUT u16 *pNumLibs,
1397 OPTIONAL OUT u16 *pNumPersLibs,
1398 OPTIONAL OUT struct dsp_uuid *dep_lib_uuids,
1399 OPTIONAL OUT bool *pPersistentDepLibs,
1400 enum nldr_phase phase)
1402 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1403 char *psz_coff_buf = NULL;
1404 char *psz_cur;
1405 char *psz_file_name = NULL;
1406 struct cod_libraryobj *lib = NULL;
1407 u32 ul_addr = 0; /* Used by cod_get_section */
1408 u32 ul_len = 0; /* Used by cod_get_section */
1409 u32 dw_data_size = COD_MAXPATHLENGTH;
1410 char seps[] = ", ";
1411 char *token = NULL;
1412 bool get_uuids = (dep_lib_uuids != NULL);
1413 u16 dep_libs = 0;
1414 int status = 0;
1416 DBC_REQUIRE(refs > 0);
1418 DBC_REQUIRE(hdcd_mgr);
1419 DBC_REQUIRE(pNumLibs != NULL);
1420 DBC_REQUIRE(uuid_obj != NULL);
1422 /* Initialize to 0 dependent libraries, if only counting number of
1423 * dependent libraries */
1424 if (!get_uuids) {
1425 *pNumLibs = 0;
1426 *pNumPersLibs = 0;
1429 /* Allocate a buffer for file name */
1430 psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1431 if (psz_file_name == NULL) {
1432 status = -ENOMEM;
1433 } else {
1434 /* Get the name of the library */
1435 status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1436 &dw_data_size, phase, NULL);
1439 /* Open the library */
1440 if (DSP_SUCCEEDED(status)) {
1441 status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1442 COD_NOLOAD, &lib);
1444 if (DSP_SUCCEEDED(status)) {
1445 /* Get dependent library section information. */
1446 status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1448 if (DSP_FAILED(status)) {
1449 /* Ok, no dependent libraries */
1450 ul_len = 0;
1451 status = 0;
1455 if (DSP_FAILED(status) || !(ul_len > 0))
1456 goto func_cont;
1458 /* Allocate zeroed buffer. */
1459 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1460 if (psz_coff_buf == NULL)
1461 status = -ENOMEM;
1463 /* Read section contents. */
1464 status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1465 if (DSP_FAILED(status))
1466 goto func_cont;
1468 /* Compress and format DSP buffer to conform to PC format. */
1469 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1471 /* Read from buffer */
1472 psz_cur = psz_coff_buf;
1473 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1474 if (get_uuids) {
1475 if (dep_libs >= *pNumLibs) {
1476 /* Gone beyond the limit */
1477 break;
1478 } else {
1479 /* Retrieve UUID string. */
1480 uuid_uuid_from_string(token,
1481 &(dep_lib_uuids
1482 [dep_libs]));
1483 /* Is this library persistent? */
1484 token = strsep(&psz_cur, seps);
1485 pPersistentDepLibs[dep_libs] = atoi(token);
1486 dep_libs++;
1488 } else {
1489 /* Advanc to next token */
1490 token = strsep(&psz_cur, seps);
1491 if (atoi(token))
1492 (*pNumPersLibs)++;
1494 /* Just counting number of dependent libraries */
1495 (*pNumLibs)++;
1498 func_cont:
1499 if (lib)
1500 cod_close(lib);
1502 /* Free previously allocated dynamic buffers. */
1503 kfree(psz_file_name);
1505 kfree(psz_coff_buf);
1507 return status;