강의 PPT - 수원과학대학교 정보통신과

Report
13주차. 디바이스 드라
이버 기초
수원과학대학교 정보통신과
13.1 디바이스 드라이버의 개요

디바이스 (device)


디바이스 드라이버 (device driver)


디바이스 구동 프로그램
디바이스의 종류




컴퓨터시스템의 주변 하드웨어
문자 디바이스(character device)
블록 디바이스(block device)
네트워크 디바이스(network device)
여러 디바이스들의 구별


주번호(major number)와 부번호(minor number)로 서로 구별
동일한 디바이스는 동일한 주번호를 가지며 부번호로 구별
수원과학대학 정보통신과
2
디바이스의 종류 [1]

문자 디바이스
 데이터를
문자 단위 또는 연속적 바이트 흐름으로 전달
하고 읽음.
 데이터의 순차성을 지닌 하드웨어로 버퍼 캐시를 사용
하지 않음.
 주로 직렬 또는 병렬 인터페이스에 의해 전달
 예: 터미널, 콘솔, 키보드, 사운드카드, 스캐너, 프린터,
직렬/병렬 포트, 마우스, 조이스틱 등
수원과학대학 정보통신과
3
디바이스의 종류 [2]

블록 디바이스
 데이터를
블록 단위로 입출력하여 효율성을 향상시키
기 위해 버퍼 이용
 버퍼 캐시를 통해 임의 접근(random access)이 가능함
 블록의 크기를 관리하고 블록 데이터의 전달을 담당하
는 기능이 있음
 예: 하드디스크, 플로피 디스크, 램디스크, CD-ROM,
DVD 등
수원과학대학 정보통신과
4
디바이스의 종류 [3]

네트워크 디바이스
 문자열이
아닌 패킷 단위로 접근
 네트워크 통신을 통해 네트워크 패킷을 송수신할 수
있는 디바이스
 예: 이더넷, PPP, SLIP, ATM, 네트워크 인터페이스 카
드
수원과학대학 정보통신과
5
디바이스 파일



리눅스 시스템은 디바이스를 /dev 디렉토리에 있는 일종
의 파일로 취급. 즉, 디바이스를 파일로 추상화
디바이스 파일은 사용자에게 보이는 디바이스 드라이버
의 인터페이스 부분
디바이스 파일은 파일시스템의 데이터 영역을 차지하지
않음




일반 파일은 데이터를 쓰면 데이터를 보존하여 크기가 증가하지
만 디바이스 파일은 보존하지 않고 디바이스로 데이터를 전달
응용 프로그램은 디바이스에 접근하기 위하여 열기, 읽기,
쓰기 등과 같은 파일 연산을 이용
디바이스 파일은 파일시스템에서 고유한 번호와 이름을
할당받음
문자 디바이스와 블록 디바이스만 디바이스 파일 이용
수원과학대학 정보통신과
6
호스트 시스템의 디바이스 파일 관찰
1.
호스트 시스템의 디바이스 파일이 있는 /dev 디
렉토리 내용관찰
①
②
수원과학대학 정보통신과
7

문자나 블록 디바이스 파일의 생성



디바이스 파일은 /dev 에서 관리
디바이스 파일 형식: 문자형 c , 블록형 b
리눅스에서 사용되는 디바이스 파일의 주번호
수원과학대학 정보통신과
8
mknod 명령으로 디바이스 파일 생성
1.
디바이스 파일을 생성하고 세부 내용 관찰
②
①
②
①
디바이스 이름이 hello, 주번호 250, 부번호 0인 문자
디바이스 파일 생성
디바이스 리스트 중에서 h로 시작하는 디바이스 세부
내용 확인
수원과학대학 정보통신과
9
디바이스 드라이버


디바이스 하드웨어에 데이터를 읽거나 쓰거나 제어하기 위한 프로그
램 루틴의 집합체
운영체제와 연동되며 운영체제가 하드웨어를 제어할 수 있도록 인터
페이스를 제공


