open_map.c 5.05 KB
/**    
    @file     open_map.c
    @date     2014/01/20
    @author   오재경 freefrug@falinux.com  FALinux.Co.,Ltd.
    @brief    * mmap 유틸리티이다.
              
              Ver 0.2.0
              
    @modify   
    @todo     
    @bug     
    @remark   
    @warning   
*/
//----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/mman.h> 


#ifndef  PAGE_SIZE
#define  PAGE_SIZE  (1024*4)
#endif

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

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


#define MAP_LIST_COUNT		1024
static mmap_alloc_t *list_ptr[MAP_LIST_COUNT];
static int map_list_init = 0;

//------------------------------------------------------------------------------
/** @brief   mmap_alloc_t 할당함수
    @return  mmap_alloc 포인터
*///----------------------------------------------------------------------------
static mmap_alloc_t *get_map_struct( void )
{       
	int  idx;
	
	if ( 0 == map_list_init )
	{
		memset( list_ptr, 0, sizeof(list_ptr) );	
		map_list_init = 1;
	}
	
	for( idx=0; idx<MAP_LIST_COUNT; idx++ )
	{
		if ( NULL == list_ptr[idx] )
		{
			mmap_alloc_t *ma = (mmap_alloc_t *)malloc( sizeof(mmap_alloc_t) );	
			list_ptr[idx] = ma;
			return ma;
		}
	}
	
	printf( "unable get free list (0~%d)\n",MAP_LIST_COUNT-1 );
	return NULL;
}
//------------------------------------------------------------------------------
/** @brief   
    @return  mmap_alloc 포인터
*///----------------------------------------------------------------------------
static mmap_alloc_t *put_map_struct( void *virt )
{       
	int  idx;
	
	for( idx=0; idx<MAP_LIST_COUNT; idx++ )
	{
		if ( list_ptr[idx] ) 
		{
			mmap_alloc_t *ma = list_ptr[idx];
			
			if ( (ma->virt + ma->base_ofs) == virt )
			{
				free( (void *)ma );
				list_ptr[idx] = NULL;
				return ma;
			}
		}
	}

	printf( "unable find list (0~%d)\n",MAP_LIST_COUNT-1 );
	return NULL;
}
//------------------------------------------------------------------------------
/** @brief   mmap 생성함수
    @param   ma           mmap_alloc_t 구조체 포인터
    @param   phys_base    물리주소
    @param   size         크기
    @return  사용할수 있는 가상주소
*///----------------------------------------------------------------------------
void  *open_mmap_alloc( unsigned long phys_base, unsigned long size )
{       
	mmap_alloc_t *ma;
	
	int        dev_mem;
	int        base_ofs;
	void      *mmap_mem;
	
	// 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 = get_map_struct();
	if ( ma )
	{
		ma->dev      = dev_mem;
		ma->phys     = phys_base;
		ma->size     = size;
		ma->virt     = mmap_mem;
		ma->base_ofs = base_ofs;
    	
		return mmap_mem + base_ofs;
	}
	else
	{	
		munmap( ma->virt, ma->size );	
		close ( ma->dev );
		return NULL;
	}
}

//------------------------------------------------------------------------------
/** @brief   mmap  포인터를 해제한다.
    @param   ma    mmap_alloc_t 구조체 포인터
*///----------------------------------------------------------------------------
void  open_mmap_free( void *io_virt )
{
	mmap_alloc_t *ma;

	ma = put_map_struct( io_virt );
	
	if ( ma )
	{
		munmap( ma->virt, ma->size );	
		close ( ma->dev );
	}
}


/// 샘플 ------------------------------------------------------------------------
#if 0

static volatile unsigned int *io_port;

int  main( int argc, char **argv )
{
	unsigned int phys, data;
	
	if ( argc < 2 )
	{
		printf( " %s phys_addr\n", argv[0] );	
		return 0;
	}
	
	phys = strtoul( argv[1], NULL, 0 );
	
	// 할당 --------------
	io_port = (unsigned int *)open_mmap_alloc( phys, 0x100 );

	// 읽기	
	data = *io_port;
	printf( "read  addr=%08x   data=%08x\n", phys, data );
	
	// 해제 --------------
	open_mmap_free( io_port );
	
	return 0;	
}

#endif