/** @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 #include #include #include #include #include #include #include #include #include #include #include #include #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; idxvirt + 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