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