• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/tidspbridge/rmgr/
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/*  ----------------------------------- Trace & Debug */
33#include <dspbridge/dbc.h>
34
35/*  ----------------------------------- Platform Manager */
36#include <dspbridge/cod.h>
37
38/*  ----------------------------------- Others */
39#include <dspbridge/uuidutil.h>
40
41/*  ----------------------------------- This */
42#include <dspbridge/dbdcd.h>
43
44/*  ----------------------------------- Global defines. */
45#define MAX_INT2CHAR_LENGTH     16	/* Max int2char len of 32 bit int */
46
47/* Name of section containing dependent libraries */
48#define DEPLIBSECT		".dspbridge_deplibs"
49
50/* DCD specific structures. */
51struct dcd_manager {
52	struct cod_manager *cod_mgr;	/* Handle to COD manager object. */
53};
54
55/*  Pointer to the registry support key */
56static struct list_head reg_key_list;
57static DEFINE_SPINLOCK(dbdcd_lock);
58
59/* Global reference variables. */
60static u32 refs;
61static u32 enum_refs;
62
63/* Helper function prototypes. */
64static s32 atoi(char *psz_buf);
65static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
66				     enum dsp_dcdobjtype obj_type,
67				     struct dcd_genericobj *gen_obj);
68static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
69static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
70static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
71				   struct dsp_uuid *uuid_obj,
72				   u16 *num_libs,
73				   u16 *num_pers_libs,
74				   struct dsp_uuid *dep_lib_uuids,
75				   bool *prstnt_dep_libs,
76				   enum nldr_phase phase);
77
78/*
79 *  ======== dcd_auto_register ========
80 *  Purpose:
81 *      Parses the supplied image and resigsters with DCD.
82 */
83int dcd_auto_register(struct dcd_manager *hdcd_mgr,
84			     char *sz_coff_path)
85{
86	int status = 0;
87
88	DBC_REQUIRE(refs > 0);
89
90	if (hdcd_mgr)
91		status = dcd_get_objects(hdcd_mgr, sz_coff_path,
92					 (dcd_registerfxn) dcd_register_object,
93					 (void *)sz_coff_path);
94	else
95		status = -EFAULT;
96
97	return status;
98}
99
100/*
101 *  ======== dcd_auto_unregister ========
102 *  Purpose:
103 *      Parses the supplied DSP image and unresiters from DCD.
104 */
105int dcd_auto_unregister(struct dcd_manager *hdcd_mgr,
106			       char *sz_coff_path)
107{
108	int status = 0;
109
110	DBC_REQUIRE(refs > 0);
111
112	if (hdcd_mgr)
113		status = dcd_get_objects(hdcd_mgr, sz_coff_path,
114					 (dcd_registerfxn) dcd_register_object,
115					 NULL);
116	else
117		status = -EFAULT;
118
119	return status;
120}
121
122/*
123 *  ======== dcd_create_manager ========
124 *  Purpose:
125 *      Creates DCD manager.
126 */
127int dcd_create_manager(char *sz_zl_dll_name,
128			      struct dcd_manager **dcd_mgr)
129{
130	struct cod_manager *cod_mgr;	/* COD manager handle */
131	struct dcd_manager *dcd_mgr_obj = NULL;	/* DCD Manager pointer */
132	int status = 0;
133
134	DBC_REQUIRE(refs >= 0);
135	DBC_REQUIRE(dcd_mgr);
136
137	status = cod_create(&cod_mgr, sz_zl_dll_name, NULL);
138	if (status)
139		goto func_end;
140
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;
146
147		/* Return handle to this DCD interface. */
148		*dcd_mgr = dcd_mgr_obj;
149	} else {
150		status = -ENOMEM;
151
152		/*
153		 * If allocation of DcdManager object failed, delete the
154		 * COD manager.
155		 */
156		cod_delete(cod_mgr);
157	}
158
159	DBC_ENSURE((!status) ||
160			((dcd_mgr_obj == NULL) && (status == -ENOMEM)));
161
162func_end:
163	return status;
164}
165
166/*
167 *  ======== dcd_destroy_manager ========
168 *  Purpose:
169 *      Frees DCD Manager object.
170 */
171int dcd_destroy_manager(struct dcd_manager *hdcd_mgr)
172{
173	struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
174	int status = -EFAULT;
175
176	DBC_REQUIRE(refs >= 0);
177
178	if (hdcd_mgr) {
179		/* Delete the COD manager. */
180		cod_delete(dcd_mgr_obj->cod_mgr);
181
182		/* Deallocate a DCD manager object. */
183		kfree(dcd_mgr_obj);
184
185		status = 0;
186	}
187
188	return status;
189}
190
191/*
192 *  ======== dcd_enumerate_object ========
193 *  Purpose:
194 *      Enumerates objects in the DCD.
195 */
196int dcd_enumerate_object(s32 index, enum dsp_dcdobjtype obj_type,
197				struct dsp_uuid *uuid_obj)
198{
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;
207
208	DBC_REQUIRE(refs >= 0);
209	DBC_REQUIRE(index >= 0);
210	DBC_REQUIRE(uuid_obj != NULL);
211
212	if ((index != 0) && (enum_refs == 0)) {
213		/*
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.
217		 */
218		status = -EIDRM;
219	} else {
220		/*
221		 * Pre-determine final key length. It's length of DCD_REGKEY +
222		 *  "_\0" + length of sz_obj_type string + terminating NULL.
223		 */
224		dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
225		DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
226
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;
235		}
236
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);
241
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;
252			}
253		}
254
255		if (!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;
264				}
265			}
266			spin_unlock(&dbdcd_lock);
267
268			if (&dcd_key->link == &reg_key_list)
269				status = -ENODATA;
270		}
271
272		if (!status) {
273			/* Create UUID value using string retrieved from
274			 * registry. */
275			uuid_uuid_from_string(sz_value, &dsp_uuid_obj);
276
277			*uuid_obj = dsp_uuid_obj;
278
279			/* Increment enum_refs to update reference count. */
280			enum_refs++;
281
282			status = 0;
283		} else if (status == -ENODATA) {
284			/* At the end of enumeration. Reset enum_refs. */
285			enum_refs = 0;
286
287			/*
288			 * TODO: Revisit, this is not an errror case but code
289			 * expects non-zero value.
290			 */
291			status = ENODATA;
292		} else {
293			status = -EPERM;
294		}
295	}
296
297	DBC_ENSURE(uuid_obj || (status == -EPERM));
298
299	return status;
300}
301
302/*
303 *  ======== dcd_exit ========
304 *  Purpose:
305 *      Discontinue usage of the DCD module.
306 */
307void dcd_exit(void)
308{
309	struct dcd_key_elem *rv, *rv_tmp;
310	DBC_REQUIRE(refs > 0);
311
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);
319		}
320	}
321
322	DBC_ENSURE(refs >= 0);
323}
324
325/*
326 *  ======== dcd_get_dep_libs ========
327 */
328int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr,
329			    struct dsp_uuid *uuid_obj,
330			    u16 num_libs, struct dsp_uuid *dep_lib_uuids,
331			    bool *prstnt_dep_libs,
332			    enum nldr_phase phase)
333{
334	int status = 0;
335
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(prstnt_dep_libs != NULL);
341
342	status =
343	    get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
344			     prstnt_dep_libs, phase);
345
346	return status;
347}
348
349/*
350 *  ======== dcd_get_num_dep_libs ========
351 */
352int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr,
353				struct dsp_uuid *uuid_obj,
354				u16 *num_libs, u16 *num_pers_libs,
355				enum nldr_phase phase)
356{
357	int status = 0;
358
359	DBC_REQUIRE(refs > 0);
360	DBC_REQUIRE(hdcd_mgr);
361	DBC_REQUIRE(num_libs != NULL);
362	DBC_REQUIRE(num_pers_libs != NULL);
363	DBC_REQUIRE(uuid_obj != NULL);
364
365	status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs,
366				  NULL, NULL, phase);
367
368	return status;
369}
370
371/*
372 *  ======== dcd_get_object_def ========
373 *  Purpose:
374 *      Retrieves the properties of a node or processor based on the UUID and
375 *      object type.
376 */
377int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
378			      struct dsp_uuid *obj_uuid,
379			      enum dsp_dcdobjtype obj_type,
380			      struct dcd_genericobj *obj_def)
381{
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. */
395
396	DBC_REQUIRE(refs > 0);
397	DBC_REQUIRE(obj_def != NULL);
398	DBC_REQUIRE(obj_uuid != NULL);
399
400	sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
401	if (!sz_uuid) {
402		status = -ENOMEM;
403		goto func_end;
404	}
405
406	if (!hdcd_mgr) {
407		status = -EFAULT;
408		goto func_end;
409	}
410
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);
415
416	/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
417	strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
418
419	if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
420		strncat(sz_reg_key, "_\0", 2);
421	else
422		status = -EPERM;
423
424	status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
425	if (status == -1) {
426		status = -EPERM;
427	} else {
428		status = 0;
429
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;
436		}
437
438		/* Create UUID value to set in registry. */
439		uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
440
441		if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
442			strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
443		else
444			status = -EPERM;
445
446		/* Retrieve paths from the registry based on struct dsp_uuid */
447		dw_buf_size = DCD_MAXPATHLENGTH;
448	}
449	if (!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;
455		}
456		spin_unlock(&dbdcd_lock);
457		if (&dcd_key->link == &reg_key_list) {
458			status = -ENOKEY;
459			goto func_end;
460		}
461	}
462
463
464	/* Open COFF file. */
465	status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
466							COD_NOLOAD, &lib);
467	if (status) {
468		status = -EACCES;
469		goto func_end;
470	}
471
472	/* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
473	DBC_ASSERT((strlen(sz_uuid) + 1) < sizeof(sz_sect_name));
474
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));
480
481	/* Get section information. */
482	status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
483	if (status) {
484		status = -EACCES;
485		goto func_end;
486	}
487
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__);
499	}
500#else
501	status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
502#endif
503	if (!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__);
511		}
512
513		/* Parse the content of the COFF buffer. */
514		status =
515		    get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
516		if (status)
517			status = -EACCES;
518	} else {
519		status = -EACCES;
520	}
521
522	/* Free the previously allocated dynamic buffer. */
523	kfree(psz_coff_buf);
524func_end:
525	if (lib)
526		cod_close(lib);
527
528	kfree(sz_uuid);
529
530	return status;
531}
532
533/*
534 *  ======== dcd_get_objects ========
535 */
536int dcd_get_objects(struct dcd_manager *hdcd_mgr,
537			   char *sz_coff_path, dcd_registerfxn register_fxn,
538			   void *handle)
539{
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;
551
552	DBC_REQUIRE(refs > 0);
553	if (!hdcd_mgr) {
554		status = -EFAULT;
555		goto func_end;
556	}
557
558	/* Open DSP coff file, don't load symbols. */
559	status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
560	if (status) {
561		status = -EACCES;
562		goto func_cont;
563	}
564
565	/* Get DCD_RESIGER_SECTION section information. */
566	status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
567	if (status || !(ul_len > 0)) {
568		status = -EACCES;
569		goto func_cont;
570	}
571
572	/* Allocate zeroed buffer. */
573	psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
574#ifdef _DB_TIOMAP
575	if (strstr(sz_coff_path, "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);
583	}
584#else
585	status =
586	    cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
587#endif
588	if (!status) {
589		/* Compress DSP buffer to conform to PC format. */
590		if (strstr(sz_coff_path, "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__);
596		}
597
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);
603
604			/*  Retrieve object type */
605			token = strsep(&psz_cur, seps);
606
607			/*  Retrieve object type */
608			object_type = atoi(token);
609
610			/*
611			 *  Apply register_fxn to the found DCD object.
612			 *  Possible actions include:
613			 *
614			 *  1) Register found DCD object.
615			 *  2) Unregister found DCD object (when handle == NULL)
616			 *  3) Add overlay node.
617			 */
618			status =
619			    register_fxn(&dsp_uuid_obj, object_type, handle);
620			if (status) {
621				/* if error occurs, break from while loop. */
622				break;
623			}
624		}
625	} else {
626		status = -EACCES;
627	}
628
629	/* Free the previously allocated dynamic buffer. */
630	kfree(psz_coff_buf);
631func_cont:
632	if (lib)
633		cod_close(lib);
634
635func_end:
636	return status;
637}
638
639/*
640 *  ======== dcd_get_library_name ========
641 *  Purpose:
642 *      Retrieves the library name for the given UUID.
643 *
644 */
645int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
646				struct dsp_uuid *uuid_obj,
647				char *str_lib_name,
648				u32 *buff_size,
649				enum nldr_phase phase, bool *phase_split)
650{
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;
657
658	DBC_REQUIRE(uuid_obj != NULL);
659	DBC_REQUIRE(str_lib_name != NULL);
660	DBC_REQUIRE(buff_size != NULL);
661	DBC_REQUIRE(hdcd_mgr);
662
663	dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
664		" buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
665		buff_size);
666
667	/*
668	 *  Pre-determine final key length. It's length of DCD_REGKEY +
669	 *  "_\0" + length of sz_obj_type string + terminating NULL.
670	 */
671	dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
672	DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
673
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;
680
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);
701	}
702	if (!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;
709		}
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;
716	}
717	if (!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;
724		}
725		spin_unlock(&dbdcd_lock);
726	}
727
728	if (&dcd_key->link == &reg_key_list)
729		status = -ENOKEY;
730
731	/* If can't find, phases might be registered as generic LIBRARYTYPE */
732	if (status && phase != NLDR_NOPHASE) {
733		if (phase_split)
734			*phase_split = false;
735
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;
742		}
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;
750		}
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;
756
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;
763		}
764		spin_unlock(&dbdcd_lock);
765
766		status = (&dcd_key->link != &reg_key_list) ?
767						0 : -ENOKEY;
768	}
769
770	if (!status)
771		memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
772	return status;
773}
774
775/*
776 *  ======== dcd_init ========
777 *  Purpose:
778 *      Initialize the DCD module.
779 */
780bool dcd_init(void)
781{
782	bool init_cod;
783	bool ret = true;
784
785	DBC_REQUIRE(refs >= 0);
786
787	if (refs == 0) {
788		/* Initialize required modules. */
789		init_cod = cod_init();
790
791		if (!init_cod) {
792			ret = false;
793			/* Exit initialized modules. */
794			if (init_cod)
795				cod_exit();
796		}
797
798		INIT_LIST_HEAD(&reg_key_list);
799	}
800
801	if (ret)
802		refs++;
803
804	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0)));
805
806	return ret;
807}
808
809/*
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.
814 */
815int dcd_register_object(struct dsp_uuid *uuid_obj,
816			       enum dsp_dcdobjtype obj_type,
817			       char *psz_path_name)
818{
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;
826
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));
835
836	dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
837		__func__, uuid_obj, obj_type, psz_path_name);
838
839	/*
840	 * Pre-determine final key length. It's length of DCD_REGKEY +
841	 *  "_\0" + length of sz_obj_type string + terminating NULL.
842	 */
843	dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
844	DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
845
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;
853	}
854
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;
866
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;
873	}
874
875	if (status)
876		goto func_end;
877
878	/*
879	 * If psz_path_name != NULL, perform registration, otherwise,
880	 * perform unregistration.
881	 */
882
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;
891		}
892		spin_unlock(&dbdcd_lock);
893		if (&dcd_key->link == &reg_key_list) {
894			/*
895			 * Add new reg value (UUID+obj_type)
896			 * with COFF path info
897			 */
898
899			dcd_key = kmalloc(sizeof(struct dcd_key_elem),
900								GFP_KERNEL);
901			if (!dcd_key) {
902				status = -ENOMEM;
903				goto func_end;
904			}
905
906			dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
907								GFP_KERNEL);
908
909			if (!dcd_key->path) {
910				kfree(dcd_key);
911				status = -ENOMEM;
912				goto func_end;
913			}
914
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;
933				}
934			}
935
936			/*  We have a match!  Copy out the data. */
937			memcpy(dcd_key->path, psz_path_name, dw_path_size);
938		}
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;
951			}
952		}
953		spin_unlock(&dbdcd_lock);
954		if (&dcd_key->link == &reg_key_list)
955			status = -EPERM;
956	}
957
958	if (!status) {
959		/*
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.
965		 */
966		enum_refs = 0;
967	}
968func_end:
969	return status;
970}
971
972/*
973 *  ======== dcd_unregister_object ========
974 *  Call DCD_Register object with psz_path_name set to NULL to
975 *  perform actual object de-registration.
976 */
977int dcd_unregister_object(struct dsp_uuid *uuid_obj,
978				 enum dsp_dcdobjtype obj_type)
979{
980	int status = 0;
981
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));
990
991	/*
992	 *  When dcd_register_object is called with NULL as pathname,
993	 *  it indicates an unregister object operation.
994	 */
995	status = dcd_register_object(uuid_obj, obj_type, NULL);
996
997	return status;
998}
999
1000/*
1001 **********************************************************************
1002 * DCD Helper Functions
1003 **********************************************************************
1004 */
1005
1006/*
1007 *  ======== atoi ========
1008 *  Purpose:
1009 *      This function converts strings in decimal or hex format to integers.
1010 */
1011static s32 atoi(char *psz_buf)
1012{
1013	char *pch = psz_buf;
1014	s32 base = 0;
1015	unsigned long res;
1016	int ret_val;
1017
1018	while (isspace(*pch))
1019		pch++;
1020
1021	if (*pch == '-' || *pch == '+') {
1022		base = 10;
1023		pch++;
1024	} else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
1025		base = 16;
1026	}
1027
1028	ret_val = strict_strtoul(pch, base, &res);
1029
1030	return ret_val ? : res;
1031}
1032
1033/*
1034 *  ======== get_attrs_from_buf ========
1035 *  Purpose:
1036 *      Parse the content of a buffer filled with DSP-side data and
1037 *      retrieve an object's attributes from it. IMPORTANT: Assume the
1038 *      buffer has been converted from DSP format to GPP format.
1039 */
1040static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
1041				     enum dsp_dcdobjtype obj_type,
1042				     struct dcd_genericobj *gen_obj)
1043{
1044	int status = 0;
1045	char seps[] = ", ";
1046	char *psz_cur;
1047	char *token;
1048	s32 token_len = 0;
1049	u32 i = 0;
1050#ifdef _DB_TIOMAP
1051	s32 entry_id;
1052#endif
1053
1054	DBC_REQUIRE(psz_buf != NULL);
1055	DBC_REQUIRE(ul_buf_size != 0);
1056	DBC_REQUIRE((obj_type == DSP_DCDNODETYPE)
1057		    || (obj_type == DSP_DCDPROCESSORTYPE));
1058	DBC_REQUIRE(gen_obj != NULL);
1059
1060	switch (obj_type) {
1061	case DSP_DCDNODETYPE:
1062		/*
1063		 * Parse COFF sect buffer to retrieve individual tokens used
1064		 * to fill in object attrs.
1065		 */
1066		psz_cur = psz_buf;
1067		token = strsep(&psz_cur, seps);
1068
1069		/* u32 cb_struct */
1070		gen_obj->obj_data.node_obj.ndb_props.cb_struct =
1071		    (u32) atoi(token);
1072		token = strsep(&psz_cur, seps);
1073
1074		/* dsp_uuid ui_node_id */
1075		uuid_uuid_from_string(token,
1076				      &gen_obj->obj_data.node_obj.ndb_props.
1077				      ui_node_id);
1078		token = strsep(&psz_cur, seps);
1079
1080		/* ac_name */
1081		DBC_REQUIRE(token);
1082		token_len = strlen(token);
1083		if (token_len > DSP_MAXNAMELEN - 1)
1084			token_len = DSP_MAXNAMELEN - 1;
1085
1086		strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
1087			token, token_len);
1088		gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1089		token = strsep(&psz_cur, seps);
1090		/* u32 ntype */
1091		gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1092		token = strsep(&psz_cur, seps);
1093		/* u32 cache_on_gpp */
1094		gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1095		token = strsep(&psz_cur, seps);
1096		/* dsp_resourcereqmts dsp_resource_reqmts */
1097		gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1098		    cb_struct = (u32) atoi(token);
1099		token = strsep(&psz_cur, seps);
1100
1101		gen_obj->obj_data.node_obj.ndb_props.
1102		    dsp_resource_reqmts.static_data_size = atoi(token);
1103		token = strsep(&psz_cur, seps);
1104		gen_obj->obj_data.node_obj.ndb_props.
1105		    dsp_resource_reqmts.global_data_size = atoi(token);
1106		token = strsep(&psz_cur, seps);
1107		gen_obj->obj_data.node_obj.ndb_props.
1108		    dsp_resource_reqmts.program_mem_size = atoi(token);
1109		token = strsep(&psz_cur, seps);
1110		gen_obj->obj_data.node_obj.ndb_props.
1111		    dsp_resource_reqmts.uwc_execution_time = atoi(token);
1112		token = strsep(&psz_cur, seps);
1113		gen_obj->obj_data.node_obj.ndb_props.
1114		    dsp_resource_reqmts.uwc_period = atoi(token);
1115		token = strsep(&psz_cur, seps);
1116
1117		gen_obj->obj_data.node_obj.ndb_props.
1118		    dsp_resource_reqmts.uwc_deadline = atoi(token);
1119		token = strsep(&psz_cur, seps);
1120
1121		gen_obj->obj_data.node_obj.ndb_props.
1122		    dsp_resource_reqmts.avg_exection_time = atoi(token);
1123		token = strsep(&psz_cur, seps);
1124
1125		gen_obj->obj_data.node_obj.ndb_props.
1126		    dsp_resource_reqmts.minimum_period = atoi(token);
1127		token = strsep(&psz_cur, seps);
1128
1129		/* s32 prio */
1130		gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1131		token = strsep(&psz_cur, seps);
1132
1133		/* u32 stack_size */
1134		gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1135		token = strsep(&psz_cur, seps);
1136
1137		/* u32 sys_stack_size */
1138		gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1139		    atoi(token);
1140		token = strsep(&psz_cur, seps);
1141
1142		/* u32 stack_seg */
1143		gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1144		token = strsep(&psz_cur, seps);
1145
1146		/* u32 message_depth */
1147		gen_obj->obj_data.node_obj.ndb_props.message_depth =
1148		    atoi(token);
1149		token = strsep(&psz_cur, seps);
1150
1151		/* u32 num_input_streams */
1152		gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1153		    atoi(token);
1154		token = strsep(&psz_cur, seps);
1155
1156		/* u32 num_output_streams */
1157		gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1158		    atoi(token);
1159		token = strsep(&psz_cur, seps);
1160
1161		/* u32 utimeout */
1162		gen_obj->obj_data.node_obj.ndb_props.utimeout = atoi(token);
1163		token = strsep(&psz_cur, seps);
1164
1165		/* char *pstr_create_phase_fxn */
1166		DBC_REQUIRE(token);
1167		token_len = strlen(token);
1168		gen_obj->obj_data.node_obj.pstr_create_phase_fxn =
1169					kzalloc(token_len + 1, GFP_KERNEL);
1170		strncpy(gen_obj->obj_data.node_obj.pstr_create_phase_fxn,
1171			token, token_len);
1172		gen_obj->obj_data.node_obj.pstr_create_phase_fxn[token_len] =
1173		    '\0';
1174		token = strsep(&psz_cur, seps);
1175
1176		/* char *pstr_execute_phase_fxn */
1177		DBC_REQUIRE(token);
1178		token_len = strlen(token);
1179		gen_obj->obj_data.node_obj.pstr_execute_phase_fxn =
1180					kzalloc(token_len + 1, GFP_KERNEL);
1181		strncpy(gen_obj->obj_data.node_obj.pstr_execute_phase_fxn,
1182			token, token_len);
1183		gen_obj->obj_data.node_obj.pstr_execute_phase_fxn[token_len] =
1184		    '\0';
1185		token = strsep(&psz_cur, seps);
1186
1187		/* char *pstr_delete_phase_fxn */
1188		DBC_REQUIRE(token);
1189		token_len = strlen(token);
1190		gen_obj->obj_data.node_obj.pstr_delete_phase_fxn =
1191					kzalloc(token_len + 1, GFP_KERNEL);
1192		strncpy(gen_obj->obj_data.node_obj.pstr_delete_phase_fxn,
1193			token, token_len);
1194		gen_obj->obj_data.node_obj.pstr_delete_phase_fxn[token_len] =
1195		    '\0';
1196		token = strsep(&psz_cur, seps);
1197
1198		/* Segment id for message buffers */
1199		gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1200		token = strsep(&psz_cur, seps);
1201
1202		/* Message notification type */
1203		gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1204		token = strsep(&psz_cur, seps);
1205
1206		/* char *pstr_i_alg_name */
1207		if (token) {
1208			token_len = strlen(token);
1209			gen_obj->obj_data.node_obj.pstr_i_alg_name =
1210					kzalloc(token_len + 1, GFP_KERNEL);
1211			strncpy(gen_obj->obj_data.node_obj.pstr_i_alg_name,
1212				token, token_len);
1213			gen_obj->obj_data.node_obj.pstr_i_alg_name[token_len] =
1214			    '\0';
1215			token = strsep(&psz_cur, seps);
1216		}
1217
1218		/* Load type (static, dynamic, or overlay) */
1219		if (token) {
1220			gen_obj->obj_data.node_obj.us_load_type = atoi(token);
1221			token = strsep(&psz_cur, seps);
1222		}
1223
1224		/* Dynamic load data requirements */
1225		if (token) {
1226			gen_obj->obj_data.node_obj.ul_data_mem_seg_mask =
1227			    atoi(token);
1228			token = strsep(&psz_cur, seps);
1229		}
1230
1231		/* Dynamic load code requirements */
1232		if (token) {
1233			gen_obj->obj_data.node_obj.ul_code_mem_seg_mask =
1234			    atoi(token);
1235			token = strsep(&psz_cur, seps);
1236		}
1237
1238		/* Extract node profiles into node properties */
1239		if (token) {
1240
1241			gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1242			    atoi(token);
1243			for (i = 0;
1244			     i <
1245			     gen_obj->obj_data.node_obj.
1246			     ndb_props.count_profiles; i++) {
1247				token = strsep(&psz_cur, seps);
1248				if (token) {
1249					/* Heap Size for the node */
1250					gen_obj->obj_data.node_obj.
1251					    ndb_props.node_profiles[i].
1252					    ul_heap_size = atoi(token);
1253				}
1254			}
1255		}
1256		token = strsep(&psz_cur, seps);
1257		if (token) {
1258			gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1259			    (u32) (token);
1260		}
1261
1262		break;
1263
1264	case DSP_DCDPROCESSORTYPE:
1265		/*
1266		 * Parse COFF sect buffer to retrieve individual tokens used
1267		 * to fill in object attrs.
1268		 */
1269		psz_cur = psz_buf;
1270		token = strsep(&psz_cur, seps);
1271
1272		gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1273		token = strsep(&psz_cur, seps);
1274
1275		gen_obj->obj_data.proc_info.processor_family = atoi(token);
1276		token = strsep(&psz_cur, seps);
1277
1278		gen_obj->obj_data.proc_info.processor_type = atoi(token);
1279		token = strsep(&psz_cur, seps);
1280
1281		gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1282		token = strsep(&psz_cur, seps);
1283
1284		gen_obj->obj_data.proc_info.ul_internal_mem_size = atoi(token);
1285		token = strsep(&psz_cur, seps);
1286
1287		gen_obj->obj_data.proc_info.ul_external_mem_size = atoi(token);
1288		token = strsep(&psz_cur, seps);
1289
1290		gen_obj->obj_data.proc_info.processor_id = atoi(token);
1291		token = strsep(&psz_cur, seps);
1292
1293		gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1294		token = strsep(&psz_cur, seps);
1295
1296		gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1297		token = strsep(&psz_cur, seps);
1298
1299		gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1300
1301#ifdef _DB_TIOMAP
1302		/* Proc object may contain additional(extended) attributes. */
1303		/* attr must match proc.hxx */
1304		for (entry_id = 0; entry_id < 7; entry_id++) {
1305			token = strsep(&psz_cur, seps);
1306			gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1307			    ul_gpp_phys = atoi(token);
1308
1309			token = strsep(&psz_cur, seps);
1310			gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1311			    ul_dsp_virt = atoi(token);
1312		}
1313#endif
1314
1315		break;
1316
1317	default:
1318		status = -EPERM;
1319		break;
1320	}
1321
1322	return status;
1323}
1324
1325/*
1326 *  ======== CompressBuffer ========
1327 *  Purpose:
1328 *      Compress the DSP buffer, if necessary, to conform to PC format.
1329 */
1330static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1331{
1332	char *p;
1333	char ch;
1334	char *q;
1335
1336	p = psz_buf;
1337	if (p == NULL)
1338		return;
1339
1340	for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1341		ch = dsp_char2_gpp_char(q, char_size);
1342		if (ch == '\\') {
1343			q += char_size;
1344			ch = dsp_char2_gpp_char(q, char_size);
1345			switch (ch) {
1346			case 't':
1347				*p = '\t';
1348				break;
1349
1350			case 'n':
1351				*p = '\n';
1352				break;
1353
1354			case 'r':
1355				*p = '\r';
1356				break;
1357
1358			case '0':
1359				*p = '\0';
1360				break;
1361
1362			default:
1363				*p = ch;
1364				break;
1365			}
1366		} else {
1367			*p = ch;
1368		}
1369		p++;
1370		q += char_size;
1371	}
1372
1373	/* NULL out remainder of buffer. */
1374	while (p < q)
1375		*p++ = '\0';
1376}
1377
1378/*
1379 *  ======== dsp_char2_gpp_char ========
1380 *  Purpose:
1381 *      Convert DSP char to host GPP char in a portable manner
1382 */
1383static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
1384{
1385	char ch = '\0';
1386	char *ch_src;
1387	s32 i;
1388
1389	for (ch_src = word, i = dsp_char_size; i > 0; i--)
1390		ch |= *ch_src++;
1391
1392	return ch;
1393}
1394
1395/*
1396 *  ======== get_dep_lib_info ========
1397 */
1398static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
1399				   struct dsp_uuid *uuid_obj,
1400				   u16 *num_libs,
1401				   u16 *num_pers_libs,
1402				   struct dsp_uuid *dep_lib_uuids,
1403				   bool *prstnt_dep_libs,
1404				   enum nldr_phase phase)
1405{
1406	struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1407	char *psz_coff_buf = NULL;
1408	char *psz_cur;
1409	char *psz_file_name = NULL;
1410	struct cod_libraryobj *lib = NULL;
1411	u32 ul_addr = 0;	/* Used by cod_get_section */
1412	u32 ul_len = 0;		/* Used by cod_get_section */
1413	u32 dw_data_size = COD_MAXPATHLENGTH;
1414	char seps[] = ", ";
1415	char *token = NULL;
1416	bool get_uuids = (dep_lib_uuids != NULL);
1417	u16 dep_libs = 0;
1418	int status = 0;
1419
1420	DBC_REQUIRE(refs > 0);
1421
1422	DBC_REQUIRE(hdcd_mgr);
1423	DBC_REQUIRE(num_libs != NULL);
1424	DBC_REQUIRE(uuid_obj != NULL);
1425
1426	/*  Initialize to 0 dependent libraries, if only counting number of
1427	 *  dependent libraries */
1428	if (!get_uuids) {
1429		*num_libs = 0;
1430		*num_pers_libs = 0;
1431	}
1432
1433	/* Allocate a buffer for file name */
1434	psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1435	if (psz_file_name == NULL) {
1436		status = -ENOMEM;
1437	} else {
1438		/* Get the name of the library */
1439		status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1440					      &dw_data_size, phase, NULL);
1441	}
1442
1443	/* Open the library */
1444	if (!status) {
1445		status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1446				  COD_NOLOAD, &lib);
1447	}
1448	if (!status) {
1449		/* Get dependent library section information. */
1450		status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1451
1452		if (status) {
1453			/* Ok, no dependent libraries */
1454			ul_len = 0;
1455			status = 0;
1456		}
1457	}
1458
1459	if (status || !(ul_len > 0))
1460		goto func_cont;
1461
1462	/* Allocate zeroed buffer. */
1463	psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1464	if (psz_coff_buf == NULL)
1465		status = -ENOMEM;
1466
1467	/* Read section contents. */
1468	status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1469	if (status)
1470		goto func_cont;
1471
1472	/* Compress and format DSP buffer to conform to PC format. */
1473	compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1474
1475	/* Read from buffer */
1476	psz_cur = psz_coff_buf;
1477	while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1478		if (get_uuids) {
1479			if (dep_libs >= *num_libs) {
1480				/* Gone beyond the limit */
1481				break;
1482			} else {
1483				/* Retrieve UUID string. */
1484				uuid_uuid_from_string(token,
1485						      &(dep_lib_uuids
1486							[dep_libs]));
1487				/* Is this library persistent? */
1488				token = strsep(&psz_cur, seps);
1489				prstnt_dep_libs[dep_libs] = atoi(token);
1490				dep_libs++;
1491			}
1492		} else {
1493			/* Advanc to next token */
1494			token = strsep(&psz_cur, seps);
1495			if (atoi(token))
1496				(*num_pers_libs)++;
1497
1498			/* Just counting number of dependent libraries */
1499			(*num_libs)++;
1500		}
1501	}
1502func_cont:
1503	if (lib)
1504		cod_close(lib);
1505
1506	/* Free previously allocated dynamic buffers. */
1507	kfree(psz_file_name);
1508
1509	kfree(psz_coff_buf);
1510
1511	return status;
1512}
1513