디바이스 드라이버 (Device Driver) - 3. file_operations 구조체




3.1 file_operations란?


  • 문자 디바이스 드라이버와 응용 프로그램을 연결하는 고리.
  • linux/fs.h에서 정의하는 이 구조체는 함수 포인터 집합이다.
  • 특정 동작 함수를 구현하여 가리켜야한다.
  • 지정하지 않으면 NULL로 남겨두어야 한다.



3.2 file_operations 구조체 및 필드 설명



  • file_operations 구조체

struct file_operations{

       struct moduel *owner;

       ssize_t (*read) (struct file *, loff_t, int);

       ssize_t (*write) (struct file *, const char *, size_t, loff_t *);

       int (*open) (struct inode *, struct file *);

       int (*release) (struct inode *, struct file *);

       int (*mmap) (struct inode *, struct file *);


       ...


 



  • file_operations 구조체 필드 설명

- struct module *owner;
파일 오퍼레이션의 소유자를 나타낸다. 보통 <linux/module.h>에 정의되어 잇는 THIS_MODULE 매크로를 사용해 초기화 한다.

- loff (*llseek (struct file *, loff_t, int)
디바이스 드라이버의 파이 ㄹ포인터 위치를 강제로 이동시키는 함수를 지정한다.

- ssize_t (*read) (struct file *, char *, size_t, loff_t *);
디바이스에서 자료를 읽는데 사용한다. NULL 이면 -EINVAL 반환

- ssize_t (*write) (struct file *, const char *, size_t, loff_t * );
자료를 디바이스로 보낸다. NULL이면 -EINVAL 반환

- unsigned int (*poll) (struct file *, struct poll_table_struct * );
다중 입출력 처리를 가능하게 해주는 poll, epoll, select의 백엔드이다.

- int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
디바이스 관련 명령들을 제어할 수 있다.

- int (*unlocked_ioctl) (struct file *flip, unsigned int cmd, unsigned long arg);
모든 CPU에서 lock을 걸던 것을 개별적인 lock을 걸 수 있도록 ioctl에서 바꾼 함수.
함수에 진입 시 커널에 대한 락이 처리되어지지 않기 때문에 함수 내에서 별도의 동기화 기법을 사용해야 한다. 이 함수를 부르면 된다.



3.3 file_operations에 연결되는 함수



  • open 함수
디바이스 드라이버가 처음 열렸을 때 하드웨어 초기화
디바이스 드라이버의 동작에 필요한 에러 체크
- -ENODEV 하드웨어가 존재하지 않는다.
- -ENOMEM 커널 메모리가 부족하다.
- -EBUSY 디바이스가 이미 사용 중이다.
minor 번호에 대한 처리가 필요한 경우 file_operations 구조체를 갱신
- 보통 file 구조체 flip의 private_data에 등록하여 사용한다.

  • release 함수
device_close로 부르는 경우도 있다.
open이 flip->private data에 할당한 데이터의 할당 삭제
마지막 close 호출 시 디바이스 종료


  • write 함수

- 주요 매소드

 ssize_t xxx_write (struct file *flip, char *buff, size_t count, loff_t *offp)

  사용자 영역인 buff에서 count 바이트 만큼 읽은 후  디바이스의 offp 위치로 저장


*인자 설명
struct file *flip   읽기와 쓰기에 전달되는 flip은 디바이스 파일이 어떤 형식으로 열렸는가에 대한 정보를 저장
loff_t f_ops        f_pos 필드 변수에는 현재의 읽기/쓰기 위치를 저장




- 데이터 전달 함수

kernel 영역과 user 영역은 서로 접근하지 못하는 메모리 영역이기 때문에, pointer를 이용하지 못하고, 데이터를 전달하는 함수를 이용

 copy_from_user(void *to, void *from, unsigned long size)

 application으로부터 data를 복사한다.

 get_user(x, ptr)

 x 변수에 ptr의 사용자 메모리 값을 대입한다.





  • read 함수

- 주요 매소드

 ssize_t xxx_read (struct file *flip, char * buff, size_t count, loff_t *offp) 

 디바이스의 offp 위치에서 count 바이트만큼을 읽어서 사용자 영역인 buff로 저장해주는 기능



- 데이터 전달 함수

kernel 영역과 user 영역은 서로 접근하지 못하는 메모리 영역이기 때문에, pointer를 이용하지 못하고, 데이터를 전달하는 함수를 이용

copy_to_user(void *to, void *from, unsigned long size)

 application으로 data를 복사해준다.

 put_user(x, ptr)

 x 변수 값을 ptr의 사용자 메모리 값에 대입한다.





  • ioctl 함수


일반적으로 I/O Control에 관련한 작업을 수행하는 함수.

대부분의 ioctl 메소드 구현은 cmd 인수 값에 따라 올바른 동작을 선택하는 switch 문으로 구성한다.


- 사용자 영역에서 ioctl 함수 시스템 콜


int ioctl (int fd, int cmd, ...);



- 커널 영역에서 ioctl 함수


int (*unlocked_ioctl) (struct file *flip, unsiged int cmd, unsigned long arg);


- inode와 flip 포인터는 응용 프로그램의 파일 디스크립터 fd와 일치하는 인수

- cmd 인수는 명령을 나타내는 응용 프로그램의 인수 전달

- arg 인수는 명령 실행의 결과 데이터가 전달되는 unsigned long 형의 정수 또는 포인터


- cmd의 구성


총 32 bit로, 

[0:1] 읽기/쓰기 구분

[2:15] 데이터 크기

[16:23] 매직넘어

[24:31] 구분 번호



- cmd 명령의 해석 매크로 함수



 _IOC_NR

 구분 번호 필드 값을 읽는 매크로 

 _IOC_TYPE

 매직 넘버 필드 값을 읽는 매크로 

 _IOC_SIZE

 데이터의 크기 필드 값을 읽는 매크로 

 _IOC_DIR

 읽기와 쓰기 속성 필드 값을 읽는 매크로 



(예) if ( _IOC_TYPE(cmd) != MY_MAGIC ) return -EINVAL;



- cmd 명령의 작성 매크로 함수



 _IO 

 부가적인 데이터가 없는 명령을 만드는 매크로 

 _IOR

 데이터를 읽어오기 위한 명령을 작성 

 _IOW

 데이터를 써 넣기 위한 명령을 작성 

 _IOWR

 디바이스 드라이버에서 읽고 쓰기 위한 명령을 작성하는 매크로 



(예) _IOW (매직넘버, 구분번호, 정수형








+ Recent posts