안드로이드환경에서의 리눅스디바이스드라이버 문자디바이스드라이버설명
Table of contents 디바이스드라이버구조 시스템구조 모듈의기본골격 드라이버 IO 제어
안드로이드환경에서의 한백전자교육사업부 리눅스디바이스드라이버
시스템구조 쉘 응용프로그램 표준라이브러리 시스템콜 가상파일시스템 (VFS) 버퍼캐시 네트워크시스템 문자디바이스드라이버 블럭디바이스드라이버 네트워크디바이스드라이버 하드웨어
모듈 커널의런타임에커널영역의코드를추가 개발시간단축 컴파일시간단축 쉬운커널확장 최적화된커널생성 디바이스사용시해당드라이버추가 디바이스드라이버도모듈형태
커널내부의모듈관리 복잡한커널구조 개발의어려움 외부모듈객체화 ( 외부참조심볼선언 ) 예 : 모듈프로그램, 디바이스드라이버프로그램 모듈로딩시 커널의심볼테이블 ( 외부변수나함수의주소 ) 에등록 $ cat /proc/kallsyms 시스템콜을통해모듈객체를커널에링킹 동적라이브러리의동작과유사
모듈의기본골격 1. #include <linux/init.h> 2. #include <linux/module.h> 3. #include <linux/kernel.h> 4. 5. int init(void) { 6. printk ("hello, I'm module\n"); 7. return 0; 8. } 9. 10. void exit(void) { 11. printk("good bye!\n"); 12. } 13. 14. module_init (init); 15. module_exit (exit); 16. 17. MODULE_AUTHOR ("hanback"); 18. MODULE_DESCRIPTION ("hello module"); 19. MODULE_LICENSE ("Dual BSD/GPL");
Module Makefile 형식 CC = arm-linux-gcc # 소스를컴파일할컴파일러 ($PATH 에추가되어있음 ) obj-m := module.o # 모듈로컴파일후생성될드라이버파일이름지정 KDIR := /working/linux-2.6.35-hanback # 헤더를참조할커널소스의최상위경로지정 PWD := $(shell pwd) # make 명령을실행시현재경로지정 default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules rm -f default clean: rm -f *.ko rm -f *.o rm -f *.mod.* rm -f.*.cmd 1. 모든실행명령전은반드시tab키 2. $(MAKE) modules : 정의된메크로들을이용하여모듈컴파일명령 3. -C $(KDIR) : 커널소스로 make 프로세스의경로을이동후컴파일 4. SUBDIRS : 컴파일전참조파일과컴파일후생성파일의경로
커널링크와언링크명령 # insmod module.ko Using module.ko hello, I'm module # lsmod Module Size Used by module 1280 0 - Live 0xbf071000 uvcvideo 41828 0 - Live 0xbf065000 camera 171120 0 - Live 0xbf03a000 mcf25 218656 0 - Live 0xbf003000 cfio 6308 2 mcf25, Live 0xbf000000 # rmmod module Good bye!
디바이스파일 리눅스는모든자원을파일형식으로표현 # ls l /dev 디바이스파일의형식 디바이스타입정보 주번호 (major number) 부번호 (minor number) 디바이스파일생성명령 mknod [ 디바이스명 ] [ 디바이스파일형 ] [ 주번호 ] [ 부번호 ] # mknod /dev/ledioport c 240 1
디바이스드라이버제어방식 응용프로그램 : 하드웨어제어를장치파일을통해접근 장치파일 : 커널파일시스템구조에의해 H/W 제어루틴과연결 디바이스드라이버 : 응용의 H/W 제어요청에응답 사용자공간 커널공간 응용프로그램 저수준파일입출력함수 open( ) 장치파일 파일처리시스템콜 led_ioport( ) 디바이스드라이버 하드웨어
응용의시스템콜과드라이버함수의연결 디바이스드라이버 장치파일내의주번호로파일오퍼레이션구조체와연결 insmod 응용프로그램 led_init ( ) { register_chrdev( ) } 디바이스등록함수 register_chrdev( ) 호출시커널에서생성 oepn ( /dev/led ) read ( ) write ( ) close ( ) ioctl ( ) struct file_operations led_fop = { open : led_open, read : led_read, write : led_write, release : led_release, ioctl : led_ioctl } ; led_open ( ) {.. } led_read ( ) {.. } {.. } {.. } led_write ( ) led_release( ) led_ioctrl ( ) {.. } rmmod led_exit ( ) { unregister_chrdev( ) } 디바이스제거함수 unregister_chrdev( ) 호출시커널에서제거
드라이버초기화및해제 c 언어의 main( ) 역활 디바이스드라이버 # insmod lodioport.ko # rmmod lodioport
디바이스드라이버등록 / 초기화와해제 / 종료 문자디바이스드라이버함수와응용프로그램시스템콜함수를연결하는고리 file_oprations 필드 struct module *owner; linux/include/fs.h - 구조체의사용자를나타냄. - 디바이스드라이버의사용횟수를커널에서관리하기때문에이필드를지정 - 보통 THIS_MODULE 을지정 ssize_t (*read) (struct file*, char user *, size_t, loff_t *); - 디바이스드라이버의읽기를구현하는함수를지정 - NULL 을지정하면응용에서디바이스파일에 READ 함수를수행 - 반환값은항상 EINVAL 이다 ssize_t (*write) (struct file*, char user *, size_t, loff_t *); - 디바이스드라이버의쓰기를구현하는함수를지정 - NULL 을지정하면응용프로그램에서디바이스파일에 write 함수를수행 - 반환값은항상 EINVAL
디바이스드라이버등록 / 초기화와해제 / 종료 file_oprations 사용빈도가높은필드 int (*open) (struct inode *, struct file *) - 응용프로그램에서디바이스를처음사용하는경우를처리하는함수를지정 int (*release) (struct inode *, struct file *); - 응용프로그램에서디바이스를더이상사용하지않아서닫기를구현하는함수를지정 int (*ioctl) (struct inode *, struct file*, unsigned int, unsigned long); - read( ) 와 write( ) 로구현하기곤란한디바이스드라이버의입출력처리를구현하는함수를지정 - NULL 을지정하면응용프로그램에서디바이스파일에 ioctl( ) 함수를수행 - 반환값은항상 EINVAL 이다. int (*mmap) (struct file *, sturct vm_area_struct *); - 하드웨어의메모리를프로세스의메모리에매핑시키는함수를지정. -NULL 을지정하면응용프로그램에서디바이스파일에 mmap( ) 함수를수행하며 - 반환값은항상 ENODEV 이다.
디바이스드라이버 IO 제어 응용프로그램 디바이스드라이버
디바이스드라이버 IO 제어 read 함수의구현 fd = open ( const char *pathname, int flags ); ret = read ( int fd, void *buf, size_t count ); ssize_t led_read ( struct file *filp, char *buf, size_t count, loff_t *f_pos ) {... return ret; } 읽기와쓰기에전달되는 file 구조체의선두주소 open() 의 Lvalue 의 fd 를넘기면커널에의해할당됨 struct file { struct file_operations *f_op; // 부번호처리시참조 unsinged int f_flags; // open() 에서넘긴 flags저장 loff_t f_pos; // 파일포인터 }
디바이스드라이버 IO 제어 write 함수의구현 fd = open ( const char *pathname, int flags ); ret = write ( int fd, void *buf, size_t count ); ssize_t led_write ( struct file *filp, char *buf, size_t count, loff_t *f_pos ) {... return ret; }
디바이스드라이버 IO 제어 struct file *filp 구조체 열린파일을나타냄 드라이버코드에서사용가능 열린파일은해당 file 구조체가커널에존재 Open함수수행시커널이생성 Close함수수행시커널이자료구조해제 struct file *Filp
디바이스드라이버 IO 제어 <Include/linux/fs.h> 576 struct file { 577 struct list_head f_list; 578 struct dentry *f_dentry; 579 struct vfsmount *f_vfsmnt; 580 struct file_operations *f_op; 581 atomic_t f_count; 582 unsigned int f_flags; 583 mode_t f_mode; 584 int f_error; 585 loff_t f_pos; 586 struct fown_struct f_owner; 587 unsigned int f_uid, f_gid; 588 struct file_ra_state f_ra; 589 590 size_t f_maxcount; 591 unsigned long f_version; 592 void *f_security; 593 594 /* needed for tty driver, and maybe others */ 595 void *private_data; 596 597 #ifdef CONFIG_EPOLL 598 /* Used by fs/eventpoll.c to link all the hooks to this file */ 599 struct list_head f_ep_links; 600 spinlock_t f_ep_lock; 601 #endif /* #ifdef CONFIG_EPOLL */ 602 struct address_space *f_mapping; 603 };
디바이스드라이버 IO 제어 IO 영역의경쟁처리 디바이스드라이버간의충돌을방지 인터럽트, DMA 자원을관리하는함수제공 I/O영역을관리 I/O포트접근방식 (x86) 메모리와주변기기의주소영역을분리하여사용 I/O 포트용읽기신호선과쓰기신호선이따로있음 I/O 포트에접근하는명령어가별도로있음. I/O 메모리접근방식 (arm)
디바이스드라이버 IO 제어 I/O 포트함수 request_region ( ) release_region ( ) check_region ( ) I/O 메모리함수 request_mem_region ( ) Release_mem_region ( ) check_mem_region ( ) volatile unsigned char *iob; // 8비트 i/o 처리용포인터변수 volatile unsigned char *iow; // 16비트 volatile unsigned char *iol; // 32비트 *iob=0xff; *iow=0xff00; *iol=0xff00ff00; writeb(0xff); writew(0xff00); writel(0xff00ff00);
디바이스드라이버 IO 제어 프로세스모드 사용자모드 응용프로그램코드실행 사용자메모리공간 3G에서실행 커널모드 커널코드실행 커널메모리 1G에서실행 사용자모드에서커널모드로의전환 소프트웨어인터럽트를통해가능 Ex) 시스템콜 사용자메모리 3G 커널메모리 1G
디바이스드라이버 IO 제어 사용자메모리와커널메모리복사함수들 커널모드의커널코드에서실행가능 int verify_area (int type, const void user *addr, unsigned long size); int copy_to_user (void user *to, const void *from, unsigend long n); int copy_from_user (void *to, const void user *from, unsigned long n); int get_user (x, ptr); int put_user (x, ptr);
디바이스드라이버 IO 제어 verify_area ( ) 기능 형태 설명 매개변수 반환값 사용자모모리공간의유효성을검사 #include <asm/uaccess.h> int verify_area (int type, const void user *addr, unsigned long size); 사용자메모리영역을카리키는 addr 부터 size 로지정되는크기의공간이읽기또는쓰기에유효한공간인가를확인 Type : 읽기또는쓰기모드 - VERIFY_WRITE : 읽기쓰기공간에대한검사 - VERIFY_READ : 읽기공간에대한검사 Addr : 사용자메모리블록선두주소 Size : 써넣을바이트단위의크기 성공 : 0, 실패 : 음수
디바이스드라이버 IO 제어 copy_to_user( ) 기능 형태 설명 매개변수 반환값 copy_from_user( ) 기능 형태 설명 매개변수 반환값 커널메모리블록데이터를사용자메모리블록데이터에써넣음 #include <asm/uaccess.h> int copy_to_user (void user *to, const void *from, unsigend long n); From 이가리키는주소의커널메모리블록데이터를 to 가가리키는사용자메모리블록데이터에바이트크기단위인 n 만큼써넣는다 from : 커널메모리블록선도주소 to : 사용자메모리블록선두주소 n : 써넣을바이트단위의크기 성공 : 0, 실패 : 음수 사용자메모리블록데이터를커널메모리블록데이터에써넣음 #include <asm/uaccess.h> int copy_from_user (void *to, const void user *from, unsigned long n); From 이가리키는주소의사용자메모리블록데이터를 to 가가리키는커널메모리블록데이터에바이트크기단위인 n 만큼써넣는다 from : 사용자메모리블록선도주소 to : 커널메모리블록선두주소 n : 써넣을바이트단위의크기 성공 : 0, 실패 : 음수
디바이스드라이버 IO 제어 get_user ( ) 기능 형태 설명 매개변수 반환값 사용자공간의데이터를읽는다 #include <asm/uaccess.h> int get_user (x, ptr); Ptr 이가리키는사용자메모리에서 x 변수의크기만큼읽어온다 x : 커널변수 ptr : 사용자메모리블록의선두주소 성공 : 0, 실패 : 음수 put_user ( ) 기능 형태 설명 매개변수 반환값 커널변수값을사용자공간에써넣는다 #include <asm/uaccess.h> int put_user (x, ptr); Ptr 이가리키는사용자메모리에서 x 변수의크기만큼써넣는다 x : 커널변수 ptr : 사용자메모리블록의선두주소 성공 : 0, 실패 : 음수