2 * @brief Memory management for host mode
\r
5 * Copyright(C) NXP Semiconductors, 2012
\r
6 * All rights reserved.
\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
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
32 #define __INCLUDE_FROM_USB_DRIVER
\r
33 #include "USBMode.h"
\r
35 #ifdef USB_CAN_BE_HOST
\r
37 #include "../../../Common/Common.h"
\r
38 #include "USBTask.h"
\r
39 #include "HAL/HAL.h"
\r
40 #include "USBMemory.h"
\r
42 /************************************************************************/
\r
43 /* LOCAL SYMBOL DECLARATIION */
\r
44 /************************************************************************/
\r
45 #define TEST_NEW_ALLOC 0
\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
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
71 /************************************************************************/
\r
73 /************************************************************************/
\r
74 #define ALIGN_FOUR_BYTES (4) // FIXME only m3 is 1 byte alignment
\r
76 /* FIXME the following dynamic allocation is temporarly */
\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
84 static uint8_t USB_Mem_Buffer[USBRAM_BUFFER_SIZE] ATTR_ALIGNED(4) __BSS(USBRAM_SECTION);
\r
86 void USB_Memory_Init(uint32_t Memory_Pool_Size)
\r
88 PMemBlockInfo head = (PMemBlockInfo) USB_Mem_Buffer;
\r
91 head->size = (Memory_Pool_Size & 0xfffffffc) - HEADER_SIZE ;// align memory size
\r
93 head->type = MEM_FREE;
\r
99 uint8_t* USB_Memory_Alloc(uint32_t size, uint32_t num_aligned_bytes)
\r
101 PMemBlockInfo freeBlock=NULL, newBlock, blk_ptr = NULL;
\r
102 PMemBlockInfo head = (PMemBlockInfo) USB_Mem_Buffer;
\r
105 for (blk_ptr = head; blk_ptr != NULL; blk_ptr = NEXT_BLOCK(blk_ptr)) // 1st-fit technique
\r
107 if (((blk_ptr->type == MEM_FREE)||(blk_ptr->type == MEM_PAD)) && (blk_ptr->size >= size))
\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
113 blk_ptr->type = MEM_USED;
\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
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
126 /* Filter by requested alignment*/
\r
127 if(num_aligned_bytes > 0)
\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
134 uint32_t padBlkSize;
\r
136 if((num_aligned_bytes - pad_size) >= HEADER_SIZE)
\r
137 padBlkSize = num_aligned_bytes - pad_size - HEADER_SIZE;
\r
139 padBlkSize = 2*num_aligned_bytes - pad_size - HEADER_SIZE;
\r
141 if(padBlkSize > freeBlock->size) //not enough space to create new pad
\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
147 else //there is space for new pad
\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
154 blk_ptr->size = padBlkSize;
\r
155 blk_ptr->next = LINK_TO_THIS_BLOCK(newBlock);
\r
156 blk_ptr->type = MEM_PAD;
\r
160 else if(blk_ptr->type == MEM_USED) break;
\r
164 if (blk_ptr == NULL) {
\r
165 return ((uint8_t *) NULL);
\r
168 return (((uint8_t *) blk_ptr) + HEADER_SIZE);
\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
176 for (freeBlock = head; freeBlock != NULL; freeBlock = NEXT_BLOCK(freeBlock)) // 1st-fit technique
\r
178 if ((freeBlock->isFree == 1) && (freeBlock->size >= size))
\r
180 blk_ptr = freeBlock;
\r
185 if (blk_ptr == NULL) {
\r
186 return ((uint8_t *) NULL);
\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
191 newBlock = blk_ptr;
\r
192 //newBlock->size = blk_ptr->size;
\r
193 //newBlock->next = blk_ptr->next;
\r
194 newBlock->isFree = 0;
\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
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
209 return (((uint8_t *) newBlock) + HEADER_SIZE);
\r
213 void USB_Memory_Free(uint8_t *ptr)
\r
215 PMemBlockInfo prev;
\r
216 PMemBlockInfo head = (PMemBlockInfo) USB_Mem_Buffer;
\r
217 PMemBlockInfo blk_ptr;
\r
224 blk_ptr = (PMemBlockInfo) HEADER_POINTER(ptr);
\r
228 bool being_pad = false;
\r
229 if (blk_ptr->next != 0) // merge with next free block
\r
231 if ((NEXT_BLOCK(blk_ptr)->type == MEM_FREE)||(NEXT_BLOCK(blk_ptr)->type == MEM_PAD))
\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
237 else being_pad = true;
\r
240 for (prev = head; prev != NULL; prev = NEXT_BLOCK(prev)) // merge with previous free block
\r
242 if (NEXT_BLOCK(prev) == blk_ptr)
\r
244 if ((prev->type == MEM_FREE)||(prev->type == MEM_PAD))
\r
246 prev->size = prev->size + blk_ptr->size + HEADER_SIZE;
\r
247 prev->next = blk_ptr->next;
\r
249 else if(being_pad == true) // prev&next blocks are used
\r
250 blk_ptr->type = MEM_PAD;
\r
257 if (blk_ptr->next != 0) // merge with next free block
\r
259 if (NEXT_BLOCK(blk_ptr)->isFree == 1)
\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
266 for (prev = head; prev != NULL; prev = NEXT_BLOCK(prev)) // merge with previous free block
\r
268 if (NEXT_BLOCK(prev) == blk_ptr)
\r
270 if (prev->isFree == 1)
\r
272 prev->size = prev->size + blk_ptr->size + HEADER_SIZE;
\r
273 prev->next = blk_ptr->next;
\r
280 blk_ptr->isFree = 1;
\r