Linux-libre 3.14.34-gnu
[librecmc/linux-libre.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 }