/**************************************************************************//** * @file support.c * @version V1.10 * $Revision: 11 $ * $Date: 14/10/03 1:54p $ * @brief Functions to support USB host driver. * * @note * SPDX-License-Identifier: Apache-2.0 * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #include #include #include #include "usb.h" /// @cond HIDDEN_SYMBOLS #define USB_MEMORY_POOL_SIZE (32*1024) #define USB_MEM_BLOCK_SIZE 128 #define BOUNDARY_WORD 4 static uint32_t _FreeMemorySize; uint32_t _AllocatedMemorySize; #define USB_MEM_ALLOC_MAGIC 0x19685788 /* magic number in leading block */ typedef struct USB_mhdr { uint32_t flag; /* 0:free, 1:allocated, 0x3:first block */ uint32_t bcnt; /* if allocated, the block count of allocated memory block */ uint32_t magic; uint32_t reserved; } USB_MHDR_T; uint8_t _USBMemoryPool[USB_MEMORY_POOL_SIZE] __attribute__((aligned(USB_MEM_BLOCK_SIZE))); static USB_MHDR_T *_pCurrent; uint32_t *_USB_pCurrent = (uint32_t *) &_pCurrent; static uint32_t _MemoryPoolBase, _MemoryPoolEnd; void USB_InitializeMemoryPool() { _MemoryPoolBase = (UINT32)&_USBMemoryPool[0] | NON_CACHE_MASK; _MemoryPoolEnd = _MemoryPoolBase + USB_MEMORY_POOL_SIZE; _FreeMemorySize = _MemoryPoolEnd - _MemoryPoolBase; _AllocatedMemorySize = 0; _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; memset((char *)_MemoryPoolBase, 0, _FreeMemorySize); } int USB_available_memory() { return _FreeMemorySize; } int USB_allocated_memory() { return _AllocatedMemorySize; } void *USB_malloc(INT wanted_size, INT boundary) { USB_MHDR_T *pPrimitivePos = _pCurrent; USB_MHDR_T *pFound; INT found_size = -1; INT i, block_count; INT wrap = 0; int disable_ohci_irq, disable_ehci_irq; if (IS_OHCI_IRQ_ENABLED()) disable_ohci_irq = 1; else disable_ohci_irq = 0; if (IS_EHCI_IRQ_ENABLED()) disable_ehci_irq = 1; else disable_ehci_irq = 0; if (disable_ohci_irq) DISABLE_OHCI_IRQ(); if (disable_ehci_irq) DISABLE_EHCI_IRQ(); if (wanted_size >= _FreeMemorySize) { rt_kprintf("USB_malloc - want=%d, free=%d\n", wanted_size, _FreeMemorySize); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return NULL; } if ((UINT32)_pCurrent >= _MemoryPoolEnd) _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */ do { if (_pCurrent->flag) /* is not a free block */ { if (_pCurrent->magic != USB_MEM_ALLOC_MAGIC) { rt_kprintf("\nUSB_malloc - incorrect magic number! C:%x F:%x, wanted:%d, Base:0x%x, End:0x%x\n", (UINT32)_pCurrent, _FreeMemorySize, wanted_size, (UINT32)_MemoryPoolBase, (UINT32)_MemoryPoolEnd); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return NULL; } if (_pCurrent->flag == 0x3) _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + _pCurrent->bcnt * USB_MEM_BLOCK_SIZE); else { rt_kprintf("USB_malloc warning - not the first block!\n"); _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE); } if ((UINT32)_pCurrent > _MemoryPoolEnd) rt_kprintf("USB_malloc - behind limit!!\n"); if ((UINT32)_pCurrent == _MemoryPoolEnd) { //rt_kprintf("USB_alloc - warp!!\n"); wrap = 1; _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */ } found_size = -1; /* reset the accumlator */ } else /* is a free block */ { if (found_size == -1) /* the leading block */ { pFound = _pCurrent; block_count = 1; if (boundary > BOUNDARY_WORD) found_size = 0; /* not use the data area of the leading block */ else found_size = USB_MEM_BLOCK_SIZE - sizeof(USB_MHDR_T); /* check boundary - * If boundary > BOUNDARY_WORD, the start of next block should * be the beginning address of allocated memory. Thus, we check * the boundary of the next block. The leading block will be * used as a header only. */ if ((boundary > BOUNDARY_WORD) && ((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE >= _MemoryPoolEnd) || ((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE) % boundary != 0))) found_size = -1; /* violate boundary, reset the accumlator */ } else /* not the leading block */ { found_size += USB_MEM_BLOCK_SIZE; block_count++; } if (found_size >= wanted_size) { pFound->bcnt = block_count; pFound->magic = USB_MEM_ALLOC_MAGIC; _FreeMemorySize -= block_count * USB_MEM_BLOCK_SIZE; _AllocatedMemorySize += block_count * USB_MEM_BLOCK_SIZE; _pCurrent = pFound; for (i = 0; i < block_count; i++) { _pCurrent->flag = 1; /* allocate block */ _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE); } pFound->flag = 0x3; if (boundary > BOUNDARY_WORD) { if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); //rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size); return (void *)((UINT32)pFound + USB_MEM_BLOCK_SIZE); } else { //USB_debug("USB_malloc(%d,%d):%x\tsize:%d, C:0x%x, %d\n", wanted_size, boundary, (UINT32)pFound + sizeof(USB_MHDR_T), block_count * USB_MEM_BLOCK_SIZE, _pCurrent, block_count); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); //rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size); return (void *)((UINT32)pFound + sizeof(USB_MHDR_T)); } } /* advance to the next block */ _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE); if ((UINT32)_pCurrent >= _MemoryPoolEnd) { wrap = 1; _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */ found_size = -1; /* reset accumlator */ } } } while ((wrap == 0) || (_pCurrent < pPrimitivePos)); rt_kprintf("USB_malloc - No free memory!\n"); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return NULL; } void USB_free(void *alloc_addr) { USB_MHDR_T *pMblk; UINT32 addr = (UINT32)alloc_addr; INT i, count; int disable_ohci_irq, disable_ehci_irq; if (IS_OHCI_IRQ_ENABLED()) disable_ohci_irq = 1; else disable_ohci_irq = 0; if (IS_EHCI_IRQ_ENABLED()) disable_ehci_irq = 1; else disable_ehci_irq = 0; //rt_kprintf("USB_free: 0x%x\n", (int)alloc_addr); if ((addr < _MemoryPoolBase) || (addr >= _MemoryPoolEnd)) { if (addr) { rt_kprintf("[%s]Wrong!!\n", __func__); //free(alloc_addr); } return; } if (disable_ohci_irq) DISABLE_OHCI_IRQ(); if (disable_ehci_irq) DISABLE_EHCI_IRQ(); //rt_kprintf("USB_free:%x\n", (INT)addr+USB_MEM_BLOCK_SIZE); /* get the leading block address */ if (addr % USB_MEM_BLOCK_SIZE == 0) addr -= USB_MEM_BLOCK_SIZE; else addr -= sizeof(USB_MHDR_T); if (addr % USB_MEM_BLOCK_SIZE != 0) { rt_kprintf("USB_free fatal error on address: %x!!\n", (UINT32)alloc_addr); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return; } pMblk = (USB_MHDR_T *)addr; if (pMblk->flag == 0) { rt_kprintf("USB_free(), warning - try to free a free block: %x\n", (UINT32)alloc_addr); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return; } if (pMblk->magic != USB_MEM_ALLOC_MAGIC) { rt_kprintf("USB_free(), warning - try to free an unknow block at address:%x.\n", addr); if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return; } //_pCurrent = pMblk; //rt_kprintf("+ 0x%x, %d\n", (int)pMblk, pMblk->bcnt); count = pMblk->bcnt; for (i = 0; i < count; i++) { pMblk->flag = 0; /* release block */ pMblk = (USB_MHDR_T *)((UINT32)pMblk + USB_MEM_BLOCK_SIZE); } _FreeMemorySize += count * USB_MEM_BLOCK_SIZE; _AllocatedMemorySize -= count * USB_MEM_BLOCK_SIZE; if (disable_ohci_irq) ENABLE_OHCI_IRQ(); if (disable_ehci_irq) ENABLE_EHCI_IRQ(); return; } /// @endcond HIDDEN_SYMBOLS