Linux Audio

Check our new training course

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