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