- cleanup_module() : 디바이스 드라이버 제거, 할당된 IO memory 영역 변환
- 함수 : read(), ioctl(), write(), open(), release()
-> 사용자 공간과 커널 공간의 데이터 전송, 메모리에 값을 읽거나 씀
디바이스 드라이버 원형
- 파일 처리 함수 데이터 구조체 생성 및 구조체 맴버변수에 제작한 함수 매핑
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
// 헤더 파일
int device_open(){}
int device_release(){}
ssize_t device_write(){}
ssize_t device_read(){}
// 함수 프로토 타입
static struct file_operations device_fops =
{
read:device_read,
write:device_write,
open:device_open,
release:device_release
};
// 파일 처리 함수
int init_module(void){} // 모듈 설치시 초기화 수행
void cleanup_module(void){} // 모듈 제거시 반환 작업 수행
/*
디바이스 드라이버는 모듈 프로그램 사용
-> 모듈 프로그램 원형에 디바이스 드라이버에 필요한 파일 처리 함수부분 추가
*/
2) 디바이스 드라이버 등록과 삭제
디바이스 드라이버 등록
- 디바이스 드라이버를 커널에 등록하는 함수
- 문자형 디바이스 : int device_chrdev(unsigned int major, const char *name, struct file_operations *fops);
- 블록형 함수 : int register_blkdev(unsigned int major, const char *name, struct file_operations *fops);
- 파라미터
주번호 : 0을 주면 사용하지 않는 값반환
이름 : /proc/devices에 표시
fops : 디바이스와 연관된 파일 연선 구조체 포인터
- 음수가 반환시 오류가 발생한것. 디바이스 드라이버의 init_module()에서 호출
디바이스 드라이버 제거
커널에 등록되어있는 디바이스 드라이버 제거
- 문자형 디바이스 : int unregister_chrdev(unsigned int major, const char *name);
- 블록형 디바이스 : int unregister_blkdev(unsigend int major, const char *name);
# insmod mymod.o // 모듈을 커널에 로딩
Using mymod.o
Start of Module !! //init_module 함수가 실행되어 printk함수에 의해 출력
# lsmod
Module size Usedby
mymod 247 0(unused)
# rmmod mymod //cleanup_module 함수 실행
End of Module !!
3) 디바이스 드라이버 분석
디바이스 드라이버
- ARM 프로세서 기반 하드웨어 플랫폼에서 ARM의 GPIO에 연결된 LED를 제어하는 LED 디바이스 드라이버소스
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#define LED_MAJOR 0
#define LED_NAME "LED PORT"
#define LED_MODULE_VERSION "v1.0"
#define LED_ADDR 0xf1600000
#define LED_ADDR_RANGE 1
// LED 디바이스 주번호, 디바이스이름, 버전번호, 가상어드레스 주소, 어드레스 범위
static int led_usage = 0;
static int led_major = 0;
//LED 사용 여부 표시하는변수, 주번호 저장하는 변수
int led_open(struct inode *minode, struct file *mfile);
int led_release(struct inode *minode, struct file *mfile);
ssize_t led_writeb(struct inode *minode, const char *gdata, size_t length, loff_t *off_what);
static struct file_operations_led_fops = {
write:led_writeb,
open:led_open,
release:led_release,
};
int init_module(void){
int result;
result = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
if (resulr <0){
printk(KERN_WARNING "can't get any major\n");
return result;
}
led_major =result;
//커널에 등록된 IO자원중 지정된 주소로부터 일정 크기 영역사용가능한지 여부 확인
if(!check_region(LED_ADDR, LED_ADDR_RANGE))
request_region(LED_ADDR, LED_ADDR_RANGE,LED_NAME); //시용영역확부
else
printk("Can't get IO region");
printf("init module, led major number : %d\n",result);
return 0;
}
void cleanup_module(void){
release_region(LED_ADDR, LED_ADDR_RANGE);
if (unregister_chrdev(led_major, LED_NAME))
printk(KERNEL_WARNING "%s driver cleanup failed \n",LED_NAME);
}
int led_open(struct inode *mindoe, struct file *mfile){
if (led_usage !=0) return -EBUSY;
MOD_INC_USE_COUNT;
led_usage=1;
return 0;
}
int led_open(struct inode *mindoe, struct file *mfile){
MOD_INC_USE_COUNT;
led_usage=0;
return 0;
}
//디바이스에 데이터를 써넣는 함수
ssize_t led_Writeb(struct file *inode, const char *gdata, size_t length, loff_t *off_what){
unsigned char *addr;
unsigned char c;
//사용자 영역변수인 gdata로부터 커널영역인 c변수로 데이터 전달받음
get_user(c, gdata);
addr=(unsigned char*)(LED_ADDR);
*addr=c;
return length;
}
응용 프로그램
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv){
int dev;
char buff;
if (argc <= 1) return -1;
dev = open("/dev/led", O_WRONLY);
if (dev != -1){
buff =atoi(argv[1]);
write(dev, &buff, 1);
close(dev);
}
else {
printf("Device open Error\n");
exit(-1);
}
return 0;
}