문자 디바이스 드라이버cfs6.tistory.com/upload_control/download.blog?fhandle=... · 2015....
TRANSCRIPT
문자문자 디바이스디바이스 드라이버드라이버
임베디드임베디드 시스템시스템 소프트웨어소프트웨어 II
(http://(http://et.smu.ac.kret.smu.ac.kr))
문자 디바이스 드라이버 9-2
차례차례
• 리눅스 디바이스
• 디바이스 파일
• 디바이스 드라이버
• 커널 모듈 (hello.c)
• 커널 모듈 컴파일 (Makefile)
• 커널 모듈 load/unload
• 디바이스 드라이버 프로그램
• 문자 디바이스 드라이버 (skeleton.c)
• 응용 프로그램 (app.c)
• 문자 디바이스 드라이버 시험
문자 디바이스 드라이버 9-3
리눅스리눅스 디바이스디바이스
• 디바이스(device)는 키보드, 마우스, 터미널, 프린터, 디스크 등과
같은 하드웨어 주변 장치를 말함
• 리눅스에서 디바이스의 사용 – 각 디바이스를 대변하는 디바이스 파
일에 파일 입출력 시스템 호출(예: open/read/close 등)을 사용
• 디바이스 분류 - character(문자)/block(블록)/network(네트워크)
• 디바이스 번호 - character/block device는 major/minor 번호를 가
짐
• 디바이스 특수 파일 생성 - "mknod 파일이름 분류 major minor"
문자 디바이스 드라이버 9-4
디바이스디바이스 파일파일 (/dev)(/dev)
lrwxrwxrwx 1 root root 5 4월 12 21:26 mouse -> psaux
brw-rw---- 1 root disk 3, 0 1월 30 2003 hda
brw-rw---- 1 root disk 3, 64 1월 30 2003 hdb
brw-rw---- 1 root disk 8, 0 1월 30 2003 sda
brw-rw---- 1 root disk 8, 16 1월 30 2003 sdb
brw-rw---- 1 ecl1 floppy 2, 0 1월 30 2003 fd0
brw-rw---- 1 ecl1 floppy 2, 1 1월 30 2003 fd1
crw-rw---- 1 root lp 99, 0 1월 30 2003 parport0
crw-rw---- 1 root lp 99, 1 1월 30 2003 parport1
crw--w---- 1 root root 4, 0 1월 30 2003 tty0
crw------- 1 root root 4, 1 4월 19 18:05 tty1
문자 디바이스 드라이버 9-5
디바이스디바이스 드라이버드라이버
• 디바이스와 응용 프로그램 사이에 존재하여 데이터 전달
등의 기능을 담당하는 커널 프로그램
• 디바이스 파일에 대한 입출력 시스템 호출(예: open/
read/write/close 등)을 제공
• 디바이스의 복잡하고 고유한 특성을 사용자에게 숨기고
디바이스 입출력 프로그래밍을 일반 파일 입출력 프로그
램과 유사하게, 쉽게 하게함
문자 디바이스 드라이버 9-6
디바이스디바이스 드라이버드라이버 -- 그림그림응용 프로그램
시스템 콜 인터패이스
가상 파일 시스템(VFS)
디바이스 인터페이스
디바이스
문자디바이스 드라이버
블록디바이스 드라이버
네트워크디바이스 드라이버
버퍼 캐쉬네트워크
서브시스템
사용자 영역
커널 영역
하드웨어
문자 디바이스 드라이버 9-7
커널커널 모듈모듈
• 사용자의 요구에 따라 커널에 load되어 커널의 일부로
사용되는 프로그램 코드
• 커널 모듈은 커널을 recompile/reboot 하지 않고 커널에
새로운 기능을 추가
• 커널 모듈을 사용하지 않으면 커널의 크기가 매우 커지
며 새로운 기능을 추가할 때 마다 커널 전체를
recompile/reboot해야 하는 단점이 있다
• 커널 모듈의 사용 보기로 디바이스 드라이버가 있는데
이는 새로운 하드웨어 디바이스를 사용자가 사용할 수
있게 한다
문자 디바이스 드라이버 9-8
커널커널 모듈모듈 ((hello.chello.c))
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
int init_module(void){
printk("<1>hello module loaded\n");
// A non 0 return means init_module failed
return 0;
}
void cleanup_module(void){
printk(KERN_ALERT "hello module unloaded\n");
}
문자 디바이스 드라이버 9-9
함수함수 printkprintk()()의의 인수인수
• File "/lib/modules/`uname –r`/build/include/linux/kernel.h"에 정의
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
문자 디바이스 드라이버 9-10
매크로매크로 module_init/module_exitmodule_init/module_exit
#include <linux/module.h> // Needed by all modules#include <linux/kernel.h> // Needed for KERN_ALERT#include <linux/init.h> // Needed for the macros
static int hello_init(void){printk(KERN_ALERT “hello module loaded₩n”);return 0;
}
static void hello_exit(void){printk(KERN_ALERT “hello module unloaded₩n”);
}
module_init(hello_init);module_exit(hello_exit);
문자 디바이스 드라이버 9-11
커널커널 모듈모듈 컴파일컴파일 ((MakefileMakefile))
TARGET = hello
WARN = -Wall -Wstrict-prototypes -Wmissing-prototypes
INCLUDE = -isystem /lib/modules/`uname -r`/build/include
CFLAGS = -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE}
CC = gcc
$(TARGET).o: $(TARGET).c
clean:
rm -rf $(TARGET).o
문자 디바이스 드라이버 9-12
커널커널 모듈모듈 load/unloadload/unload
• 모듈 load 명령 줄# insmod hello.o
• 모둘 load 확인 명령 줄# lsmod
Module Size Used by
hello 368 0 (unused)
• 모둘 unload 명령 줄# rmmod hello
• printk() 메시지 확인# tail -2 /var/log/messages
Oct 12 17:54:29 kernel: hello module loaded
Oct 12 17:54:45 kernel: hello module unloaded
문자 디바이스 드라이버 9-13
디바이스디바이스 드라이버드라이버 프로그램프로그램
• 함수 init_module() – 디바이스 드라이버를 커널에 등록
하는 일을 수행
• 함수 cleanup_module() - 디바이스 드라이버를 커널에
서 제거하는 일을 수행
• 구조체 struct file_operations - 각 file operation 함수의
이름을 정의
• 각 file operation 함수들 - 실제 I/O 동작을 프로그램한
함수
문자 디바이스 드라이버 9-14
함수함수 init_module()/cleanup_moduleinit_module()/cleanup_module()()
int init_module(void)
{
int i;
i=register_chrdev(240,"skeleton", &skeleton_fops);
if(i!=0)
return -EIO;
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(240,"skeleton");
}
문자 디바이스 드라이버 9-15
구조체구조체 structstruct file_operationsfile_operations
static struct file_operations skeleton_fops ={
THIS_MODULE, /* struct module *owner;*/NULL, /* skeleton_llseek */skeleton_read, /* skeleton_read */skeleton_write, /* skeleton_write */NULL, /* skeleton_readdir */NULL, /* skeleton_poll */skeleton_ioctl, /* skeleton_ioctl */NULL, /* skeleton_mmap */skeleton_open, /* skeleton_open */NULL, /* skeleton_flush */skeleton_release, /* skeleton_release */NULL, /* skeleton_fsync */NULL, /* skeleton_fasync */NULL, /* skeleton_lock */NULL, /* skeleton_readv */NULL /* skeleton_writev */
};
문자 디바이스 드라이버 9-16
함수함수 open()/release()open()/release()
static int skeleton_open(struct inode *inode, struct file *file)
{
MOD_INC_USE_COUNT;
return 0;
}
static int skeleton_release(struct inode *inode, struct file *file)
{
MOD_DEC_USE_COUNT;
return 0;
}
문자 디바이스 드라이버 9-17
함수함수 read()read()static unsigned int length=0;
static char string[1024];
static ssize_t skeleton_read(struct file *file, char *buf, size_t count, loff_t*ppos)
{
int err,tmp;
if(length<=0)
return 0;
err=copy_to_user(buf,string,length);
if(err!=0)
return -EFAULT;
tmp=length;
length=0;
return tmp;
}
문자 디바이스 드라이버 9-18
함수함수 write()write()
static ssize_t skeleton_write(struct file *file, const char *buf, size_t count,
loff_t *ppos)
{
int err;
err=copy_from_user(string,buf,count);
if(err!=0)
return -EFAULT;
length=count;
return count;
}
문자 디바이스 드라이버 9-19
함수함수 ioctl()ioctl()static int data;
static int skeleton_ioctl(struct inode *inode, struct file *file, unsigned intcmd, unsigned long arg)
{int retval=0;
switch(cmd){case 1: /* for writing data to arg */
if(copy_from_user(&data,(int *)arg,sizeof(int)))return -EFAULT;
break;case 2: /* for reading data from arg */
if(copy_to_user((int *)arg,&data,sizeof(int)))return -EFAULT;
break;default:
retval = -EINVAL;}return retval;
}
문자 디바이스 드라이버 9-20
커널커널 영역과영역과 사용자사용자 영역영역 사이의사이의 데이터데이터 교환교환
• 사용자 영역에서 커널 영역으로 데이터 복사
void copy_from_user(void *to, const void *from, unsigned long count);
void get_user(datum ptr);
• 커널 영역에서 사용자 영역으로 데이터 복사
void copy_to_user(void *to, const void *from, unsigned long count);
void put_user(datum ptr);
문자 디바이스 드라이버 9-21
응용응용 프로그램프로그램 ((app.capp.c) ) -- 1/21/2#include <fcntl.h>#include <unistd.h>#include <stdio.h>main() {
int fd,len;char buffer1[128],buffer2[128];int data1,data2;if((fd=open("/dev/skeleton",O_RDWR))==-1){
printf("open error\n");exit(0);
}printf("open success: fd=%i\n",fd);strcpy(buffer1,"This is a test message!");if((len=write(fd,buffer1,strlen(buffer1)))==-1){
printf("write error\n");exit(1);
}printf("write success: %s\n",buffer1);
문자 디바이스 드라이버 9-22
응용응용 프로그램프로그램 ((app.capp.c) ) -- 2/22/2if((len=read(fd,buffer2,len))==-1){
printf("read error\n");exit(2);
}buffer2[len]='\0';printf("read success: %s\n",buffer2);data1=0x12345678;if(ioctl(fd,1,&data1)!=0){
printf("ioctl 1 error\n");}printf("ioctl 1 success: 0x%x\n",data1);if(ioctl(fd,2,&data2)!=0){
printf("ioctl 2 error\n");}printf("ioctl 2 success: 0x%x\n",data2);close(fd);printf("close success: fd=%d\n",fd);
}
문자 디바이스 드라이버 9-23
디바이스의디바이스의 정보를정보를 가지는가지는 파일들파일들
• /proc/devices
– 현재 시스템에 사용되는 문자 및 블록 디바이스의 major 번호
• /usr/src/linux-2.4.20-8/Documentation/devices.txt
– 디바이스들의 major/minor 번호에 대한 문서
• /usr/src/linux-2.4.20-8/include/linux/major.h
– 디바이스들의 major 번호를 정의한 커널 소스 헤더 파일
문자 디바이스 드라이버 9-24
문자문자 디바이스디바이스 드라이버드라이버 시험시험
• 디바이스 드라이버 컴파일
# gcc -c -D__KERNEL__ -DMODULE -Wall
-I/usr/src/linux/include -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h skeleton.c
• 디바이스 파일 생성
# mknod -m 666 /dev/skeleton c 240 0
• 디바이스 드라이버 모듈 load
# insmod skeleton.o
• 디바이스 드라이버 사용
# ./app
• 디바이스 드라이버 모듈 unload
# rmmod skeleton
FND FND 디바이스디바이스 드라이버드라이버
임베디드임베디드 시스템시스템 소프트웨어소프트웨어 II
(http://(http://et.smu.ac.kret.smu.ac.kr))
문자 디바이스 드라이버 9-26
차례차례
• 7-Segment FND 구동 원리
• 디바이스 드라이버 프로그램 시 필요한 함수
• FND 디바이스 드라이버 fnd-driver.c
• FND 응용 프로그램 fnd-app.c
• FND 디바이스 드라이버 시험
문자 디바이스 드라이버 9-27
77--Segment FNDSegment FND
FND의 한 digit (7-Segment)
PXA255 Pro II는 6개의 7-
Segment를 가지는 FND가
있음 (digit 1~digit 6)
문자 디바이스 드라이버 9-28
77--Segment FND Segment FND 구동구동 원리원리
• FND 포트의 물리 주소
– 0xC0000002
• FND digit 및 segment 위치와 데이터 bit
– digit 부분(dig1~dig6)에는 0을, segment(a~dp) 부분에는 1을
write하면 주어진 digit의 segment에 불이 켜짐
– 보기) FND의 digit 3에 숫자 3(=segment abcdg)을 출력하려면
0xC0000002 번지에 0x4FFB을 출력하면 됨
FND
dp g f e d c b a x x dig6
dig5
dig4
dig3
dig2
dig1
bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
문자 디바이스 드라이버 9-29
디바이스디바이스 드라이버드라이버 프로그램프로그램 시시필요한필요한 함수함수
• get_user(void *x, const void *addr)– 사용자 영역의 *addr의 값을 커널 영역인 x로 sizeof(addr) 만큼 복사
• put_user(void *x, const void *addr)– 커널 영역의 *x의 값을 사용자 영역인 addr로 sizeof(addr) 만큼 복사
• copy_to_user(void *to, void *from, unsigned long size)– 커널 영역의 from에서 size 만큼을 사용자 영역의 to로 복사
• copy_from_user(void *to, void *from, unsigned long size)– 사용자 영역의 from에서 size 만큼을 커널 영역의 to로 복사
• I/O로 부터 값을 읽는 함수– __u8 inb(unsigned int port)– __u16 inw(unsigned int port)– __u32 inl(unsigned int port)
• I/O에 값을 쓰는 함수– void outb(__u8 data, unsigned int port)– void outw(__u16 data, unsigned int port)– void outl(__u32 data, unsigned int port)
문자 디바이스 드라이버 9-30
매크로매크로//전역전역 변수변수 ((fndfnd--driver.cdriver.c))
#define IOM_FND_MAJOR 241 // fnd device major number#define IOM_FND_NAME "fnds" // fnd device name#define IOM_FND_ADDRESS 0xC000002 // fnd physical address
static int fnd_usage = 0; static int fnd_major = 0;static unsigned short *iom_fnd_addr;static unsigned short value_digit[6];static int WaitQ_count = 0;
static struct file_operations iom_fnd_fops = {open: iom_fnd_open, write: iom_fnd_write,release: iom_fnd_release,
};
static struct tq_struct Task = {{ NULL, NULL }, 0,iom_fnd_display, (void *)&value_digit[0],
};
DECLARE_WAIT_QUEUE_HEAD(WaitQ_fnd); //wait queue declare
문자 디바이스 드라이버 9-31
init/cleanup (init/cleanup (fndfnd--driver.cdriver.c))int init_module(void){int result;result=register_chrdev(IOM_FND_MAJOR,IOM_FND_NAME,&iom_fnd_fops);if(result<0)
return result;fnd_major=IOM_FND_MAJOR;iom_fnd_addr=ioremap(IOM_FND_ADDRESS,0x02);return 0;
}
void cleanup_module(void) {if(WaitQ_count == 0){
WaitQ_count++;interruptible_sleep_on(&WaitQ_fnd);
}iounmap(iom_fnd_addr);unregister_chrdev(fnd_major,IOM_FND_NAME)
}
문자 디바이스 드라이버 9-32
open/release (open/release (fndfnd--driver.cdriver.c))int iom_fnd_open(struct inode *minode, struct file *mfile) {
if(fnd_usage != 0) return -EBUSY;MOD_INC_USE_COUNT;fnd_usage = 1;
return 0;}
int iom_fnd_release(struct inode *minode, struct file *mfile)
{
MOD_DEC_USE_COUNT;fnd_usage = 0;return 0;
}
문자 디바이스 드라이버 9-33
write (write (fndfnd--driver.cdriver.c))ssize_t iom_fnd_write(struct file *inode, const char
*gdata, size_t length, loff_t *off_what) {const char *tmp = gdata;unsigned char value,cathode = 0xff;int i; unsigned char fnd_buff[5];
copy_from_user(fnd_buff, tmp, length);// 3 bytes receivedfor(i=0; i<6; i++){if(i%2) value=Getsegcode((fnd_buff[i/2]>>4)&0xf);else value=Getsegcode(fnd_buff[i/2]&0xf);value_digit[i]=(unsigned
short)((value<<8)|(cathode&~(0x1<<(5-i))));}queue_task(&Task, &tq_timer); // put in the task queue return length;
}
문자 디바이스 드라이버 9-34
GetsegcodeGetsegcode ((fndfnd--driver.cdriver.c))char Getsegcode(int x){char code;
switch (x) {case 0x0 : code = 0x3f; break;case 0x1 : code = 0x06; break;case 0x2 : code = 0x5b; break;case 0x3 : code = 0x4f; break;case 0x4 : code = 0x66; break;case 0x5 : code = 0x6d; break;case 0x6 : code = 0x7d; break;case 0x7 : code = 0x07; break;case 0x8 : code = 0x7f; break;case 0x9 : code = 0x6f; break;case 0xA : code = 0x77; break;case 0xB : code = 0x7c; break;case 0xC : code = 0x39; break;case 0xD : code = 0x5e; break;case 0xE : code = 0x79; break;case 0xF : code = 0x71; break;default : code = 0; break;}return code;
}
문자 디바이스 드라이버 9-35
display (display (fndfnd--driver.cdriver.c))void iom_fnd_display(void* value){
int i; unsigned short* tmp;tmp =(unsigned short* )value;for(i=0; i<6; i++){
outw(tmp[i],iom_fnd_addr); // fnd outputudelay(1000);
}
if(WaitQ_count){ wake_up_interruptible(&WaitQ_fnd);outw(0x3f,iom_fnd_addr); // fnd turn off
} elsequeue_task(&Task, &tq_timer); // task_queue에 다시 넣음
}
문자 디바이스 드라이버 9-36
FND FND 응용응용 프로그램프로그램 ((fndfnd--app.capp.c))int main(int argc, char **argv){
int dev; unsigned buff;
if((dev=open("/dev/fnds",O_WRONLY))==-1){fprintf(stderr,"can not open /dev/fnds\n");exit(1);
}buff=(unsigned)strtol(&argv[1][0],NULL,16);write(dev,&buff,3);close(dev);return(0);
}
문자 디바이스 드라이버 9-37
MakefileMakefileall: fnd-driver fnd-app
fnd-driver:arm-linux-gcc -Wall -D KERNEL_-DMODULE \-I/home/et1/lab-03/linux-2.4.19-pxa255_pro2/include \-c fnd-driver.c
fnd-app: arm-linux-gcc fnd-app.c -o fnd-app
clean:rm -f *.o fnd-app
문자 디바이스 드라이버 9-38
FND FND 디바이스디바이스 드라이버드라이버 시험시험
• 호스트에서 디바이스 드라이버 프로그램 fnd-driver.c 및 응용 프로
그램 fnd-app.c를 컴파일
• 만들어진 디바이스 드라이버 fnd-driver.o 및 응용 프로그램 fnd-
app를 키트로 download
• 아래 절차에 따라 시험
# mknod /dev/fnds c 241 0
# insmod ./fnd-driver.o
# ./fnd-app 123456
# ./fnd-app 654321
...
# rmmod fnd-driver
문자 디바이스 드라이버 9-39
참고참고 자료자료
• Alessandro Rubini and Jonathan Corbet, Linux Device Drivers, 2nd Edition, Oreilly, http://w
ww.xml.com/ldd/chapter/book, 2001.
• Peter Jay Salzman and Ori Pomerantz, The Linux Kernel Module Programming Guide, 2003-
04-04 Ver 2.4.0, http://www.faqs.org/docs/kernel/
• Skeleton Character Device Driver 코드, http://et.smu.ac.kr/classes/2005-
cm0033/materials/09-skeleton-char-device-driver, 2005
• FND Device Driver Source, http://et.smu.ac.kr/classes/2005-cm0033/materials/ 10-fnd-
driver, 2005.
• (주)휴인스기술연구소, 8.3, 8.6, Intel PXA255와 임베디드 리눅스 응용, 홍릉과학출판사, 2004.
• Alessandro Rubini and Jonathan Corbet, Linux Device Drivers, 2nd Edition, Oreilly, http://w
ww.xml.com/ldd/chapter/book, 2001.
• Peter Jay Salzman and Ori Pomerantz, The Linux Kernel Module Programming Guide, 2003-
04-04 Ver 2.4.0, http://www.faqs.org/docs/kernel, 2003.