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