커널이 직접 하드웨어를 제어하지 않고 디바이스 드라이버를 통해 하드
웨어 제어
응용 프로그램에서 디바이스에 접근하기

디바이스 파일에 입출력을 요청  시스템 호출을 통해 커널에서 디바이
스 드라이버로 전달  디바이스 드라이버가 하드웨어 제어
수원과학대학 정보통신과
10
13.2 파일 입출력
 파일
입출력 함수
저수준 파일 입출력 함수
스트림 파일 입출력함수
접근 형태
직접 접근
형식화된 형태로 접근, 사용하기 쉬움
버퍼 사용 유무
사용 않음
버퍼를 사용
디바이스 파일 다루기
가능
곤란
디바이스 드라이버 구현
사용
사용 불가
종류
open(), read(),
write(), close(),
fsync(),ioctl(),
poll(), mmap() 등
fopen(), fread(),
fwrite(), fclose() 등
수원과학대학 정보통신과
11
저수준 파일 입출력 함수 [1]
int open(const char *filename, int flags)
기능
파일을 열어 사용할 수 있게 한다.
인자
filename: 일반파일 또는 장치파일 이름
flags: 파일을 여는 방법을 지정하는 플래그로, OR 연산자로 중복지정가능
- O_RDONLY (읽기전용), O_WRONLY (쓰기전용), O_RDWR (읽고쓰기)
- O_NONBLOCK (비블록모드), O_NDELAY (비지연)
반환값
성공하면 열기에 성공한 파일의 파일기술자를 반환
실패하면 -1을 반환
int close(int fd)
기능
열린 파일을 닫는다.
인자
fd: 파일기술자
반환값
성공하면 0, 실패하면 -1을 반환
수원과학대학 정보통신과
12
저수준 파일 입출력 함수 [2]
ssize_t read(int fd, void *buf, size_t count)
기능
파일로부터 데이터를 count 바이트만큼 읽어서 buf 메모리에 저장한다.
인자
fd: 읽고자하는 파일의 파일기술자
buf: 데이터를 저장할 메모리의 주소
count: 읽을 바이트 수
반환값
성공하면 읽어 들인 바이트 수를 반환하며, 실패하면 -1을 반환
ssize_t write(int fd, void *buf, size_t count)
기능
buf 메모리로부터 데이터를 count 바이트만큼 읽어 파일에 기록한다.
인자
fd: 쓰고자하는 파일의 파일기술자
buf: 데이터를 읽을 메모리의 주소
count: 쓸 바이트 수
반환값
성공하면 쓴 바이트 수를 반환하며, 실패하면 -1을 반환
수원과학대학 정보통신과
13
저수준 파일 입출력 함수 [3]
off_t lseek(int fd, off_t offset, int whence)
기능
파일에서 읽고쓸 지점의 위치를 이동한다.
인자
fd: 위치를 이동하고자 파일의 파일기술자
offset: 이동 기준점으로부터 이동할 바이트 수
whence: 이동 기준점을 지정하는 것으로 다음 세가지가 있음
- SEEK_SET: 파일의 맨 처음이 기준
- SEEK_CUR: 현재 위치가 기준
- SEEK_END: 파일의 맨 끝이 기준
반환값
성공하면 이동한 위치를 반환, 실패하면 -1을 반환
수원과학대학 정보통신과
14
저수준 파일 입출력 함수 [4]
int ioctl(int fd, int request, ...)
기능
입출력 장치의 제어를 위해 사용되는 함수로, 장치에 접근해서 장치 정보를
얻어오거나, 장치의 값을 변경하기 위한 용도로 사용한다.
인자
fd: 제어하고자 하는 장치의 파일기술자
request: ioctl()로 요청할 정보를 지정함
...: 어떤 입출력장치에 대한 제어인가에 따라 달라진다. 그러므로 ioctl()을 제
대로 사용하기 위해서는 필요한 정보를 얻어오기 위한 request와 request에
대해서 넘겨주는 데이터(대부분 구조체)에 대해서 알고 있어야 한다. request
가능한 목록은 "man ioctl_list"로 확인해 볼 수 있다. request의 목록이 정
의된 헤더 파일은 /usr/include/bits/ioctls.h 이다.
반환값
성공하면 쓴 바이트 수를 반환하며, 실패하면 -1을 반환
수원과학대학 정보통신과
15
file 구조체

