2275dd0ebd359629dbe49913394341969028b876
[keystone-rtos/rm-lld.git] / src / rm_dtb_util.c
1 /**
2  *   @file  rm_dtb_util.c
3  *
4  *   @brief   
5  *      This is the Resource Manager Resource List and Policy DTB parsing 
6  *      utility source
7  *
8  *  \par
9  *  ============================================================================
10  *  @n   (C) Copyright 2012, Texas Instruments, Inc.
11  * 
12  *  Redistribution and use in source and binary forms, with or without 
13  *  modification, are permitted provided that the following conditions 
14  *  are met:
15  *
16  *    Redistributions of source code must retain the above copyright 
17  *    notice, this list of conditions and the following disclaimer.
18  *
19  *    Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the 
21  *    documentation and/or other materials provided with the   
22  *    distribution.
23  *
24  *    Neither the name of Texas Instruments Incorporated nor the names of
25  *    its contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
29  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
30  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
32  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
33  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
34  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
37  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
38  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  *  \par
41 */
43 /* RM Types */
44 #include <ti/drv/rm/rm_types.h>
46 /* RM internal API includes */
47 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
49 /* RM OSAL layer */
50 #include <rm_osal.h>
52 /* LIBFDT includes */
53 #include <ti/drv/rm/src/libfdt/libfdt.h>
54 #include <ti/drv/rm/src/libfdt/libfdt_env.h>
56 /**********************************************************************
57  ********************Common DTB Parsing Functions**********************
58  **********************************************************************/
60 char rmDtbStartingNode[] = "\0";
61  
62 char *Rm_commonExtractName(const void *dtbDataPtr, int32_t dtbDataLen)
63 {
64     char *resourceName = NULL;
65     
66     resourceName = (char *) Rm_osalMalloc(dtbDataLen);
68     /* The resource name is stored as a null terminated string in the DTB
69      * so it's just a straightforward string copy operation to a local
70      * buffer to extract it. */
71     strcpy(resourceName, (char *)dtbDataPtr);
73     return(resourceName);
74 }
76 /* Free memory that was allocated to extract a name property string */
77 void Rm_commonFreeName(char *resourceName)
78 {
79     int32_t nameSize;
80     
81     /* Free the character array memory */
82     nameSize = strlen(resourceName);
83     /* Add one for the NULL character */
84     Rm_osalFree((void *)resourceName, nameSize+1);
85 }
87 /* Construct and return a list of ranges as specified in either the Resource
88  * DTB or a Policy DTB */
89 Rm_ResourceRange *Rm_commonExtractRange(const void *dtbDataPtr, int32_t dtbDataLen)
90 {
91     uint32_t *dtbRangeData = (uint32_t *)dtbDataPtr;
92     Rm_ResourceRange *startRange = NULL;
93     Rm_ResourceRange *newRange = NULL;
94     Rm_ResourceRange *prevRange = NULL;
95     uint32_t i;
96     
97     /* Ranges are stored in the DTB as a list of 32-bit words.  The number of 32-bit
98      * words in the DTB ranges field should be even since ranges are specified in a 
99      * base, lenth format. The DTB gives properties lengths in bytes so the length
100      * returned from the DTB should be a multiple of the number of bytes in two
101      * uint32_ts. */
102     if (dtbDataLen % (2 * sizeof(uint32_t)))
103     {
104         /* Return NULL if there are an odd number of range values */
105         return (NULL);
106     }
108     /* Extract the range data from the DTB */
109     for (i = 0; i < (dtbDataLen / sizeof(uint32_t)); i+=2)
110     {
111         /* Creat a new range entry */
112         newRange = (Rm_ResourceRange *) Rm_osalMalloc(sizeof(Rm_ResourceRange));
113         /* Populate the new range entry.  The endianness of the value extracted must
114          * be flipped */
115         newRange->base = fdt32_to_cpu(dtbRangeData[i]);
116         newRange->length = fdt32_to_cpu(dtbRangeData[i+1]);
117         newRange->nextRange = NULL;
118         
119         /* Range linked list pointer accounting */
120         if (prevRange == NULL)
121         {
122             /* Save the first entry so it can be returned */
123             startRange = newRange;
124         }
125         else
126         {
127             prevRange->nextRange = (void *) newRange;
128         }
130         prevRange = newRange;
131     }
133     /* Return a pointer to the start of the range list */
134     return (startRange);
137 /* Function to clean up the memory allocated for a linked list of extracted ranges */
138 void Rm_commonFreeRangeList(Rm_ResourceRange *rangeList)
140     Rm_ResourceRange *nextRange;
141     
142     while (rangeList != NULL)
143     {
144         nextRange = rangeList->nextRange;
145         Rm_osalFree((void *)rangeList, sizeof(Rm_ResourceRange));
146         rangeList = nextRange;
147     }
150 /**********************************************************************
151  ***********Resource List DTB Parsing Defines and Functions************
152  **********************************************************************/
154 /* Resource List Properties - These are the property values used
155  * by an application integrator to define the properties of resources
156  * listed in the Device Resource List */
157 char rmResourceDeviceNameProp[] = "device-name";
158 char rmResourceRangeProp[] = "resource-range";
159 char rmResourceLinuxAliasProp[] = "linux-dtb-alias";
160 char rmResourceNsAssignmentProp[] = "ns-assignment";
162 Rm_ResourcePropType Rm_resourceGetPropertyType(const char * propertyName)
164     Rm_ResourcePropType propertyType = Rm_resourcePropType_UNKNOWN;
166     if(strcmp(rmResourceDeviceNameProp, propertyName) == 0)
167     {
168         propertyType = Rm_resourcePropType_DEVICE_NAME;
169     }    
170     else if(strcmp(rmResourceRangeProp, propertyName) == 0)
171     {
172         propertyType = Rm_resourcePropType_RESOURCE_RANGE;
173     }
174     else if(strcmp(rmResourceLinuxAliasProp, propertyName) == 0)
175     {
176         propertyType = Rm_resourcePropType_RESOURCE_LINUX_ALIAS;
177     }    
178     else if(strcmp(rmResourceNsAssignmentProp, propertyName) == 0)
179     {
180         propertyType = Rm_resourcePropType_NSASSIGNMENT;
181     }
183     return (propertyType);
186 char *Rm_resourceExtractDeviceName(const void *dtbDataPtr, int32_t dtbDataLen)
188     return(Rm_commonExtractName(dtbDataPtr, dtbDataLen));
191 void Rm_resourceFreeDeviceName(char *deviceName)
193     Rm_commonFreeName(deviceName);
196 Rm_ResourceRange *Rm_resourceExtractRange(const void *dtbDataPtr, int32_t dtbDataLen)
198     return(Rm_commonExtractRange(dtbDataPtr, dtbDataLen));
201 void Rm_resourceFreeRange(Rm_ResourceRange *rangeList)
203     Rm_commonFreeRangeList(rangeList);
206 Rm_LinuxAlias *Rm_resourceExtractLinuxAlias(const void *dtbDataPtr, int32_t dtbDataLen)
208     uint8_t *dtbAliasData = (uint8_t *)dtbDataPtr;
209     uint32_t pathLenBytes;
210     uint32_t extractedValue;
211     uint8_t *extractedValueBytePtr;        
212     Rm_LinuxAlias *startAlias = NULL;
213     Rm_LinuxAlias *newAlias = NULL;
214     Rm_LinuxAlias *prevAlias = NULL;
215     uint32_t numOffsets;
216     int32_t i = 0;
217     uint16_t j;
218     
219     /* Linux aliases are stored in the DTB as a list space-separated path node names within
220      * null terminated string.  Following the path string 
221      * will be two or three values specifying the fields in the linux DTB property
222      * that contain the relevant data.  The first value specifies the number of offsets
223      * that follow.  If two field offsets are specified the 
224      * Linux DTB contains a base + length. If   one field offset is specified the 
225      * Linux DTB contains a single value for reservation.  There is no padding between
226      * the path string and the 32-bit offsets.  Therefore the 32-bit offsets may not be on
227      * a 4-byte boundary and must be constructed upon extraction */
229     /* Extract the alias data from the DTB */
230     while(i < dtbDataLen)
231     {
232         /* Creat a new alias entry */
233         newAlias = (Rm_LinuxAlias *) Rm_osalMalloc(sizeof(Rm_LinuxAlias));
234         
235         /* Populate the new alias entry.  Allocate a buffer for the path
236          * string (adding one for the null character). */
237         pathLenBytes = strlen((char *) &dtbAliasData[i]) + 1;
238         newAlias->path = (char *) Rm_osalMalloc(pathLenBytes);
239         strcpy(newAlias->path, ((char *) &dtbAliasData[i]));
240         
241         /* Extract the 32-bit value specifying the number of offsets that follow */
242         i += pathLenBytes;
243         extractedValueBytePtr = (uint8_t *)&extractedValue;
244         for (j = 0; j < sizeof(uint32_t); j++, i++)
245         {
246             extractedValueBytePtr[j] = dtbAliasData[i];
247         }
248         /* flip the endianness */
249         numOffsets = fdt32_to_cpu(extractedValue);
251         /* numOffsets should always be either 1 or 2 */
252         if ((numOffsets == 1) || (numOffsets == 2))
253         {
254             /* Always extract the base value */
255             extractedValueBytePtr = (uint8_t *)&extractedValue;
256             for (j = 0; j < sizeof(uint32_t); j++, i++)
257             {
258                 extractedValueBytePtr[j] = dtbAliasData[i];
259             }            
260             newAlias->baseOffset = fdt32_to_cpu(extractedValue);
262             if (numOffsets == 2)
263             {
264                 /* Extract the 32-bit length value if two offsets were specified */
265                 for (j = 0; j < sizeof(uint32_t); j++, i++)
266                 {
267                     extractedValueBytePtr[j] = dtbAliasData[i];
268                 }
269                 /* flip the endianness */
270                 newAlias->lengthOffset = fdt32_to_cpu(extractedValue);
271             }
272             else
273             {
274                 newAlias->lengthOffset = RM_DTB_LINUX_ALIAS_OFFSET_NOT_SET;
275             }            
276             
277             newAlias->nextLinuxAlias = NULL;
278             
279             if (prevAlias == NULL)
280             {
281                 /* Save the first entry so it can be returned */
282                 startAlias = newAlias;
283             }
284             else
285             {
286                 prevAlias->nextLinuxAlias = (void *) newAlias;
287             }
288             prevAlias = newAlias;
289         }
290         else
291         {
292             /* Return NULL */
293             startAlias = NULL;
294             break;
295         }
296     }
298     /* Return a pointer to the start of the NameServer assignment list */
299     return (startAlias);
302 /* Function to clean up the memory allocated for a linked list of extracted Linux
303  * aliases. */
304 void Rm_resourceFreeLinuxAlias(Rm_LinuxAlias *aliasList)
306     Rm_LinuxAlias *nextAlias;
307     int32_t pathSize;
308        
309     while (aliasList != NULL)
310     {
311         nextAlias = aliasList->nextLinuxAlias;
312         /* Free the path string memory first */
313         pathSize = strlen(aliasList->path);        
314         Rm_osalFree((void *)aliasList->path, pathSize + 1);
315         /* Free the list element */
316         Rm_osalFree((void *)aliasList, sizeof(Rm_LinuxAlias));
317         aliasList = nextAlias;
318     }
321 /* Construct and return a list of NameServer assignments as specified in the Resource DTB */
322 Rm_NsAssignment *Rm_resourceExtractNsAssignment(const void *dtbDataPtr, int32_t dtbDataLen)
324     uint8_t *dtbNsAssignmentData = (uint8_t *)dtbDataPtr;
325     uint32_t nameLenBytes;
326     uint32_t extractedValue;
327     uint8_t *extractedValueBytePtr;        
328     Rm_NsAssignment *startAssignment = NULL;
329     Rm_NsAssignment *newAssignment = NULL;
330     Rm_NsAssignment *prevAssignment = NULL;
331     int8_t i = 0;
332     uint16_t j;
333     
334     /* NameServer assignments are stored in the DTB as a null-terminated character
335      * string followed by a 32-bit word containing the value to be assigned to the
336      * name in the string.  There is no padding between the string and the 32-bit 
337      * word.  Therefore the 32-bit word may not be on a 4-byte boundary and must
338      * be constructed upon extraction */
340     /* Extract the NameServer assignment data from the DTB */
341     while(i < dtbDataLen)
342     {
343         /* Creat a new NameServer assignment entry */
344         newAssignment = (Rm_NsAssignment *) Rm_osalMalloc(sizeof(Rm_NsAssignment));
345         
346         /* Populate the new assignment entry.  Allocate a buffer for the assignment
347          * name string (adding one for the null character). */
348         nameLenBytes = strlen((char *) &dtbNsAssignmentData[i]) + 1;
349         newAssignment->nsName = (char *) Rm_osalMalloc(nameLenBytes);
350         strcpy(newAssignment->nsName, ((char *) &dtbNsAssignmentData[i]));
351         
352         /* Extract the 32-bit base value */
353         i += nameLenBytes;
354         extractedValueBytePtr = (uint8_t *)&extractedValue;
355         for (j = 0; j < sizeof(uint32_t); j++, i++)
356         {
357             extractedValueBytePtr[j] = dtbNsAssignmentData[i];
358         }
359         /* flip the endianness */
360         newAssignment->resourceBase = fdt32_to_cpu(extractedValue);
362         /* Extract the 32-bit length value */
363         for (j = 0; j < sizeof(uint32_t); j++, i++)
364         {
365             extractedValueBytePtr[j] = dtbNsAssignmentData[i];
366         }
367         /* flip the endianness */
368         newAssignment->resourceLength = fdt32_to_cpu(extractedValue);
370         newAssignment->nextNsAssignment = NULL;
372         if (prevAssignment == NULL)
373         {
374             /* Save the first entry so it can be returned */
375             startAssignment = newAssignment;
376         }
377         else
378         {
379             prevAssignment->nextNsAssignment = (void *) newAssignment;
380         }
381         prevAssignment = newAssignment;
382     }
384     /* Return a pointer to the start of the NameServer assignment list */
385     return (startAssignment);
388 /* Function to clean up the memory allocated for a linked list of extracted NameServer
389  * assignments. */
390 void Rm_resourceFreeNsAssignmentList (Rm_NsAssignment *nsAssignmentList)
392     Rm_NsAssignment *nextAssignment;
393     int32_t nameSize;
394     
395     while (nsAssignmentList != NULL)
396     {
397         nextAssignment = nsAssignmentList->nextNsAssignment;
398         /* Free the character array memory first */
399         nameSize = strlen(nsAssignmentList->nsName);
400         /* Add one for the NULL character */
401         Rm_osalFree((void *)nsAssignmentList->nsName, nameSize+1);
402         /* Free the list element */
403         Rm_osalFree((void *)nsAssignmentList, sizeof(Rm_NsAssignment));
404         nsAssignmentList = nextAssignment;
405     }
408 /**********************************************************************
409  ***************Policy DTB Parsing Defines and Functions***************
410  **********************************************************************/
412 /* Policy Properties - These are the property values used
413  * by an application integrator to define the properties of resources
414  * listed in a Resource Manager Policy */
415 char rmPolicyPolicyTypeProp[] = "policy-type";
416 char rmPolicyAssignedRangesProp[] = "assigned-ranges";
417 char rmPolicyAllocationSizesProp[] = "allocation-sizes";
418 char rmPolicyAssignedNsNamesProp[] = "assigned-ns-names";
420 Rm_PolicyPropType Rm_policyGetPropertyType(const char * propertyName)
422     Rm_PolicyPropType propertyType = Rm_policyPropType_UNKNOWN;
424     if(strcmp(rmPolicyPolicyTypeProp, propertyName) == 0)
425     {
426         propertyType = Rm_policyPropType_POLICY_TYPE;
427     } 
428     else if(strcmp(rmPolicyAssignedRangesProp, propertyName) == 0)
429     {
430         propertyType = Rm_policyPropType_RESOURCE_ASSIGNED_RANGES;
431     }
432     else if(strcmp(rmPolicyAllocationSizesProp, propertyName) == 0)
433     {
434         propertyType = Rm_policyPropType_RESOURCE_ALLOCATION_SIZES;
435     }
436     else if(strcmp(rmPolicyAssignedNsNamesProp, propertyName) == 0)
437     {
438         propertyType = Rm_policyPropType_ASSIGNED_NS_NAMES;
439     }
441     return (propertyType);
444 /* MODIFY TO RETURN A POLICY TYPE INSTEAD OF A STRING??? */
445 char *Rm_policyExtractPolicyType(const void *dtbDataPtr, int32_t dtbDataLen)
447     return(Rm_commonExtractName(dtbDataPtr, dtbDataLen));
450 void Rm_policyFreePolicyType(char *policyType)
452     Rm_commonFreeName(policyType);
455 Rm_ResourceRange *Rm_policyExtractAssignedRanges(const void *dtbDataPtr, int32_t dtbDataLen)
457     return(Rm_commonExtractRange(dtbDataPtr, dtbDataLen));
460 void Rm_policyFreeAssignedRanges(Rm_ResourceRange *rangeList)
462     Rm_commonFreeRangeList(rangeList);
465 /* Construct and return a list of allocation sizes as specified in the Policy DTB */
466 Rm_AllocationSize *Rm_policyExtractAllocationSizes(const void *dtbDataPtr, int32_t dtbDataLen)
468     uint32_t *dtbRangeData = (uint32_t *)dtbDataPtr;
469     Rm_AllocationSize *startAllocationSize = NULL;
470     Rm_AllocationSize *newAllocationSize = NULL;
471     Rm_AllocationSize *prevAllocationSize = NULL;
472     uint32_t i;
473     
474     /* Allocation sizes are stored in the DTB as a list of 32-bit words. The DTB 
475      * gives properties lengths in bytes so the length returned from the DTB 
476      * should be a multiple of the number of bytes a uint32_t. */
477     if (dtbDataLen % sizeof(uint32_t))
478     {
479         return (NULL);
480     }
482     /* Extract the allocation size data from the DTB */
483     for (i = 0; i < (dtbDataLen / sizeof(uint32_t)); i++)
484     {
485         /* Creat a new allocation size entry */
486         newAllocationSize = (Rm_AllocationSize *) Rm_osalMalloc(sizeof(Rm_AllocationSize));
487         /* Populate the new allocation size entry.  The endianness of the value extracted must
488          * be flipped */
489         newAllocationSize->allocationSize = fdt32_to_cpu(dtbRangeData[i]);
490         newAllocationSize->nextAllocationSize = NULL;
491         
492         /* Allocation size linked list pointer accounting */
493         if (prevAllocationSize == NULL)
494         {
495             /* Save the first entry so it can be returned */
496             startAllocationSize = newAllocationSize;
497         }
498         else
499         {
500             prevAllocationSize->nextAllocationSize = (void *) newAllocationSize;
501         }
503         prevAllocationSize = newAllocationSize;
504     }
506     /* Return a pointer to the start of the allocation size list */
507     return (startAllocationSize);
510 /* Function to clean up the memory allocated for a linked list of extracted allocation sizes */
511 void Rm_policyFreeAllocationSizesList (Rm_AllocationSize *allocationSizeList)
513     Rm_AllocationSize *nextAllocationSize;
514     
515     while (allocationSizeList != NULL)
516     {
517         nextAllocationSize = allocationSizeList->nextAllocationSize;
518         Rm_osalFree((void *)allocationSizeList, sizeof(Rm_AllocationSize));
519         allocationSizeList = nextAllocationSize;
520     }
523 /* Construct and return a list of assigned NameServer names as specified in the Policy DTB */
524 Rm_AssignedNsNames *Rm_policyExtractAssignedNsNames(const void *dtbDataPtr, int32_t dtbDataLen)
526     uint8_t *dtbAssignedNsNamesData = (uint8_t *)dtbDataPtr;
527     uint32_t nameLenBytes;        
528     Rm_AssignedNsNames *startAssignedName = NULL;
529     Rm_AssignedNsNames *newAssignedName = NULL;
530     Rm_AssignedNsNames *prevAssignedName = NULL;
531     int8_t i = 0;
532     
533     /* Assigned NameServer names are stored in the DTB as a block of null-terminated 
534      * character strings.  There is no padding between the strings. */
536     /* Extract the assigned NameServer name data from the DTB */
537     while(i < dtbDataLen)
538     {
539         /* Creat a new assigned NameServer name entry */
540         newAssignedName = (Rm_AssignedNsNames *) Rm_osalMalloc(sizeof(Rm_AssignedNsNames));
541         
542         /* Populate the new assigned name entry.  Allocate a buffer for the assigned
543          * name string (adding one for the null character). */
544         nameLenBytes = strlen((char *) &dtbAssignedNsNamesData[i]) + 1;
545         newAssignedName->assignedName = (char *) Rm_osalMalloc(nameLenBytes);
546         strcpy(newAssignedName->assignedName, ((char *) &dtbAssignedNsNamesData[i]));
548         newAssignedName->nextAssignedName = NULL;
550         if (prevAssignedName == NULL)
551         {
552             /* Save the first entry so it can be returned */
553             startAssignedName = newAssignedName;
554         }
555         else
556         {
557             prevAssignedName->nextAssignedName = (void *) newAssignedName;
558         }
559         prevAssignedName = newAssignedName;
560     }
562     /* Return a pointer to the start of the assigned NameServer names list */
563     return (startAssignedName);
566 /* Function to clean up the memory allocated for a linked list of extracted 
567  * assigned NameServer names. */
568 void Rm_policyFreeAssignmentNsNamesList (Rm_AssignedNsNames *assignedNsNamesList)
570     Rm_AssignedNsNames *nextAssignedName;
571     int32_t nameSize;
572     
573     while (assignedNsNamesList != NULL)
574     {
575         nextAssignedName = assignedNsNamesList->nextAssignedName;
576         /* Free the character array memory first */
577         nameSize = strlen(assignedNsNamesList->assignedName);
578         /* Add one for the NULL character */
579         Rm_osalFree((void *)assignedNsNamesList->assignedName, nameSize+1);
580         /* Free the list element */
581         Rm_osalFree((void *)assignedNsNamesList, sizeof(Rm_AssignedNsNames));
582         assignedNsNamesList = nextAssignedName;
583     }
586 /**********************************************************************
587  ****************Linux DTB Parsing Defines and Functions***************
588  **********************************************************************/
590 Rm_LinuxValueRange *Rm_linuxExtractValues(const void *dtbDataPtr, int32_t dtbDataLen)
592     uint32_t *dtbValueData = (uint32_t *)dtbDataPtr;
593     Rm_LinuxValueRange *startValue = NULL;
594     Rm_LinuxValueRange *newValue = NULL;
595     Rm_LinuxValueRange *prevValue = NULL;
596     uint32_t i;
597     
598     /* Values are stored in the Linux DTB as a list of 32-bit words.  The number of 32-bit
599      * words in the value field can differ.  depending on the number of values specified. */
601     /* Extract the value data from the Linux DTB */
602     for (i = 0; i < (dtbDataLen / sizeof(uint32_t)); i++)
603     {
604         /* Creat a new value entry */
605         newValue = (Rm_LinuxValueRange *) Rm_osalMalloc(sizeof(Rm_LinuxValueRange));
606         /* Populate the new value entry.  The endianness of the value extracted must
607          * be flipped */
608         newValue->value = fdt32_to_cpu(dtbValueData[i]);
609         newValue->nextValue = NULL;
610         
611         /* Value linked list pointer accounting */
612         if (prevValue == NULL)
613         {
614             /* Save the first entry so it can be returned */
615             startValue = newValue;
616         }
617         else
618         {
619             prevValue->nextValue = (void *) newValue;
620         }
622         prevValue = newValue;
623     }
625     /* Return a pointer to the start of the value list */
626     return (startValue);
629 void Rm_linuxFreeValues(Rm_LinuxValueRange *valueList)
631     Rm_LinuxValueRange *nextValue;
632     
633     while (valueList != NULL)
634     {
635         nextValue = valueList->nextValue;
636         Rm_osalFree((void *)valueList, sizeof(Rm_LinuxValueRange));
637         valueList = nextValue;
638     }
641 /**
642 @}
643 */