tmmap.c 4.31 KB
/**    
    @file     tmmap.c
    @date     2009/07/06
    @author   오재경 freefrug@falinux.com  FALinux.Co.,Ltd.
    @brief    mmap 를 다루는 함수를 객체화 하였다.
              
    @todo     테스트 함수를 아직 만들지 않았다.
    @bug     
    @remark  
    @warning 
*/
//
//  저작권    에프에이리눅스(주)
//            외부공개 금지
//
//----------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/mman.h> 


#include <tlist.h>
#include <tmmap.h>


/// mmap 를 위한 개별 관리 구조체
typedef struct {
	
	int            dev;         // /dev/mem 파일핸들
	unsigned long  phys;        // 물리주소
	unsigned long  size;        // 크기
	int            base_ofs;    // 베이스 주소가 4K 정렬이 되지 않았을때 사용

	void          *virt;        // 할당받은 메모리포인터
	
} mmap_alloc_t;


static tlist *ma_list = NULL;   /// mmap 관리 리스트


//------------------------------------------------------------------------------
/** @brief   mmap 생성함수
    @param   base
    @param   size
*///----------------------------------------------------------------------------
void  *tmmap_alloc( unsigned long phys_base, unsigned long size )
{       
	int            dev_mem;
	int            base_ofs;
	void          *mmap_mem;
	mmap_alloc_t  *ma;
	
	// 관리 리스트를 생성한다.
	if ( NULL == ma_list )
	{
		ma_list = tlist_create();	
	}
	
	// 4K 정렬 주소로 변경한다.
	base_ofs   = phys_base & (PAGE_SIZE-1);
	phys_base &= ~(PAGE_SIZE-1);
	
	// 4K 단위의 메모리를 할당받는다.
	size = PAGE_SIZE * ( (size + base_ofs + (PAGE_SIZE-1))/(PAGE_SIZE) );
	
	dev_mem = open( "/dev/mem", O_RDWR|O_SYNC );
	if (0 > dev_mem)
	{
		printf( "open error /dev/mem\n" );
		return NULL;
	}

	// mmap 로 맵핑한다.
	mmap_mem = mmap( 0,                                // 커널에서 알아서 할당요청
                     size,                             // 할당 크기
                     PROT_READ|PROT_WRITE, MAP_SHARED, // 할당 속성
                     dev_mem,                          // 파일 핸들
                     phys_base );                      // 매핑 대상의 물리주소	
	
	
	if ( !mmap_mem )
	{
		printf( "mmap error !!!\n" );
		return NULL;
	}

	// 개별 관리를 위한 구조체를 할당한다.
	ma = (mmap_alloc_t  *)malloc( sizeof(mmap_alloc_t) );
	ma->dev      = dev_mem;
	ma->phys     = phys_base;
	ma->size     = size;
	ma->virt     = mmap_mem;
	ma->base_ofs = base_ofs;

	// 관리 리스트에 등록한다.
	tlist_add( ma_list, (void *)ma );

	return mmap_mem + base_ofs;
}
//------------------------------------------------------------------------------
/** @brief   mmap로 획드한 메모리 포인터를 이용하여 관리 구조체를 얻는다.
    @param   virt   mmap 로 획드한 메모리 포인터
    @return  인덱스
*///----------------------------------------------------------------------------
static int tmmap_get_index( void *virt )
{
	mmap_alloc_t  *ma;
	int  idx, count;
	
	if ( ma_list )
	{
		count = tlist_getcount( ma_list );
		for (idx=0; idx<count; idx++ )
		{
			ma = (mmap_alloc_t *)tlist_get( ma_list, idx );
			
			// 가상메모리가 동일한 주소인지 확인한다.
			if( (ma->virt + ma->base_ofs) == virt )
			{
				return idx;
			}
		}
	}
	
	return -1;
}
//------------------------------------------------------------------------------
/** @brief   mmap  포인터를 해제한다.
    @param   mem   mmap 로 획드한 메모리 포인터
*///----------------------------------------------------------------------------
void  tmmap_free( void *mem )
{
	int  idx;
	mmap_alloc_t  *ma;
		
	if ( ma_list && mem )
	{
		// 해당하는 아이템을 찾아 메모리를 해제한다.
		idx = tmmap_get_index( mem );
		if ( 0 <= idx )
		{
			ma = (mmap_alloc_t *)tlist_get( ma_list, idx );
			
			munmap( ma->virt, ma->size );	
			close ( ma->dev );
			
			free( (void *)ma );
			tlist_delete( ma_list, idx );
		} 

		// 아이템이 없다면 관리자도 해제한다.
		if ( 0 >= tlist_getcount( ma_list ) )
		{
			tlist_free( ma_list );
			ma_list = NULL;
		}

	}
}