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