디바이스 드라이버를 구현할 때 사용하며 커널에서만 사용

응용 프로그램에서 사용하는 C 라이브러리의 FILE과 다름
<kernel>/include/linux/fs.h에 정의

01 struct file {
02
struct dentry f_dentry;
03
struct vfsmount *f_vfsmnt;
04
struct file_operations f_op;
05
atomic_t f_count;
06
unsigned int f_flags;
07
mode_t f_mode;
08
loff_t f_pos;
09
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
10
struct fown_struct f_owner;
11
unsigned int f_uid, f_gid;
12
int f_error;
13
unsigned long f_version;
14
void *private_data;
15 };
수원과학대학 정보통신과
16
파일 연산 구조체 [1]

커널은 등록된 디바이스 드라이버의 파일 연산 구조체를
참고해 응용프로그램의 요청에 대응하는 함수 호출

<kernel>/include/linux/fs.h에 정의
01 struct file_operations {
02
struct module *owner;
03
loff_t (*lseek) (struct file *, loff_t, int);
04
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
05
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
06
int (*readdir) (struct file *, void *, filldir_t);
07
unsigned int (*poll) (struct file *, struct poll_table_struct *);
08
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned
long);
09
int (*mmap) (struct file *, struct vm_area_struct *);
10
int (*open) (struct inode *, struct file *);
11
int (*release) (struct inode *, struct file *);
12
int (*fsync) (struct file *, struct dentry *);
13
int (*fasync) (int, struct file *, int);
14
int (*check_media_change) (kdev_t dev);
15
int (*revalidate) (kdev_t dev);
16
int (*lock) (struct file *, int, struct file_lock *);
17 };
수원과학대학 정보통신과
17
파일 연산 구조체 [2]
 문자
디바이스 드라이버의 파일 연산 구조체 사용
 파일
연산 구조체에서 사용하지 않는 필드는 NULL로
선언되므로 필요한 필드만 선언하면 됨
 전형적인 파일 연산 구조체의 선언내용

xxx는 일반적으로 디바이스의 이름
struct file_operations xxx_fops = {
.owner = THIS_MODULE,
.open = xxx_open,
.release = xxx_release,
.read = xxx_read,
.write = xxx_write,
.ioctl = xxx_ioctl,
};
수원과학대학 정보통신과
18
13.3 디바이스 드라이버의 등록과 해제 [1]


디바이스 드라이버를 동작시키려면 커널에 디바
이스의 특성에 맞는 형식으로 등록해야 함
문자 디바이스의 등록과 해제
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops)
int unregister_chrdev(unsigned int major, const char *name)



major : 주번호로, 0이면 사용하지 않는 주번호 중에서 동적으로
할당
name : 디바이스의 이름으로 /proc/devices에 나타나 있음
반환값 : 오류 코드. 반환값이 0이거나 양수이면 성공적인 수행.
음수이면 오류 발생.
수원과학대학 정보통신과
19
디바이스 드라이버의 등록과 해제 [2]

블록 디바이스의 등록과 해제
int register_blkdev(unsigned int major, const char *name)
int unregister_blkdev(unsigned int major, const char *name)




major : 주번호로, 0이면 사용하지 않는 주번호 중에서 동적으로
할당
name : 블록 디바이스 장치 이름
반환값 : 오류 코드. 0이나 양수이면 성공적인 수행. 음수이면 오
류 발생
네트워크 디바이스의 등록과 해제
int register_netdev(struct net_device *dev)
void unregister_netdev(struct net_device *dev)


