이식성과 데이터형 서로 다른 프로세서 상에서의 이식성을 위해 가급적 리눅스 커널이 제공하는 데이터형을 사용하는 것이 좋다. #include <asm/types.h>에 정의. 주로 사용되는 데이터형 App Kernel __s8 s8 부호있는 8비트 정수형 __u8 u8 부호없는 __s16 s16 16비트 정수형 __u16 u16 __s32 s32 32비트 정수형 __u32 u32 __s64 s64 64비트 정수형 __u64 u64
동적 메모리 할당 함수 할당 속도가 빠르고 사용법이 간단해 kmalloc() 디바이스 드라이버에서 가장 많이 kfree() 사용되는 함수(할당 크기 제한 있음). vmalloc() vfree() 가상공간이 허용하는 한 크기 제한 없이 할당 받을 수 있다. 큰 메모리 공간을 할당할 때 주로 사용한다(속도가 느리다). __get_free_pages() __free_pages() 잘 사용되지 않는 함수.
kmalloc(), kfree()-1 메모리주소 kmalloc(할당 받을 크기, 옵션); kfree(메모리주소); * 할당 가능한 최대 크기는 32 x PAGE_SIZE (일반적으로 128KB) #include <linux/slab.h> char *buf; buf = kmalloc(1024, GFP_KERNEL); if (buf != NULL) { … kfree(buf); }
kmalloc(), kfree()-2 메모리 할당 시 사용되는 옵션 (할당된 메모리에 특성을 주거나 할당 시점에 처리방식을 지정) GFP_KERNEL 동적 메모리 할당이 항상 성공하도록 요구한다. 메모리 부족 시 메모리가 사용 가능해 질 때까지 잠든다. 이런 특성으로 인해서 인터럽트에서는 사용하면 안 된다. GFP_ATOMIC 커널에 할당 가능한 메모리가 있으면 무조건 할당하고, 없으면 즉시 NULL을 반환한다. 프로세스가 잠드는 문제는 없지만 메모리 할당에 실패할 경우를 항상 염두 해 두어야 한다. GFP_DMA 연속된 물리 메모리를 할당 받을 때 사용한다. (DMA를 사용할 때 사용해야 한다.)
vmalloc(), vfree() 메모리주소 vmalloc(할당 받을 크기); vfree(메모리주소); #include <linux/vmalloc.h> char *buf; buf = vmalloc(1024); if (buf != NULL) { … vfree(buf); }
vmalloc(), vfree() 특징 가상 주소 공간에서 할당받기 때문에 해당주소의 영역이 하드디스크에 있을 수도 있어 실패할 수 있다. 커다란 연속된 공간을 할당하기 위해 가상메모리 관리 루틴이 수행되기 때문에 kmalloc() 보다 속도가 매우 느리다. 할당 시 프로세스가 잠들지 못하게 할 수 없기 때문에 인터럽트 서비스 함수 안에서는 사용할 수 없다.
__get_free_pages(), free_pages() #include <linux/mm.h> //2.4 #include <linux/gfp.h> //2.6 #include <asm/page.h> //get_order char *buf; buf = __get_free_pages(GFP_KERNEL, order); /* order=0이면 1개의 page, order=3이면 3개의 page /* MAX_ORDER은 11, 그러나 5이하의 값만 사용하는 것이 안전 (32*PAGE_SIZE) */ if (buf != NULL) { … free_pages(buf, order); }
초기화와 종료 처리 디바이스 드라이버가 동작하기 위한 초기화와 종료에 필요한 대표적인 처리 항목 디바이스 드라이버가 동작하기 위한 초기화와 종료에 필요한 대표적인 처리 항목 디바이스 드라이버의 등록과 해제 디바이스 드라이버에 내부 구조체의 메모리 할당과 해제 여러 프로세스가 하나의 디바이스에 접근할 때 필요한 사전 처리 및 종료 시 처리 주 번호에 종속된 부 번호를 관리하기 위한 사전 처리 및 종료 시 처리 하드웨어 검출 처리 및 에러 처리 응용 프로그램에서 디바이스 드라이버를 사용하는 경우의 처리 및 사용 종료 처리 부 번호에 관련된 프로세스별 처리 프로세스별 메모리 할당과 해제 사용하는 모듈 수의 관리
초기화와 종료 처리 디바이스 드라이버 두 가지 초기화 처리시점 1) 모듈 적재와 & 제거과정 디바이스 드라이버 두 가지 초기화 처리시점 1) 모듈 적재와 & 제거과정 -insmod 명령 : module_init – 모듈적재 과정(초기화 처리) -rmmod 명령 : module_exit – 모듈제거 과정(종료처리) 2)응용프로그램이 디바이스 파일을 여는 과정과 닫는 과정 -open( )함수 : file_operation.open – 디바이스 파일을 여는 과정 -close( )함수 : file_operation.release – 디바이스 파일을 닫는 과정 이중 어디에서 처리해야 된다는 표준 규정은 없다.(하드웨어의 구조와 디바이스 드라이버의 구현 방식에 따라 달리 지기 때문)
초기화와 종료 처리 module_init 의 초기화 처리 디바이스 드라이버의 등록 디바이스 드라이버에 내부 구조체의 메모리 할당 여러 프로세스가 하나의 디바이스에 접근하는 경우에 사전처리 주 번호에 종속된 부 번호를 관리하기 위한 사전 처리 하드웨어 검출 처리 및 에러 처리 하드웨어 초기화
초기화와 종료 처리 module_init 처리순서 int xxx_init(void) { } xxx_probe(… //하드웨어 검출 처리 및 에러처리 xxx_setup(…. //하드웨어 초기화 register_chrdev(… //디바이스 드라이버의 등록 info = kmalloc(… //디바이스 드라이버에 동작에 필요한 내부 구조체의 메모리 할당 xxx_setupinfo(… //여러 프로세가 디바이스 하나에 접근하는 경우에 필요한 사전 처리 xxx_setupminor(… // 주번호에 종속된 부 번호를 관리하기 위한 사전 처리 }
초기화와 종료 처리 module_exit 의 종료 처리 초기화 시점에 할당된 메모리 모두 반납 디바이스 드라이버의 해제 (디바이스 드라이버는 커널의 일부이기 때문에 메모리를 자동 반납하지 않는다.) 디바이스 드라이버의 해제 디바이스 드라이버에 할당된 모든 메모리의 해제 하드웨어 제거에 따른 처리
초기화와 종료 처리 module_exit 처리순서 void xxx_exit(void) { kfree(… // 디바이스 드라이버에 할당된 모든 메모리 해제 unregister_chrdev(… // 디바이스 드라이버의 해제 xxx_shutdown(… //하드웨어 제거에 따른 처리 }
초기화와 종료 처리 디바이스 드라이버 open( ) 함수[1] Open 함수 호출 시 초기화 처리 반드시 디바이스 드라이버의 주 번호 정보가 있는 파일을 열어야 한다. Open 함수 호출 시 초기화 처리 디바이스 드라이버가 처음 열렸을 때 하드웨어 초기화 디바이스 드라이버의 동작에 필요한 에러처리 부 번호에 대한 처리가 필요한 경우 파일 오퍼레이션 구조체를 갱신 프로세스별 메모리 할당과 초기화 모듈의 사용 횟수 증가(커널 2.4) 커널 2.6에서는 사용횟수 관리를 커널에서 한다.
초기화와 종료 처리 디바이스 드라이버 open( ) 함수[2] int fd; fd = open( DEVICE_FILENAME, O_RDWR|O_NDELAY); //반드시 주번호 정보가 있는 파일 if( fd < 0 ) { printf (“error number %d\n”, error); exit(1); } #include<linux/fs.h> struct file_operations call_fops = { … .open = xxx_open, … } int xxx_open( struct inode *inode, struct file *filp ) { int err = 0; //open() 시 처리내용들…. return err; } *inode – 열린 디바이스 파일에 대한 정보 *filp – 디바이스 드라이버 처리관련 정보 ENODEV : 하드웨어가 존재하지 않는다. ENOMEM : 커널 메모리가 부족하다. EBUSY : 디바이스가 이미 사용중 이다.
초기화와 종료 처리 디바이스 드라이버 release( ) 함수[1] release( ) 함수 호출 시 종료 처리 프로세스별 할당 메모리 해제 모듈 사용 횟수 감소(커널 2.4) 커널 2.6에서는 사용횟수 관리를 커널에서 한다.
초기화와 종료 처리 디바이스 드라이버 release( ) 함수[2] if( fd ) close( fd ); #include<linux/fs.h> struct file_operations call_fops = { … .release = xxx_release, … } int xxx_release( struct inode *inode, struct file *filp ) { //close( ) 시 처리내용들…. return 0; }
모듈 사용 횟수 관리 모듈 사용횟수 관리 함수 커널 2.4 MOD_INT_USE_COUNT : 모듈 사용 횟수를 증가시킨다. MOD_DEC_USE_COUNT : 모듈 사용 횟수 감소시킨다. MOD_IN_USE : 모듈 사용 횟수가 0이 아니면 참값을 반환한다. 커널 2.6 Try_module_get(THIS_MODULE) : 모듈 사용 횟수를 증가시킨다. Module_put(THIS_MODULE) : 모듈 사용 횟수 감소시킨다.
문자 디바이스 드라이버 동작-1 read dev-read 응용 프로그램 장치파일 하드웨어 return return * 단일 방식의 호출규칙을 통해 다양한 개념과 다양한 형태의 하드웨어를 제어 가능하다
문자 디바이스 드라이버 동작 디바이스 드라이버 하드웨어 인터럽트 insmod xxx_init(); struct file_operations { open : xxx_open write : xxx_write . . . } xxx_exit(); xxx_interupt(); xxx_open(); xxx_write(); 응용 프로그램 open(); write(); rmmod
커널 2.6의 파일 오퍼레이션 구조체 struct file_operations { struct module *owner; int (*open)(struct inode *, struct file *); . } * 디바이스 드라이버의 file_operations에서 정의되지 않았거나 NULL로 채워진 필드는 커널에 의해서 default 처리를 한다.
문자 디바이스 드라이버의 등록과 해제 및 구성 <linux/fs.h>를 추가하고 int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); 를 이용해 커널에 디바이스 드라이버의 file_operations을 등록한다.(중요!!!) *디바이스 드라이버가 등록된다는 것은 주번호에 연관된 file_operations 구조체가 커널에 등록된다는 의미. int unregister_chrdev(unsigned int major, const char *name); 를 이용해 등록된 디바이스 드라이버를 해제한다. 주번호는 응용 프로그램에서 디바이스 파일을 이용해 디바이스 드라이버를 찾을 때 사용 디바이스 드라이브명은 proc 파일 시스템이나 오류정보를 커널에 나타내기 위해 사용한다. 디바이스 드라이버를 제거할때 구별자로도 사용된다. * 두값을 모두 비교해서 해제할 디바이스 드라이버를 선택한다.
문자 디바이스 드라이버의 등록과 해제 사용자 공간 커널 공간 드바이스 드라이버 module_init() { register_chrdev(); } struct file_operations module_exit() unregister_chrdev(); insmod 장치파일 응용프로그램 { open(); read(); write(); } rmmod chrdevs[MAX-]
#include <linux/init. h> #include <linux/module #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #inlcude <linux/fcntl.h> int xxx_open (struct inode *inode, struct file *filp) { } int xxx_release(struct inode *inode, struct file *filp) struct file_operations xxx_fops = .owner = THIS_MODULE, .open = xxx_open, .release = xxx_release, }; int xxx_init(void) register_chrdev(240, “char_dev”, &xxx_fops); void xxx_exit(void) { unreister_chrdev(240, “char_dev”); module_init(xxx_init); module_exit(xxx_exit);
mknod /dev/calldev c 240 32
make
insmod call_dev.ko
app(call_app) 컴파일
app 실행
dmesg