Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dbdcd.c
Go to the documentation of this file.
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. */
49 struct dcd_manager {
50  struct cod_manager *cod_mgr; /* Handle to COD manager object. */
51 };
52 
53 /* Pointer to the registry support key */
54 static struct list_head reg_key_list;
55 static DEFINE_SPINLOCK(dbdcd_lock);
56 
57 /* Global reference variables. */
58 static u32 refs;
59 static u32 enum_refs;
60 
61 /* Helper function prototypes. */
62 static s32 atoi(char *psz_buf);
63 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
64  enum dsp_dcdobjtype obj_type,
65  struct dcd_genericobj *gen_obj);
66 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
67 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
68 static 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  */
81 int 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,
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  */
101 int 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,
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  */
121 int 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 
150 func_end:
151  return status;
152 }
153 
154 /*
155  * ======== dcd_destroy_manager ========
156  * Purpose:
157  * Frees DCD Manager object.
158  */
159 int 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  */
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")) <
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)) <
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  */
286 void 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  */
304 int 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  */
322 int 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  */
341 int 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)) <
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);
503 func_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  */
515 int 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;
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. */
560  psz_coff_buf, ul_len);
561  } else {
562  dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
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);
613 func_cont:
614  if (lib)
615  cod_close(lib);
616 
617 func_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  */
627 int 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)) <
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")) <
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  */
755 bool 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  */
774 int 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)) <
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(strlen(sz_reg_key) + 1,
856  GFP_KERNEL);
857 
858  if (!dcd_key->path) {
859  kfree(dcd_key);
860  status = -ENOMEM;
861  goto func_end;
862  }
863 
864  strncpy(dcd_key->name, sz_reg_key,
865  strlen(sz_reg_key) + 1);
866  strncpy(dcd_key->path, psz_path_name ,
867  dw_path_size);
868  spin_lock(&dbdcd_lock);
869  list_add_tail(&dcd_key->link, &reg_key_list);
870  spin_unlock(&dbdcd_lock);
871  } else {
872  /* Make sure the new data is the same. */
873  if (strncmp(dcd_key->path, psz_path_name,
874  dw_path_size)) {
875  /* The caller needs a different data size! */
876  kfree(dcd_key->path);
877  dcd_key->path = kmalloc(dw_path_size,
878  GFP_KERNEL);
879  if (dcd_key->path == NULL) {
880  status = -ENOMEM;
881  goto func_end;
882  }
883  }
884 
885  /* We have a match! Copy out the data. */
886  memcpy(dcd_key->path, psz_path_name, dw_path_size);
887  }
888  dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
889  __func__, psz_path_name, dw_path_size);
890  } else {
891  /* Deregister an existing object */
892  spin_lock(&dbdcd_lock);
893  list_for_each_entry(dcd_key, &reg_key_list, link) {
894  if (!strncmp(dcd_key->name, sz_reg_key,
895  strlen(sz_reg_key) + 1)) {
896  list_del(&dcd_key->link);
897  kfree(dcd_key->path);
898  kfree(dcd_key);
899  break;
900  }
901  }
902  spin_unlock(&dbdcd_lock);
903  if (&dcd_key->link == &reg_key_list)
904  status = -EPERM;
905  }
906 
907  if (!status) {
908  /*
909  * Because the node database has been updated through a
910  * successful object registration/de-registration operation,
911  * we need to reset the object enumeration counter to allow
912  * current enumerations to reflect this update in the node
913  * database.
914  */
915  enum_refs = 0;
916  }
917 func_end:
918  return status;
919 }
920 
921 /*
922  * ======== dcd_unregister_object ========
923  * Call DCD_Register object with psz_path_name set to NULL to
924  * perform actual object de-registration.
925  */
926 int dcd_unregister_object(struct dsp_uuid *uuid_obj,
927  enum dsp_dcdobjtype obj_type)
928 {
929  int status = 0;
930 
931  /*
932  * When dcd_register_object is called with NULL as pathname,
933  * it indicates an unregister object operation.
934  */
935  status = dcd_register_object(uuid_obj, obj_type, NULL);
936 
937  return status;
938 }
939 
940 /*
941  **********************************************************************
942  * DCD Helper Functions
943  **********************************************************************
944  */
945 
946 /*
947  * ======== atoi ========
948  * Purpose:
949  * This function converts strings in decimal or hex format to integers.
950  */
951 static s32 atoi(char *psz_buf)
952 {
953  char *pch = psz_buf;
954  s32 base = 0;
955 
956  while (isspace(*pch))
957  pch++;
958 
959  if (*pch == '-' || *pch == '+') {
960  base = 10;
961  pch++;
962  } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
963  base = 16;
964  }
965 
966  return simple_strtoul(pch, NULL, base);
967 }
968 
969 /*
970  * ======== get_attrs_from_buf ========
971  * Purpose:
972  * Parse the content of a buffer filled with DSP-side data and
973  * retrieve an object's attributes from it. IMPORTANT: Assume the
974  * buffer has been converted from DSP format to GPP format.
975  */
976 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
977  enum dsp_dcdobjtype obj_type,
978  struct dcd_genericobj *gen_obj)
979 {
980  int status = 0;
981  char seps[] = ", ";
982  char *psz_cur;
983  char *token;
984  s32 token_len = 0;
985  u32 i = 0;
986 #ifdef _DB_TIOMAP
987  s32 entry_id;
988 #endif
989 
990  switch (obj_type) {
991  case DSP_DCDNODETYPE:
992  /*
993  * Parse COFF sect buffer to retrieve individual tokens used
994  * to fill in object attrs.
995  */
996  psz_cur = psz_buf;
997  token = strsep(&psz_cur, seps);
998 
999  /* u32 cb_struct */
1000  gen_obj->obj_data.node_obj.ndb_props.cb_struct =
1001  (u32) atoi(token);
1002  token = strsep(&psz_cur, seps);
1003 
1004  /* dsp_uuid ui_node_id */
1005  uuid_uuid_from_string(token,
1006  &gen_obj->obj_data.node_obj.ndb_props.
1007  ui_node_id);
1008  token = strsep(&psz_cur, seps);
1009 
1010  /* ac_name */
1011  token_len = strlen(token);
1012  if (token_len > DSP_MAXNAMELEN - 1)
1013  token_len = DSP_MAXNAMELEN - 1;
1014 
1015  strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
1016  token, token_len);
1017  gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1018  token = strsep(&psz_cur, seps);
1019  /* u32 ntype */
1020  gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1021  token = strsep(&psz_cur, seps);
1022  /* u32 cache_on_gpp */
1023  gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1024  token = strsep(&psz_cur, seps);
1025  /* dsp_resourcereqmts dsp_resource_reqmts */
1026  gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1027  cb_struct = (u32) atoi(token);
1028  token = strsep(&psz_cur, seps);
1029 
1030  gen_obj->obj_data.node_obj.ndb_props.
1031  dsp_resource_reqmts.static_data_size = atoi(token);
1032  token = strsep(&psz_cur, seps);
1033  gen_obj->obj_data.node_obj.ndb_props.
1034  dsp_resource_reqmts.global_data_size = atoi(token);
1035  token = strsep(&psz_cur, seps);
1036  gen_obj->obj_data.node_obj.ndb_props.
1037  dsp_resource_reqmts.program_mem_size = atoi(token);
1038  token = strsep(&psz_cur, seps);
1039  gen_obj->obj_data.node_obj.ndb_props.
1040  dsp_resource_reqmts.wc_execution_time = atoi(token);
1041  token = strsep(&psz_cur, seps);
1042  gen_obj->obj_data.node_obj.ndb_props.
1043  dsp_resource_reqmts.wc_period = atoi(token);
1044  token = strsep(&psz_cur, seps);
1045 
1046  gen_obj->obj_data.node_obj.ndb_props.
1047  dsp_resource_reqmts.wc_deadline = atoi(token);
1048  token = strsep(&psz_cur, seps);
1049 
1050  gen_obj->obj_data.node_obj.ndb_props.
1051  dsp_resource_reqmts.avg_exection_time = atoi(token);
1052  token = strsep(&psz_cur, seps);
1053 
1054  gen_obj->obj_data.node_obj.ndb_props.
1055  dsp_resource_reqmts.minimum_period = atoi(token);
1056  token = strsep(&psz_cur, seps);
1057 
1058  /* s32 prio */
1059  gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1060  token = strsep(&psz_cur, seps);
1061 
1062  /* u32 stack_size */
1063  gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1064  token = strsep(&psz_cur, seps);
1065 
1066  /* u32 sys_stack_size */
1067  gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1068  atoi(token);
1069  token = strsep(&psz_cur, seps);
1070 
1071  /* u32 stack_seg */
1072  gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1073  token = strsep(&psz_cur, seps);
1074 
1075  /* u32 message_depth */
1076  gen_obj->obj_data.node_obj.ndb_props.message_depth =
1077  atoi(token);
1078  token = strsep(&psz_cur, seps);
1079 
1080  /* u32 num_input_streams */
1081  gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1082  atoi(token);
1083  token = strsep(&psz_cur, seps);
1084 
1085  /* u32 num_output_streams */
1086  gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1087  atoi(token);
1088  token = strsep(&psz_cur, seps);
1089 
1090  /* u32 timeout */
1091  gen_obj->obj_data.node_obj.ndb_props.timeout = atoi(token);
1092  token = strsep(&psz_cur, seps);
1093 
1094  /* char *str_create_phase_fxn */
1095  token_len = strlen(token);
1096  gen_obj->obj_data.node_obj.str_create_phase_fxn =
1097  kzalloc(token_len + 1, GFP_KERNEL);
1098  strncpy(gen_obj->obj_data.node_obj.str_create_phase_fxn,
1099  token, token_len);
1100  gen_obj->obj_data.node_obj.str_create_phase_fxn[token_len] =
1101  '\0';
1102  token = strsep(&psz_cur, seps);
1103 
1104  /* char *str_execute_phase_fxn */
1105  token_len = strlen(token);
1106  gen_obj->obj_data.node_obj.str_execute_phase_fxn =
1107  kzalloc(token_len + 1, GFP_KERNEL);
1108  strncpy(gen_obj->obj_data.node_obj.str_execute_phase_fxn,
1109  token, token_len);
1110  gen_obj->obj_data.node_obj.str_execute_phase_fxn[token_len] =
1111  '\0';
1112  token = strsep(&psz_cur, seps);
1113 
1114  /* char *str_delete_phase_fxn */
1115  token_len = strlen(token);
1116  gen_obj->obj_data.node_obj.str_delete_phase_fxn =
1117  kzalloc(token_len + 1, GFP_KERNEL);
1118  strncpy(gen_obj->obj_data.node_obj.str_delete_phase_fxn,
1119  token, token_len);
1120  gen_obj->obj_data.node_obj.str_delete_phase_fxn[token_len] =
1121  '\0';
1122  token = strsep(&psz_cur, seps);
1123 
1124  /* Segment id for message buffers */
1125  gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1126  token = strsep(&psz_cur, seps);
1127 
1128  /* Message notification type */
1129  gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1130  token = strsep(&psz_cur, seps);
1131 
1132  /* char *str_i_alg_name */
1133  if (token) {
1134  token_len = strlen(token);
1135  gen_obj->obj_data.node_obj.str_i_alg_name =
1136  kzalloc(token_len + 1, GFP_KERNEL);
1137  strncpy(gen_obj->obj_data.node_obj.str_i_alg_name,
1138  token, token_len);
1139  gen_obj->obj_data.node_obj.str_i_alg_name[token_len] =
1140  '\0';
1141  token = strsep(&psz_cur, seps);
1142  }
1143 
1144  /* Load type (static, dynamic, or overlay) */
1145  if (token) {
1146  gen_obj->obj_data.node_obj.load_type = atoi(token);
1147  token = strsep(&psz_cur, seps);
1148  }
1149 
1150  /* Dynamic load data requirements */
1151  if (token) {
1152  gen_obj->obj_data.node_obj.data_mem_seg_mask =
1153  atoi(token);
1154  token = strsep(&psz_cur, seps);
1155  }
1156 
1157  /* Dynamic load code requirements */
1158  if (token) {
1159  gen_obj->obj_data.node_obj.code_mem_seg_mask =
1160  atoi(token);
1161  token = strsep(&psz_cur, seps);
1162  }
1163 
1164  /* Extract node profiles into node properties */
1165  if (token) {
1166 
1167  gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1168  atoi(token);
1169  for (i = 0;
1170  i <
1171  gen_obj->obj_data.node_obj.
1172  ndb_props.count_profiles; i++) {
1173  token = strsep(&psz_cur, seps);
1174  if (token) {
1175  /* Heap Size for the node */
1176  gen_obj->obj_data.node_obj.
1177  ndb_props.node_profiles[i].
1178  heap_size = atoi(token);
1179  }
1180  }
1181  }
1182  token = strsep(&psz_cur, seps);
1183  if (token) {
1184  gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1185  (u32) (token);
1186  }
1187 
1188  break;
1189 
1190  case DSP_DCDPROCESSORTYPE:
1191  /*
1192  * Parse COFF sect buffer to retrieve individual tokens used
1193  * to fill in object attrs.
1194  */
1195  psz_cur = psz_buf;
1196  token = strsep(&psz_cur, seps);
1197 
1198  gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1199  token = strsep(&psz_cur, seps);
1200 
1201  gen_obj->obj_data.proc_info.processor_family = atoi(token);
1202  token = strsep(&psz_cur, seps);
1203 
1204  gen_obj->obj_data.proc_info.processor_type = atoi(token);
1205  token = strsep(&psz_cur, seps);
1206 
1207  gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1208  token = strsep(&psz_cur, seps);
1209 
1210  gen_obj->obj_data.proc_info.internal_mem_size = atoi(token);
1211  token = strsep(&psz_cur, seps);
1212 
1213  gen_obj->obj_data.proc_info.external_mem_size = atoi(token);
1214  token = strsep(&psz_cur, seps);
1215 
1216  gen_obj->obj_data.proc_info.processor_id = atoi(token);
1217  token = strsep(&psz_cur, seps);
1218 
1219  gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1220  token = strsep(&psz_cur, seps);
1221 
1222  gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1223  token = strsep(&psz_cur, seps);
1224 
1225  gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1226 
1227 #ifdef _DB_TIOMAP
1228  /* Proc object may contain additional(extended) attributes. */
1229  /* attr must match proc.hxx */
1230  for (entry_id = 0; entry_id < 7; entry_id++) {
1231  token = strsep(&psz_cur, seps);
1232  gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1233  gpp_phys = atoi(token);
1234 
1235  token = strsep(&psz_cur, seps);
1236  gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1237  dsp_virt = atoi(token);
1238  }
1239 #endif
1240 
1241  break;
1242 
1243  default:
1244  status = -EPERM;
1245  break;
1246  }
1247 
1248  return status;
1249 }
1250 
1251 /*
1252  * ======== CompressBuffer ========
1253  * Purpose:
1254  * Compress the DSP buffer, if necessary, to conform to PC format.
1255  */
1256 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1257 {
1258  char *p;
1259  char ch;
1260  char *q;
1261 
1262  p = psz_buf;
1263  if (p == NULL)
1264  return;
1265 
1266  for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1267  ch = dsp_char2_gpp_char(q, char_size);
1268  if (ch == '\\') {
1269  q += char_size;
1270  ch = dsp_char2_gpp_char(q, char_size);
1271  switch (ch) {
1272  case 't':
1273  *p = '\t';
1274  break;
1275 
1276  case 'n':
1277  *p = '\n';
1278  break;
1279 
1280  case 'r':
1281  *p = '\r';
1282  break;
1283 
1284  case '0':
1285  *p = '\0';
1286  break;
1287 
1288  default:
1289  *p = ch;
1290  break;
1291  }
1292  } else {
1293  *p = ch;
1294  }
1295  p++;
1296  q += char_size;
1297  }
1298 
1299  /* NULL out remainder of buffer. */
1300  while (p < q)
1301  *p++ = '\0';
1302 }
1303 
1304 /*
1305  * ======== dsp_char2_gpp_char ========
1306  * Purpose:
1307  * Convert DSP char to host GPP char in a portable manner
1308  */
1309 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
1310 {
1311  char ch = '\0';
1312  char *ch_src;
1313  s32 i;
1314 
1315  for (ch_src = word, i = dsp_char_size; i > 0; i--)
1316  ch |= *ch_src++;
1317 
1318  return ch;
1319 }
1320 
1321 /*
1322  * ======== get_dep_lib_info ========
1323  */
1324 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
1325  struct dsp_uuid *uuid_obj,
1326  u16 *num_libs,
1327  u16 *num_pers_libs,
1328  struct dsp_uuid *dep_lib_uuids,
1329  bool *prstnt_dep_libs,
1330  enum nldr_phase phase)
1331 {
1332  struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1333  char *psz_coff_buf = NULL;
1334  char *psz_cur;
1335  char *psz_file_name = NULL;
1336  struct cod_libraryobj *lib = NULL;
1337  u32 ul_addr = 0; /* Used by cod_get_section */
1338  u32 ul_len = 0; /* Used by cod_get_section */
1339  u32 dw_data_size = COD_MAXPATHLENGTH;
1340  char seps[] = ", ";
1341  char *token = NULL;
1342  bool get_uuids = (dep_lib_uuids != NULL);
1343  u16 dep_libs = 0;
1344  int status = 0;
1345 
1346  /* Initialize to 0 dependent libraries, if only counting number of
1347  * dependent libraries */
1348  if (!get_uuids) {
1349  *num_libs = 0;
1350  *num_pers_libs = 0;
1351  }
1352 
1353  /* Allocate a buffer for file name */
1354  psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1355  if (psz_file_name == NULL) {
1356  status = -ENOMEM;
1357  } else {
1358  /* Get the name of the library */
1359  status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1360  &dw_data_size, phase, NULL);
1361  }
1362 
1363  /* Open the library */
1364  if (!status) {
1365  status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1366  COD_NOLOAD, &lib);
1367  }
1368  if (!status) {
1369  /* Get dependent library section information. */
1370  status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1371 
1372  if (status) {
1373  /* Ok, no dependent libraries */
1374  ul_len = 0;
1375  status = 0;
1376  }
1377  }
1378 
1379  if (status || !(ul_len > 0))
1380  goto func_cont;
1381 
1382  /* Allocate zeroed buffer. */
1383  psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1384  if (psz_coff_buf == NULL)
1385  status = -ENOMEM;
1386 
1387  /* Read section contents. */
1388  status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1389  if (status)
1390  goto func_cont;
1391 
1392  /* Compress and format DSP buffer to conform to PC format. */
1393  compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1394 
1395  /* Read from buffer */
1396  psz_cur = psz_coff_buf;
1397  while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1398  if (get_uuids) {
1399  if (dep_libs >= *num_libs) {
1400  /* Gone beyond the limit */
1401  break;
1402  } else {
1403  /* Retrieve UUID string. */
1404  uuid_uuid_from_string(token,
1405  &(dep_lib_uuids
1406  [dep_libs]));
1407  /* Is this library persistent? */
1408  token = strsep(&psz_cur, seps);
1409  prstnt_dep_libs[dep_libs] = atoi(token);
1410  dep_libs++;
1411  }
1412  } else {
1413  /* Advanc to next token */
1414  token = strsep(&psz_cur, seps);
1415  if (atoi(token))
1416  (*num_pers_libs)++;
1417 
1418  /* Just counting number of dependent libraries */
1419  (*num_libs)++;
1420  }
1421  }
1422 func_cont:
1423  if (lib)
1424  cod_close(lib);
1425 
1426  /* Free previously allocated dynamic buffers. */
1427  kfree(psz_file_name);
1428 
1429  kfree(psz_coff_buf);
1430 
1431  return status;
1432 }