dev : net_device 구조체 이름
반환값 : 등록에 성공하면 0. 실패하면 0이 아닌 값을 반환
수원과학대학 정보통신과
20
문자 디바이스 드라이버의 등록 과정
커널의 chrdevs[]에 등록
문자 디바이스를 관리하는 구조체
디바이스 드라이버의 초기화 함수 호출
Shell에서 실행
수원과학대학 정보통신과
21
13.4 디바이스 드라이버 구성

01
02
03
04
05
06
전형적인 문자 디바이스 드라이버
#include
#include
#include
#include
<linux/module.h>
<linux/kernel.h>
<linux/fs.h>
<linux/init.h>
21
22
23
24
25
26
27
28
struct file_operations test_fops =
{
.owner
= THIS_MODULE,
.open
= test_open,
.release = test_release,
};
int test_init(void)
#define TEST_DEV_NAME
"test_dev"
// 디바이스를 커널에 모듈로 적재시 수행되는 함수
// 디바이스 파일 이름
29 {
30
register_chrdev(TEST_DEV_MAJOR,
07 #define TEST_DEV_MAJOR
240
TEST_DEV_NAME,
&test_fops);
// 디바이스 파일의 주번호
31
………(초기화 처리)……
08
32
return 0;
09 int test_open(struct inode *inode,
33
}
struct file *filp)
34
10 {
35 void test_exit(void)
11
………(open 처리)……
// 커널에서 디바이스를 제거할 때 수행되는 함수
12
return 0;
36 {
13 }
37
………(마무리 처리)……
14
38
unregister_chrdev(TEST_DEV_MAJOR,
15 int test_release(struct inode
TEST_DEV_NAME);
*inode, struct file *filp)
39 }
40
16 {
41 MODULE_LICENSE("GPL");
17
………(close 처리)……
42 module_init(test_init);
18
return 0;
43 module_exit(test_exit);
19 }
20
22
수원과학대학 정보통신과
수원과학대학 정보통신과
23
타겟 보드의 파일 시스템 초기화

호스트에서
 cp

/embed/hybus/images/rootfs.img /tftpboot
타겟에서
 hybus>
tftp rootfs.img root
 hybus> flash root
