노무현 대통령 배너


2006. 3. 22. 13:17

[본문스크랩] register_chrdev()상세 설명

register_chrdev()상세 설명
글쓴이 : 박철 (2002년 12월 28일 오후 12:25) 읽은수: 1,996 [ 임베디드강좌/박철 인쇄용 페이지 ]
이번 강좌는 커널 함수인 register_chrdev()를 다루고자 한다.
이 함수의 기능은 커널 내부에 등록된 문자장치를 관리하는 chrdev[] 배열구조체에서 하나의 배열을 할당을 받고, 그 배열 안의 필드에 각각의 문자장치의 이름과 파일 오퍼레이션을 연결하는 것이다. 이렇게 함으로써 해당하는 커널내부에 문자장치로 등록이 되며 이 장치를 사용하고자 하는 어플리케이션이 있을 때 이를 사용할 수 있도록 한다.

아래는 커널 내에서 정의된 chrdevs[]에 관련된 구조체와 관련된 내용이다. 문자 장치는 256개 배열의 형태로 등록이 될 수 있으며 이러한 배열의 각각은 문자장치의 이름을 나타내는 포인터와 이문자 장치를 사용할 수 있는 파일 오퍼레이션의 포인터를 포함한다.

http://lxr.hybus.net/source/fs/devices.c?a=arm#L39
39 static struct device_struct chrdevs[MAX_CHRDEV];

http://lxr.hybus.net/source/include/linux/major.h?a=arm#L15
15 #define MAX_CHRDEV 255

http://lxr.hybus.net/source/fs/devices.c?a=arm#L33
33 struct device_struct {
34 const char * name;
35 struct file_operations * fops;
36 };

보통 register_chrdev() 함수는 모듈이 적재될 때 실행되는init_module()함수내부에 있어서 커널이 부팅되거나, 모듈로 적재될 때 커널내부에 있는 배열 구조체인 chrdev[]에 등록되도록 하는 것이다.

여기서 예로든 파일은 gpio.c이며 다음과 같이 init_module()내부에서 사용되었다.

http://www.hybus.net/lecture/lecture_2.php
result = register_chrdev(gpio_major, "GPIO", &gpio_fops);

여기서 첫번째 인자인 gpio_major는 배열chrdev[]의 순서를 결정하는 major번호를 의미하며, 두번째 인자는 등록될 문자장치의 이름을 의미한다. 그리고 마지막 인자는 사용되어질 파일 오퍼레이션을 위한 함수 포인터를 의미한다. 이 세 번째 인자는 gpio.c에 있는 아래의 자료구조에 사용되어질 함수의 주소 값이 등록된다.

struct file_operations gpio_fops = { // 파일 구조체 정의
read: gpio_read,
write: gpio_write,
open: gpio_open,
release: gpio_release,
};


아래는 커널함수인 register_chrdev()의 원형을 나타낸 것이다.

http://lxr.hybus.net/source/fs/devices.c?a=arm#L98
98 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
99 {

1. 첫번째 인자, major가 0이면 자동 할당을 의미한다.

100 if (major == 0) {
101 write_lock(&chrdevs_lock);

2. major번호가 높은 순서로 할당되지 않은 chrdev[]배열 구조체를 찾아서 찾은 배열의 구조체의 필드인 chrdevs[major].name은 두번째 인자인 name의 값을 받으며, chrdevs[major].fops은 세번째 인자인 fops의 주소 값을 받는다. 그리고 리턴 값으로 할당된 major를 돌려 준다.
Gpio.c에 정의된 내용과 같은 경우에는 major가 0이므로 자동할당 시에 큰 번호(255)부터 스캔을 해나가면서 등록되지 않은 배열의 값을 major로 할당하며 이값을 리턴한다. 이때 등록되는 문자장치의 이름은 GPIO이며, 등록되는 문자장치를 위한 파일 오퍼레이션은 gpio_fops이 되는 것이다.

102 for (major = MAX_CHRDEV-1; major > 0; major--) {
103 if (chrdevs[major].fops == NULL) {
104 chrdevs[major].name = name;
105 chrdevs[major].fops = fops;
106 write_unlock(&chrdevs_lock);
107 return major;
108 }
109 }
110 write_unlock(&chrdevs_lock);
111 return -EBUSY;
112 }

3. major값이 MAX_CHRDEV(255)보다 큰 경우에는 에러처리한다.

113 if (major >= MAX_CHRDEV)
114 return -EINVAL;
115 write_lock(&chrdevs_lock);

4. 아래는 major값이 0 보다 크고 MAX_CHRDEV(255)보다 작은 경우에 실행되는 코드이다.

chrdevs[major].fops가 0이 아니거나, chrdevs[major].fops가 세번째 인자인fops 같지 않은 경우에는 -EBUSY를 가지고 반환한다.
116 if (chrdevs[major].fops && chrdevs[major].fops != fops) {
117 write_unlock(&chrdevs_lock);
118 return -EBUSY;
119 }

5. chrdev[]배열 구조체의 해당하는 major번호와 일치하는 배열의 구조체의 필드인 chrdevs[major].name은 두번째 인자인 name의 값을 받으며, chrdevs[major].fops은 세번째 인자인 fops의 주소 값을 받는다. 그리고 리턴 값으로 0을 돌려 준다.

120 chrdevs[major].name = name;
121 chrdevs[major].fops = fops;
122 write_unlock(&chrdevs_lock);
123 return 0;
124 }

첨부 파일: register_chrdev.JPG register_chrdev.JPG (100 KiB(102,357 Bytes))

[Image Size 995 x 714]
register_chrdev.JPG