리눅스/디바이스 드라이버

리눅스/드라이버 register_chrdev() 함수

우진샘 2009. 6. 22. 16:13
register_chrdev()

이 함수의 기능은 커널 내부에 등록된 문자장치를 관리하는 chrdev[] 배열구조체에서 하나의 배열을 할당을 받고, 그 배열 안의 필드에 각각의 문자장치의 이름과 파일 오퍼레이션을 연결하는 것이다. 이렇게 함으로써 해당하는 커널내부에 문자장치로 등록이 되며 이 장치를 사용하고자 하는 어플리케이션이 있을 때 이를 사용할 수 있도록 한다.
아래는 커널 내에서 정의된 chrdevs[]에 관련된 구조체와 관련된 내용이다. 문자 장치는 256개 배열의 형태로 등록이 될 수 있으며 이러한 배열의 각각은 문자장치의 이름을 나타내는 포인터와 이문자 장치를 사용할 수 있는 파일 오퍼레이션의 포인터를 포함한다.

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

int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)

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


#define MAX_CHRDEV 255

struct device_struct {
    const char * name;
    struct file_operations * fops;
};

static struct device_struct chrdevs[MAX_CHRDEV];

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

int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
{
    1. 첫번째 인자, major가 0이면 자동 할당을 의미한다.
    if (major == 0) {
        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이 되는 것이다.
        for (major = MAX_CHRDEV-1; major > 0; major--) {
            if (chrdevs[major].fops == NULL) {
                chrdevs[major].name = name;
                chrdevs[major].fops = fops;
                write_unlock(&chrdevs_lock);
                return major;
            }
        }
        write_unlock(&chrdevs_lock);
        return -EBUSY;
    }

    3. major값이 MAX_CHRDEV(255)보다 큰 경우에는 에러처리한다.
    if (major >= MAX_CHRDEV)
        return -EINVAL;

    write_lock(&chrdevs_lock);

    4. 아래는 major값이 0 보다 크고 MAX_CHRDEV(255)보다 작은 경우에 실행되는 코드이다. chrdevs[major].fops가 0이 아니거나, chrdevs[major].fops가 세번째 인자인fops 같지 않은 경우에는 -EBUSY를 가지고 반환한다.
    if (chrdevs[major].fops && chrdevs[major].fops != fops) {
        write_unlock(&chrdevs_lock);
        return -EBUSY;
    }

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

'리눅스 > 디바이스 드라이버' 카테고리의 다른 글

리눅스/메모리 매핑(memory mapping)  (0) 2010.07.06