수원과학대학 정보통신과
24
실습 13-1 가상 디바이스 드라이버 구현
가상 문자 디바이스 드라이버 프로그램 작성(13/chr_dev.c)
1.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
#include
#include
#include
#include
<linux/module.h>
<linux/kernel.h>
<linux/fs.h>
<linux/init.h>
#define CHR_DEV_NAME "chr_dev" // 디바이스 파일 이름
#define CHR_DEV_MAJOR 240 // 디바이스 파일의 주번호
static char gbuf[1024];
static int mode = 0;
// 0: 정상순서, 1: 역순
int chr_open(struct inode *inode, struct file *filp)
{
int number = MINOR(inode->i_rdev); // 부번호를 number에 저장
printk(“Virtual Character Device Open: Minor Number is
%d\n", number);
16
return 0;
17 }
18
수원과학대학 정보통신과
25
19 ssize_t chr_write(struct file *filp, const char *buf, size_t count,
loff_t *f_pos)
20 {
21
if (mode == 0) strncpy(gbuf, buf, count);
22
else {
23
int i, j, size;
24
if (count > sizeof(gbuf))
size = sizeof(gbuf);
25
else
size = count;
26
for (i=size-1, j=0; i>=0; i--, j++) gbuf[j] = buf[i];
27
gbuf[j] = '\0';
28
}
29
printk("write data: %s\n", gbuf);
30
return count;
31 }
32
33 ssize_t chr_read(struct file *filp, const char *buf, size_t count,
loff_t *f_pos)
34 {
35
strncpy(buf, gbuf, count);
36
printk("read data: %s\n", buf);
37
return count;
38 }
39
수원과학대학 정보통신과
26
40 int chr_ioctl(struct inode *inode, struct file *filp, unsigned int
cmd, unsigned long arg)
41 {
42
switch(cmd) {
43
case 0: mode = 0; break; // 정상순서
44
case 1: mode = 1; break; // 역순
45 }
46
return 0;
47 }
48
49 int chr_release(struct inode *inode, struct file *filp)
50 {
51
printk("Virtual Character Device Release\n");
52
return 0;
53 }
54
55 struct file_operations chr_fops =
56 {
57
.owner = THIS_MODULE,
58
.ioctl = chr_ioctl,
59
.write = chr_write,
60
.read = chr_read,
61
.open = chr_open,
62
.release = chr_release,
63 };
64
수원과학대학 정보통신과
27
65 int sample_init(void) //디바이스를 커널에 모듈로 적재시 수행되는함수
66 {
67
int registration; // registration에 주번호나 반환값을 저장
68
printk("Registration Character Device to Kernel\n");
69
registration =
register_chrdev(CHR_DEV_MAJOR,CHR_DEV_NAME,&chr_fops);
70
if (registration < 0)
71
return registration;
72
printk("Major Number:%d\n", registration);
73
return 0;
74 }
75
76 void sample_cleanup(void) //커널에서 디바이스를 제거할 때 수행되는
함수
77 {
78
printk("Unregistration Character Device to Kernel\n");
79
unregister_chrdev(CHR_DEV_MAJOR, CHR_DEV_NAME);
80 }
81
82 MODULE_LICENSE("GPL");
83 module_init(sample_init);
84 module_exit(sample_cleanup);
수원과학대학 정보통신과
28
실습 13-1 가상 디바이스 드라이버 구현
② Make
유틸리티를 실행해 모듈 생성
수원과학대학 정보통신과
29
③
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
30
31
가상 문자 디바이스를 사용하는 응용프로그램 작성(13/chr_appl.c)
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<fcntl.h>
<sys/ioctl.h>
<unistd.h>
//
//
//
//
//
#define DEVICE_FILE_NAME "/dev/chr_dev"
int main(int argc, char *argv[])
{
int device;
char rbuf[128];
printf(), perror()
atoi()
open()
ioctl()
read(), write()
// 디바이스 파일
// argv[1] 값을 받아 디바이스에 저장
device = open(DEVICE_FILE_NAME, O_RDWR|O_NDELAY);
if (device >= 0) {
printf(“200014000 Device file Open\n");
ioctl(device, 0);
// 정상 순서 모드
printf("Normal order: \n");
write(device, argv[1], 128); // argv[1] 값을 디바이스 파일에 전달
read(device, rbuf, 128);
printf("Read data: %s\n", rbuf);
ioctl(device, 1);
// 역순 모드
printf("Reverse order: \n");
write(device, argv[1], 128); // argv[1] 값을 디바이스 파일에 전달
read(device, rbuf, 128);
printf("read value is %s\n", rbuf);
}
else
perror("Device file open fail");
return 0;
}
수원과학대학 정보통신과
30
실습 13-3 가상 디바이스 드라이버 구현
④
응용프로그램을 타겟 시스템용으로 교차 컴파일
디바이스 드라이버 모듈 chr_dev.ko 파일과 컴파일한 응
용 프로그램 chr_appl을 타겟 시스템으로 전송
⑥ 디바이스 드라이버 모듈을 적재하고 적재 여부 확인
⑤
①
②
수원과학대학 정보통신과
31
실습 13-1 가상 디바이스 드라이버 구현
⑦
디바이스 파일을 만들고 확인
⑧
응용 프로그램 실행
[[email protected] ~]# ./chr_appl hello
200014000 Device file open
Normal order:
Read data: hello
Reverse order:
Read data: olleh
⑨
커널에서 디바이스 드라이버 모듈 제거
[[email protected] ~]# rmmod chr_dev
수원과학대학 정보통신과
32
실습문제

1. [코드 13-4]의 가상 문자 디바이스 드라이버에 다음과 같은 모드를
추가하시오.



mode = 2: 정상순서로 대문자로 바꿔서 저장
mode = 3: 역순으로 대문자로 바꿔서 저장
테스트 프로그램으로 다음과 같은 결과가 얻어짐을 확인하시오.
수원과학대학 정보통신과
33

similar documents