rt-thread/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/support.c

325 lines
9.7 KiB
C
Raw Normal View History

2021-05-12 19:15:17 +08:00
/**************************************************************************//**
* @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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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