]> git.sur5r.net Git - freertos/blob
a68e4b7358132f13db329d99f4626a9f54b0d7ea
[freertos] /
1 /*\r
2  * @brief Memory management for host mode\r
3  *\r
4  * @note\r
5  * Copyright(C) NXP Semiconductors, 2012\r
6   * All rights reserved.\r
7  *\r
8  * @par\r
9  * Software that is described herein is for illustrative purposes only\r
10  * which provides customers with programming information regarding the\r
11  * LPC products.  This software is supplied "AS IS" without any warranties of\r
12  * any kind, and NXP Semiconductors and its licensor disclaim any and\r
13  * all warranties, express or implied, including all implied warranties of\r
14  * merchantability, fitness for a particular purpose and non-infringement of\r
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility\r
16  * or liability for the use of the software, conveys no license or rights under any\r
17  * patent, copyright, mask work right, or any other intellectual property rights in\r
18  * or to any products. NXP Semiconductors reserves the right to make changes\r
19  * in the software without notification. NXP Semiconductors also makes no\r
20  * representation or warranty that such application will be suitable for the\r
21  * specified use without further testing or modification.\r
22  *\r
23  * @par\r
24  * Permission to use, copy, modify, and distribute this software and its\r
25  * documentation is hereby granted, under NXP Semiconductors' and its\r
26  * licensor's relevant copyrights in the software, without fee, provided that it\r
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This\r
28  * copyright, permission, and disclaimer notice must appear in all copies of\r
29  * this code.\r
30  */\r
31 \r
32 #define  __INCLUDE_FROM_USB_DRIVER\r
33 #include "USBMode.h"\r
34 \r
35 #ifdef USB_CAN_BE_HOST\r
36 \r
37 #include "../../../Common/Common.h"\r
38 #include "USBTask.h"\r
39 #include "HAL/HAL.h"\r
40 #include "USBMemory.h"\r
41 \r
42 /************************************************************************/\r
43 /* LOCAL SYMBOL DECLARATIION                                            */\r
44 /************************************************************************/\r
45 #define TEST_NEW_ALLOC  0\r
46 \r
47 #if TEST_NEW_ALLOC\r
48 \r
49 typedef struct MemBlockInfo_t {\r
50         uint32_t size :15; // memory size of this block\r
51         uint32_t type :2;  // indicate whether this memory block is free, pad or used\r
52         uint32_t next :15; // offset (from head address) to the next block\r
53 } sMemBlockInfo, *PMemBlockInfo;\r
54 \r
55 typedef enum\r
56 {\r
57         MEM_FREE = 0,\r
58         MEM_PAD,\r
59         MEM_USED,\r
60 }enMemBlockType;\r
61 \r
62 #else\r
63 \r
64 typedef struct MemBlockInfo_t {\r
65         uint32_t size :15; // memory size of this block\r
66         uint32_t isFree :1; // indicate whether this memory block is free or used\r
67         uint32_t next :16; // offset (from head address) to the next block\r
68 } sMemBlockInfo, *PMemBlockInfo;\r
69 \r
70 #endif\r
71 /************************************************************************/\r
72 /* LOCAL DEFINE                                                         */\r
73 /************************************************************************/\r
74 #define ALIGN_FOUR_BYTES    (4) // FIXME only m3 is 1 byte alignment\r
75 \r
76 /* FIXME the following dynamic allocation is temporarly */\r
77 \r
78 #define  HEADER_SIZE                (sizeof(sMemBlockInfo))\r
79 #define  HEADER_POINTER(x)          ((uint8_t *)x - sizeof(sMemBlockInfo))\r
80 #define  NEXT_BLOCK(x)                  ((PMemBlockInfo) ( ((x)->next==0) ? 0 : ((uint32_t)head +(x)->next) ))\r
81 #define  LINK_TO_THIS_BLOCK(x)      (((uint32_t)(x))-((uint32_t)head))\r
82 \r
83 PRAGMA_ALIGN_4\r
84 static uint8_t USB_Mem_Buffer[USBRAM_BUFFER_SIZE] ATTR_ALIGNED(4) __BSS(USBRAM_SECTION);\r
85 \r
86 void USB_Memory_Init(uint32_t Memory_Pool_Size)\r
87 {\r
88         PMemBlockInfo head = (PMemBlockInfo) USB_Mem_Buffer;\r
89 \r
90         head->next = 0;\r
91         head->size = (Memory_Pool_Size & 0xfffffffc) - HEADER_SIZE ;// align memory size\r
92 #if TEST_NEW_ALLOC\r
93         head->type = MEM_FREE;\r
94 #else\r
95         head->isFree = 1;\r
96 #endif\r
97 }\r
98 \r
99 uint8_t* USB_Memory_Alloc(uint32_t size, uint32_t num_aligned_bytes)\r
100 {\r
101         PMemBlockInfo freeBlock=NULL, newBlock, blk_ptr = NULL;\r
102         PMemBlockInfo head = (PMemBlockInfo) USB_Mem_Buffer;\r
103 \r
104 #if TEST_NEW_ALLOC\r
105         for (blk_ptr = head; blk_ptr != NULL; blk_ptr = NEXT_BLOCK(blk_ptr)) // 1st-fit technique\r
106         {\r
107                 if (((blk_ptr->type == MEM_FREE)||(blk_ptr->type == MEM_PAD)) && (blk_ptr->size >= size))\r
108                 {\r
109                         /* Filter by requested size */\r
110                         if (blk_ptr->size <= HEADER_SIZE + size) // where (blk_size=size | blk_size=size+HEAD) then allocate whole block & do not create freeBlock\r
111                         {\r
112                                 blk_ptr->next = 0;\r
113                                 blk_ptr->type = MEM_USED;\r
114                         } else {\r
115                                 /* Locate empty block at end of found block */\r
116                                 freeBlock = (PMemBlockInfo) (((uint32_t) blk_ptr) + size + HEADER_SIZE);\r
117                                 freeBlock->next = blk_ptr->next;\r
118                                 freeBlock->size = blk_ptr->size - (HEADER_SIZE + size);\r
119                                 freeBlock->type = blk_ptr->type;\r
120 \r
121                                 /* Locate new block at start of found block */\r
122                                 blk_ptr->size = size;\r
123                                 blk_ptr->next = LINK_TO_THIS_BLOCK(freeBlock);\r
124                                 blk_ptr->type = MEM_USED;\r
125                         }\r
126                         /* Filter by requested alignment*/\r
127                         if(num_aligned_bytes > 0)\r
128                         {\r
129                                 uint32_t pad_size = (((uint32_t)blk_ptr) + HEADER_SIZE) % num_aligned_bytes;\r
130                                 if(pad_size == 0) break;                                                        //block found\r
131                                 else                                                                                            //not fit alignment\r
132                                         if(blk_ptr->next != 0)                                                  //break if this is the last block in chain\r
133                                         {\r
134                                                 uint32_t padBlkSize;\r
135 \r
136                                                 if((num_aligned_bytes - pad_size) >= HEADER_SIZE)\r
137                                                         padBlkSize = num_aligned_bytes - pad_size - HEADER_SIZE;\r
138                                                 else\r
139                                                         padBlkSize = 2*num_aligned_bytes - pad_size - HEADER_SIZE;\r
140 \r
141                                                 if(padBlkSize > freeBlock->size)                        //not enough space to create new pad\r
142                                                 {\r
143                                                         blk_ptr->next = freeBlock->next;\r
144                                                         blk_ptr->size = freeBlock->size + HEADER_SIZE + size;\r
145                                                         blk_ptr->type = MEM_PAD;\r
146                                                 }\r
147                                                 else                                                                            //there is space for new pad\r
148                                                 {\r
149                                                         newBlock = (PMemBlockInfo) (((uint32_t) blk_ptr) + HEADER_SIZE + padBlkSize);\r
150                                                         newBlock->next = freeBlock->next;\r
151                                                         newBlock->type = freeBlock->type;\r
152                                                         newBlock->size = freeBlock->size + HEADER_SIZE + size - padBlkSize;\r
153 \r
154                                                         blk_ptr->size = padBlkSize;\r
155                                                         blk_ptr->next = LINK_TO_THIS_BLOCK(newBlock);\r
156                                                         blk_ptr->type = MEM_PAD;\r
157                                                 }\r
158                                         }\r
159                         }\r
160                         else if(blk_ptr->type == MEM_USED)      break;\r
161                 }\r
162         }\r
163 \r
164         if (blk_ptr == NULL) {\r
165                 return ((uint8_t *) NULL);\r
166         }\r
167 \r
168         return (((uint8_t *) blk_ptr) + HEADER_SIZE);           \r
169 \r
170 #else\r
171         /* Align the requested size by 4 bytes */\r
172         if ((size % ALIGN_FOUR_BYTES) != 0) {\r
173                 size = (((size >> 2) << 2) + ALIGN_FOUR_BYTES);\r
174         }\r
175 \r
176         for (freeBlock = head; freeBlock != NULL; freeBlock = NEXT_BLOCK(freeBlock)) // 1st-fit technique\r
177         {\r
178                 if ((freeBlock->isFree == 1) && (freeBlock->size >= size))\r
179                 {\r
180                         blk_ptr = freeBlock;\r
181                         break;\r
182                 }\r
183         }\r
184 \r
185         if (blk_ptr == NULL) {\r
186                 return ((uint8_t *) NULL);\r
187         }\r
188 \r
189         if (blk_ptr->size <= HEADER_SIZE + size) // where (blk_size=size | blk_size=size+HEAD) then allocate whole block & do not create freeBlock\r
190         {\r
191                 newBlock = blk_ptr;\r
192                 //newBlock->size    = blk_ptr->size;\r
193                 //newBlock->next    = blk_ptr->next;\r
194                 newBlock->isFree = 0;\r
195         } else {\r
196                 /* Locate empty block at end of found block */\r
197                 freeBlock = (PMemBlockInfo) (((uint8_t *) blk_ptr) + size + HEADER_SIZE);\r
198                 freeBlock->next = blk_ptr->next;\r
199                 freeBlock->size = blk_ptr->size - (HEADER_SIZE + size);\r
200                 freeBlock->isFree = 1;\r
201 \r
202                 /* Locate new block at start of found block */\r
203                 newBlock = blk_ptr;\r
204                 newBlock->size = size;\r
205                 newBlock->next = LINK_TO_THIS_BLOCK(freeBlock);\r
206                 newBlock->isFree = 0;\r
207         }\r
208 \r
209         return (((uint8_t *) newBlock) + HEADER_SIZE);\r
210 #endif\r
211 }\r
212 \r
213 void USB_Memory_Free(uint8_t *ptr)\r
214 {\r
215         PMemBlockInfo prev;\r
216         PMemBlockInfo head = (PMemBlockInfo) USB_Mem_Buffer;\r
217         PMemBlockInfo blk_ptr;\r
218 \r
219         if (ptr == NULL)\r
220         {\r
221                 return;\r
222         }\r
223 \r
224         blk_ptr = (PMemBlockInfo) HEADER_POINTER(ptr);\r
225         \r
226 #if TEST_NEW_ALLOC\r
227         \r
228         bool being_pad = false;\r
229         if (blk_ptr->next != 0) // merge with next free block\r
230         {\r
231                 if ((NEXT_BLOCK(blk_ptr)->type == MEM_FREE)||(NEXT_BLOCK(blk_ptr)->type == MEM_PAD))\r
232                 {\r
233                         blk_ptr->size = blk_ptr->size + NEXT_BLOCK(blk_ptr)->size + HEADER_SIZE;\r
234                         blk_ptr->next = NEXT_BLOCK(blk_ptr)->next;\r
235                         blk_ptr->type = NEXT_BLOCK(blk_ptr)->type;\r
236                 }\r
237                 else being_pad = true;\r
238         }\r
239 \r
240         for (prev = head; prev != NULL; prev = NEXT_BLOCK(prev)) // merge with previous free block\r
241         {\r
242                 if (NEXT_BLOCK(prev) == blk_ptr)\r
243                 {\r
244                         if ((prev->type == MEM_FREE)||(prev->type == MEM_PAD))\r
245                         {\r
246                                 prev->size = prev->size + blk_ptr->size + HEADER_SIZE;\r
247                                 prev->next = blk_ptr->next;\r
248                         }\r
249                         else if(being_pad == true)                                               // prev&next blocks are used\r
250                                 blk_ptr->type = MEM_PAD;\r
251 \r
252                         break;\r
253                 }\r
254         }       \r
255 \r
256 #else\r
257         if (blk_ptr->next != 0) // merge with next free block\r
258         {\r
259                 if (NEXT_BLOCK(blk_ptr)->isFree == 1)\r
260                 {\r
261                         blk_ptr->size = blk_ptr->size + NEXT_BLOCK(blk_ptr)->size + HEADER_SIZE;\r
262                         blk_ptr->next = NEXT_BLOCK(blk_ptr)->next;\r
263                 }\r
264         }\r
265 \r
266         for (prev = head; prev != NULL; prev = NEXT_BLOCK(prev)) // merge with previous free block\r
267         {\r
268                 if (NEXT_BLOCK(prev) == blk_ptr)\r
269                 {\r
270                         if (prev->isFree == 1)\r
271                         {\r
272                                 prev->size = prev->size + blk_ptr->size + HEADER_SIZE;\r
273                                 prev->next = blk_ptr->next;\r
274                                 blk_ptr = prev;\r
275                         }\r
276                         break;\r
277                 }\r
278         }\r
279 \r
280         blk_ptr->isFree = 1;\r
281 \r
282 #endif\r
283         return;\r
284 }\r
285 \r
286 #endif\r