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. */
49struct dcd_manager {
50	struct cod_manager *cod_mgr;	/* Handle to COD manager object. */
51};
52
53/*  Pointer to the registry support key */
54static struct list_head reg_key_list;
55static DEFINE_SPINLOCK(dbdcd_lock);
56
57/* Global reference variables. */
58static u32 refs;
59static u32 enum_refs;
60
61/* Helper function prototypes. */
62static s32 atoi(char *psz_buf);
63static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
64				     enum dsp_dcdobjtype obj_type,
65				     struct dcd_genericobj *gen_obj);
66static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
67static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
68static 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 */
81int 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 */
101int 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 */
121int 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
150func_end:
151	return status;
152}
153
154/*
155 *  ======== dcd_destroy_manager ========
156 *  Purpose:
157 *      Frees DCD Manager object.
158 */
159int 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 */
182int 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 */
286void 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 */
304int 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 */
322int 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 */
341int 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);
486func_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 */
498int 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);
596func_cont:
597	if (lib)
598		cod_close(lib);
599
600func_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 */
610int 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 */
738bool 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 */
757int 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	}
900func_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 */
909int 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 */
934static 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 */
959static 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 */
1239static 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 */
1292static 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 */
1307static 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	}
1405func_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}
1416