diff --git a/include/driver_mem.h b/include/driver_mem.h new file mode 100644 index 0000000..3a1b9e9 --- /dev/null +++ b/include/driver_mem.h @@ -0,0 +1,12 @@ +#ifndef _DRIVER_MEM_H_ +#define _DRIVER_MEM_H_ + +/* + * the driver_mem module provides a block of _uncached_ memory for USB and other drivers as + * well as some memory handling functions for it + */ +extern int driver_mem_init(void); +extern void *driver_mem_alloc(long amount); +extern int driver_mem_free(void *addr); + +#endif /* _DRIVER_MEM_H_ */ diff --git a/sys/driver_mem.c b/sys/driver_mem.c new file mode 100644 index 0000000..48cfe73 --- /dev/null +++ b/sys/driver_mem.c @@ -0,0 +1,354 @@ +/* + * driver_mem.c + * + * based from Emutos / BDOS + * + * Copyright (c) 2001 Lineo, Inc. + * + * Authors: Karl T. Braun, Martin Doering, Laurent Vogel + * + * This file is distributed under the GPL, version 2 or at your + * option any later version. + */ + +#include +#include +#include "bas_string.h" +#include "bas_printf.h" +#include "usb.h" +#include "exceptions.h" /* set_ipl() */ + +#if MACHINE_FIREBEE +#include "firebee.h" +#elif MACHINE_M5484LITE +#include "m5484l.h" +#endif + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#undef DRIVER_MEM_DEBUG + +#ifdef DRIVER_MEM_DEBUG +#define dbg(fmt, args...) xprintf(fmt, ##args) +#else +#define dbg(fmt, args...) +#endif + +extern void *info_fvdi; +extern long offscren_reserved(void); + +extern uint8_t driver_mem_buffer[DRIVER_MEM_BUFFER_SIZE]; /* defined in linker control file */ + +/* MD - Memory Descriptor */ + +#define MD struct _md_ + +MD +{ + MD *m_link; + long m_start; + long m_length; + void *m_own; +}; + +/* MPB - Memory Partition Block */ + +#define MPB struct _mpb + +MPB +{ + MD *mp_mfl; + MD *mp_mal; + MD *mp_rover; +}; + +#define MAXMD 256 + +static MD tab_md[MAXMD]; +static MPB pmd; + +static void *xmgetblk(void) +{ + int i; + + for (i = 0; i < MAXMD; i++) + { + if (tab_md[i].m_own == NULL) + { + tab_md[i].m_own = (void*)1L; + return(&tab_md[i]); + } + } + return NULL; +} + +static void xmfreblk(void *m) +{ + int i = (int)(((long) m - (long) tab_md) / sizeof(MD)); + if ((i > 0) && (i < MAXMD)) + { + tab_md[i].m_own = NULL; + } +} + +static MD *ffit(long amount, MPB *mp) +{ + MD *p, *q, *p1; /* free list is composed of MD's */ + int maxflg; + long maxval; + + if (amount != -1) + { + amount += 15; /* 16 bytes alignment */ + amount &= 0xFFFFFFF0; + } + + if ((q = mp->mp_rover) == 0) /* get rotating pointer */ + { + return 0; + } + + maxval = 0; + maxflg = ((amount == -1) ? TRUE : FALSE) ; + p = q->m_link; /* start with next MD */ + do /* search the list for an MD with enough space */ + { + if (p == 0) + { + /* at end of list, wrap back to start */ + q = (MD *) &mp->mp_mfl; /* q => mfl field */ + p = q->m_link; /* p => 1st MD */ + } + if ((!maxflg) && (p->m_length >= amount)) + { + /* big enough */ + if (p->m_length == amount) + { + q->m_link = p->m_link; /* take the whole thing */ + } + else + { + /* + * break it up - 1st allocate a new + * MD to describe the remainder + */ + p1 = xmgetblk(); + if (p1 == NULL) + { + return(NULL); + } + + /* init new MD */ + p1->m_length = p->m_length - amount; + p1->m_start = p->m_start + amount; + p1->m_link = p->m_link; + p->m_length = amount; /* adjust allocated block */ + q->m_link = p1; + } + /* link allocate block into allocated list, + mark owner of block, & adjust rover */ + p->m_link = mp->mp_mal; + mp->mp_mal = p; + mp->mp_rover = (q == (MD *) &mp->mp_mfl ? q->m_link : q); + return(p); /* got some */ + } + else if (p->m_length > maxval) + maxval = p->m_length; + p = ( q=p )->m_link; + } while(q != mp->mp_rover); + + /* + * return either the max, or 0 (error) + */ + if (maxflg) + { + maxval -= 15; /* 16 bytes alignment */ + if (maxval < 0) + { + maxval = 0; + } + else + { + maxval &= 0xFFFFFFF0; + } + } + return(maxflg ? (MD *) maxval : 0); +} + +static void freeit(MD *m, MPB *mp) +{ + MD *p, *q; + + q = 0; + for (p = mp->mp_mfl; p ; p = (q = p) -> m_link) + { + if (m->m_start <= p->m_start) + { + break; + } + } + m->m_link = p; + + if (q) + { + q->m_link = m; + } + else + { + mp->mp_mfl = m; + } + + if (!mp->mp_rover) + { + mp->mp_rover = m; + } + + if (p) + { + if (m->m_start + m->m_length == p->m_start) + { + /* join to higher neighbor */ + m->m_length += p->m_length; + m->m_link = p->m_link; + if (p == mp->mp_rover) + { + mp->mp_rover = m; + } + xmfreblk(p); + } + } + if (q) + { + if (q->m_start + q->m_length == m->m_start) + { + /* join to lower neighbor */ + q->m_length += m->m_length; + q->m_link = m->m_link; + if (m == mp->mp_rover) + { + mp->mp_rover = q; + } + xmfreblk(m); + } + } +} + +int driver_mem_free(void *addr) +{ + int level; + MD *p, **q; + MPB *mpb; + mpb = &pmd; + level = set_ipl(7); + + for(p = *(q = &mpb->mp_mal); p; p = *(q = &p->m_link)) + { + if ((long) addr == p->m_start) + { + break; + } + } + + if (!p) + { + set_ipl(level); + return(-1); + } + + *q = p->m_link; + freeit(p, mpb); + set_ipl(level); + + dbg("driver_mem_free(0x%08X)\r\n", addr); + + return(0); +} + +void *driver_mem_alloc(long amount) +{ + void *ret = NULL; + int level; + MD *m; + + if (amount == -1L) + { + return((void *)ffit(-1L, &pmd)); + } + + if (amount <= 0 ) + { + return(0); + } + + if ((amount & 1)) + { + amount++; + } + + level = set_ipl(7); + m = ffit(amount, &pmd); + + if (m != NULL) + { + ret = (void *)m->m_start; + } + set_ipl(level); + dbg("driver_mem_alloc(%d) = 0x%08X\r\n", amount, ret); + + return(ret); +} + +static int init_count = 0; + +int driver_mem_init(void) +{ + if (! init_count == 0) + { +#ifdef USE_RADEON_MEMORY + driver_mem_buffer = (void *) offscreen_reserved(); + if (driver_mem_buffer == NULL) +#endif + memset(driver_mem_buffer, 0, DRIVER_MEM_BUFFER_SIZE); + + if (driver_mem_buffer == NULL) + { + return(-1); + } + + pmd.mp_mfl = pmd.mp_rover = &tab_md[0]; + tab_md[0].m_link = (MD *) NULL; + tab_md[0].m_start = ((long) driver_mem_buffer + 15) & ~15; + tab_md[0].m_length = DRIVER_MEM_BUFFER_SIZE; + tab_md[0].m_own = (void *) 1L; + pmd.mp_mal = (MD *) NULL; + memset(driver_mem_buffer, 0, tab_md[0].m_length); + dbg("uncached driver memory buffer at 0x%08X size %d\r\n", tab_md[0].m_start, tab_md[0].m_length); + } + else + { + init_count++; + } + return(0); +} + +void driver_mem_stop(void) +{ + if (init_count-- == 0) + { +#ifndef CONFIG_USB_MEM_NO_CACHE +#ifdef USE_RADEON_MEMORY + if (driver_mem_buffer == (void *) offscren_reserved()) + return; + +#endif +#endif + } +} + + +