노무현 대통령 배너


2006. 7. 20. 13:27

커널 2.6.x 디바이스 드라이버

출처: http://pain.mizi.com/wikix/index.php?display=MyDocKernel26DeviceDriver#wikiXheading_8

커널 2.6.x 디바이스 드라이버

정원영미지리서치개발3실

suni00(at)kernel.pe.kr, suni00(at)mizi.com

ver 0.3, 2004년 06월 24일.ver 0.1, 2004년 01월 14일. 

커널 2.6.x는 소스파일 구성부터 이전과는 큰 차이를 보이며 커널코어 및 디바이스 드라이버의 구조등에 있어서도 많은 변화가 있다. 여기서는 커널 2.4.x에서 작성했던 디바이스 드라이버를 2.6.x로 포팅하는데 있어 기존과 다른 새로운점과 이로인한 디바이스 드라이버 작성할때 변화 내용을 알아보자. 물론 커널 2.6.x에서는 여전히 2.4.x에서 작성된 디바이스 드라이버와의 호환성 유지를 위해 어떤 부분들은 예전 코드로도 가능하도록 유지하고 있지만 실제 코딩을 해보면 제법 많은 차이를 실감할수 있을것이다.

차례

  1. 커널 2.6.x 특징
    1. 선점형 커널
      1. preempt_test.c
      2. Makefile
      3. compile
      4. test_preempt.c
      5. 결과
    2. 스케줄러
    3. 가상 메모리
    4. Interrupt Handler
    5. HZ
    6. jiffies
    7. 디바이스 넘버
    8. ndelay
    9. 모듈의 변화
    10. sysfs
    11. initramfs
    12. wait_event() 관련
    13. LOGO
    14. Keyboard
  2. 커널 config 등록및 컴파일
    1. Kconfig
      1. sound/Kconfig
      2. Kconfig 만들기
    2. Makefile
      1. sound/Makefile
      2. Makefile에 추가하기
  3. 디바이스 드라이버 예제
    1. simple_driver-2.4.c
    2. simple_driver.c
    3. ioctl_test.c
  4. 마치며
  5. 참고

커널 2.6.x 특징

커널 2.6.x는 우선 버전 네이밍과정부터 커널 메일링리스트에 많은 의견이 올라왔었다. 개발버전 2.5.x 에서 다음 안정버전을 3.0.x로 해도 되지 않겠느냐등이었는데 그만큼 2.4.x에 비해 큰 변화가 있음을 시사하고있다. 이런 의견의 배경이된것은 커널 2.6.x에서 가장 핵심적 변화인 커널코어쪽에서 새로운 스케줄러와 선점형 커널이 가능해졌기 때문이다.

다음은 커널 2.6.x에서 새로운것과 특징중 디바이스 드라이버를 만들기 위해 먼저 알아야할 내용들을 나열해 보았다.

선점형 커널

커널 2.6.x에서는 다음과 같이 커널 config 설정중 Processor type and features에서 [*] Preemptible Kernel 만 체크하면 선점형 커널이 된다.

선점형 커널을 위한 컴파일 옵션http://pain.mizi.com/wikix/file/MyDocKernel26DeviceDriver/preempt%2Dconfig.png

이옵션은 현재 실행중인 프로세스가 어떤 상황에 있더라도 커널이 그 프로세스를 선점하여 다른 프로세스를 실행할수있다는 것이다. (모든 경우에 대해 선점이 가능하진 않다. 이 부분에 관한 테스트도 있으니 참고하기 바란다.)

반대로 커널이 비선점(Non-preemptive)일 경우는 위와 같이 현재 실행중인 프로세스를 커널이가로챌수 없고 그 프로세스 스스로 제어권을 넘겨주기 전까지는 어떠한 우선순위를 가진 프로세스도실행될수 없음을 의미한다.

간단한 예를 들면 만약 비선점형 커널에서 어떤 프로세스가 무한루프에 빠지게 된다면 커널이 그 프로세스를 선점할수없어 무한루프 프로세스가 CPU를 계속 점유하게되어 다른 프로세스는 실행될수 없게된다. 이는 일반적으로 말하는 컴퓨터가 다운된것과 같은 것이다.

하지만 선점형 커널은 설사 위와 같이 어떤 프로세스가 무한루프에 빠지더라도 커널이 그 프로세스를선점하여 다른 프로세스를 실행할수 있기에 CPU가 먹통(?)이 되는 일은 없다. (Realtime OS의 경우 우선순위가 높은 프로세스가 무시되는 일없이 바로바로 실행되어야 하므로 선점형 커널을 쓰고이다.)

커널 2.6.x에서 선점가능한 곳을 다음 테스트 드라이버로 알아보자.(참고로 커널 2.4.x에서도 preempt patch를 적용하면 다음 테스트 드라이버로 테스트 가능하다.) 

preempt_test.c

#include#include#include#include#include#include#include#include#definePREEMPT_DEBUG#ifdefPREEMPT_DEBUG#defineDPRINTK(fmt,args...)printk(KERN_INFO"%s:"fmt,__FUNCTION__,##args)#else#defineDPRINTK(fmt,args...)#endif#ifLINUX_VERSION_CODE>=KERNEL_VERSION(2,6,0)#definepreempt_get_countpreempt_count#endifstaticintpreempt_open(structinode*inode,structfile*file){DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());return0;}staticintpreempt_release(structinode*inode,structfile*file){DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());return0;}staticssize_tpreempt_read(structfile*file,char*buf,size_tcount,loff_t*ppos){DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());return0;}staticssize_tpreempt_write(structfile*file,constchar*buf,size_tcount,loff_t*ppos){DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());return0;}staticintpreempt_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg){DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());return0;}staticstructfile_operationschar_fops={.owner=THIS_MODULE,.open=preempt_open,.release=preempt_release,.read=preempt_read,.write=preempt_write,.ioctl=preempt_ioctl,};staticstructmiscdevicechar_dev={.minor=MISC_DYNAMIC_MINOR,.name="preempt_test",.fops=&char_fops};int__initpreempt_init(void){intret;DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());ret=misc_register(&char_dev);if(ret){printk(KERN_ERR"misc_register()failedn");}DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());returnret;}void__exitpreempt_exit(void){DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());misc_deregister(&char_dev);DPRINTK("%d:preempt_count:%dn",__LINE__,preempt_get_count());}module_init(preempt_init);module_exit(preempt_exit);MODULE_LICENSE("GPL");

이 디바이스 드라이버는 선점가능 여부를 'DPRINTK(fmt, args...)'로 출력하게되는데 DPRINTK는 코드에서 알수있듯이 '#define PREEMPT_DEBUG'에 의해 'printk(KERN_INFO "%s: " fmt, __FUNCTION__ , ## args)'로 변환되어 기본적으로해당 함수이름을 출력해준다. 만약 '#undef PREEMPT_DEBUG'로 수정한다면 'DPRINTK(fmt, args...)'는 정의 된것이 아무것도 없기때문에 아무런 일을 하지 않게된다.주로 초기 프로그래밍할때 디버깅메세지를 출력하거나 하지않기 위해 이런식으로 많이 사용한다.

또 한가지 알아둘만한것은 'int misc_register(struct miscdevice * misc)'를사용한 부분이다. 이것은 간단한 디바이스 드라이버를 만들때 유용하게 쓸수있다. 

Makefile

다음과 같은 Makefile을 만든다.
##Makefile#obj-m:=preempt_test.o

compile

make-C/usr/src/linux-2.6.1/SUBDIRS=/tmp/module_testmodules
'-C' 다음은 커널소스의 위치를 적어주고 'SUBDIRS=' 다음은 preempt_test.c와 Makefile이 있는 디렉토리를 적어주면 모듈로 컴파일되어 preempt_test.ko라는 모듈이 생긴다. 

test_preempt.c

preempt_test.ko에 대한 테스트 프로그램으로 open, read, write, ioctl, close를 수행한다.
#include#include#include#definePREEMPT_NODE"/dev/misc/preempt_test"intmain(void){intret;charbuf[10];ret=open(PREEMPT_NODE,O_RDWR);read(ret,buf,1);write(ret,buf,1);ioctl(ret,0,0);close(ret);return0;}

컴파일
gcc-otest_preempttest_preempt.c

결과

printk는 '/var/log/messages'에 출력결과를 남기므로 실행결과를 보기위해 'tail -f /var/log/messages'라고 일단 실행하자. 그리고 preempt_test.ko 모듈을 올리면 '/dev/misc/preempt_test'란 노드가 생기며 여기서 test_preempt를 실행시켜보면 각각의 file operation에서의 preempt_count 값을 알수있다. (이 노드를 cat 명령등으로 read/write 해봐도 ioctl을 제외한 출력값을알수는있다.)마지막으로 preempt_test.ko 모듈을 내리면 다음과 같은 결과를 볼 수있다.preempt_count값은 해당 method가 실행될때 preempt_count 값을 출력하도록 되어있고preempt_count가 0일때는 선점가능하다는 의미이다.
preempt_init:77:preempt_count:0preempt_init:84:preempt_count:0preempt_open:24:preempt_count:1preempt_read:37:preempt_count:0preempt_write:45:preempt_count:0preempt_ioctl:53:preempt_count:1preempt_release:30:preempt_count:0preempt_exit:91:preempt_count:0preempt_exit:95:preempt_count:0
이 결과를 보면 file operation중 open일때와 ioctl을 사용할때는 선점가능하지 않음 즉 비선점임을 알수있다. 그러므로 만약 무한루프 같은 루틴이 open이나 ioctl에 있다면 그것이 실행되는 순간 CPU를 점유해버려 어떤 일도 할 수 없을것이다.file operation중 open이나 ioctl에서는 비선점임을 명심하자. (참고로 커널 2.4.x에 preempt patch를 적용한경우 위와 같은 테스트를 해보면 module init과 exit 과정에서도 preempt_count 값은 1이었다.)

스케줄러

커널 2.6.x의 스케줄러는 Ingo Molnar의 O(1) 알고리즘을 사용한다.

학교다닐때 자료구조인지 이산수학 시간인지 잘기억나진 않지만 그때를 얼핏 떠올려보면 시간복잡도를 표시하는 방법중의 하나가 O표기법(Big-Oh notation)인데 이것은 최악의 data가 들어왔을때의 처리속도를 의미한다.

예를들어 어떤 알고리즘이 O(N)이고 data가 1개라면 1이라는 시간만큼 걸리고 data가100개라면 100이라는 시간만큼 걸리게 되는것이다. 또 하나 예를들어 O(logN) log의 밑이2인알고리즘의 시간복잡도를 보면 data가 2개일때 log2 즉 1이라는 시간만큼 걸리고 data가 1024일때log1024 즉 10이라는 시간만큼 걸리는걸 의미한다.O(1)을 본다면 어떤 data가 들어와도 항상 1이라는 시간만 걸리므로 시간복잡도가 가장 빠른 알고리즘이다.

커널 2.6.x의 스케줄러가 O(1) 알고리즘을 사용한다는것은 실행중인 프로세스의 갯수와 상관없이 프로세스를 스케줄하는데 항상 일정한 시간이 걸린다는것이다. 다음 그림은 Rusty Russell의 hackbench를 이용하여 커널 2.4.18-3과 2.6.0-test9를 1 CPU에서 벤치마킹한 결과를 인용하였다. 더 자세한 내용은 http://developer.osdl.org/craiger/hackbench/에서 확인해 보기 바란다.

스케줄러 벤치마크http://pain.mizi.com/wikix/file/MyDocKernel26DeviceDriver/1way%2Dcompare.png

이러한 이유로 커널 2.6.x에서는 CPU의 load가 높거나 많은 프로세스가 실행 중이더라도 사용자나 다른 프로세스의 요구에 빠른 응답을 보낼수있게된다. 커널 2.6.x의 스케줄러는 이 O(1) 알고리즘 뿐만아니라 다른 특징들도 가지고있는데 결과적으로시스템의 안정성과 효율성을 높였다.

가상 메모리

structpte_chain{unsignedlongnext_and_idx;pte_addr_tptes[NRPTE];}____cacheline_aligned;

커널 2.6.x는 Rik van Riel의 r-map (reverse mapping)의 도입으로 위 pte_chain이라는 구조체를 두어 physical 에서 virtual로 쉽게 역매핑이 가능하다.

이것은 기존처럼 어떤 프로세스가 특정 physical page를 reference 하고있는지 찾기위해 모든 프로세스의 page table을 뒤질 필요가 없어졌고 그러므로 위와 같은 특정 상황에서는 뛰어난 성능을 보여줄수 있다. 

Interrupt Handler

인터럽트 핸들러의 리턴 type이 기존에는 void 였으나 커널 2.6.x에서는 irqreturn_t라는int형의 리턴값을 가진다. 그리고 정상적으로 수행되었을때는 IRQ_HANDLED을 리턴한다.
staticirqreturn_tinterrupt_handler(intirq,void*dev_id,structpt_regs*regs){/*runhandler*/returnIRQ_HANDLED;}

HZ

기존에 HZ값은 100이었지만 커널 2.6.x에서는 architecture마다 다르므로 schedule_timeout()등 시간과 관련된 함수를 사용할때는 꼭 HZ를 이용해야원하는 결과를 얻을수 있을것이다.예를들면 1초의 timeout를 주고싶다면 schedule_timeout(100) 이렇게 timeout값을 직접적으로 사용하지 말고 schedule_timeout(HZ)로 만약 500ms timeout을 주고싶다면schedule_timeout(HZ/2) 이런식으로 HZ를 이용하면 된다.

jiffies

32-bit 시스템에서 32bit jiffies의 경우는 HZ가 100일때는 시스템 부팅후 497일정도면 wrap되었지만 HZ가 1000일경우는 49일정도면 wrap되어 버린다. 그래서 32-bit 시스템에서 64bit jiffies를 원한다면 다음과 같이 얻어와야 한다.
u64my_time=get_jiffies_64();
timer 관련 커널함수를 사용할때 이런 부분도 유의하기 바란다.

디바이스 넘버

unsigned short였던 kdev_t가 없어지고 unsigned int인 dev_t로 바뀌면서 32bit로 확장되어 기존에 major number 8bit, minor number 8bit에서 major number 12bit, minor number 20bit가 할당되었다.

ndelay

ndelay() 추가. 하드웨어와 CPU의 속도 증가로 인해 좀더 정밀한 타이밍을 위해 nano second delay가 추가되었다. 하지만 대부분의 architecture에서는 ndelay(1)은 udelay(1)과 같을것이다.

모듈의 변화

커널 2.6.x 에서는 모듈구현 방식이 2.4.x와는 완전히 다르고 모듈명 또한 .ko(kernel object)로 변경되었다. 또한 vermagic(version magic)이라는 커널버전 정보를 가지고 있어 현재 실행중인 커널과 이 정보가 맞지 않으면 모듈이 올라가지 않는다. modinfo로 모듈의 버전정보를 알수있다.
모듈 버전정보 확인
suni00:linux-2.6.1/drivers/misc>modinfosimple_driver.koauthor:Won-youngChungdescription:SimpleDeviceDriverforKernel2.6.xlicense:GPLvermagic:2.6.1preemptPENTIUM4gcc-3.2depends:
2.6.x 에서 새로운 모듈을 로딩하기 위해서는 Rusty Russel의 module-init-tools를 컴파일하여새로운 modprobe, insmod, rmmod, depmod, lsmod를 만들어야 한다.

sysfs

mount -t sysfs none /sys
[P]
추가할것

initramfs

initrd를 대체할수 있으며 커널 컴파일시 built-in 된다.커널소스 디렉토리중 usr밑에 그 예가 있으며 다음과 같이 임시 root 디렉토리를 구성했다면 
# cd temp_root# find | cpio -co > ../initramfs_data.cpio
와 같은 방법으로 root 이미지를 만들수 있다. 그러면 커널 컴파일시 initramfs_data.cpio.gz가 initramfs_data.o가 되어 커널이미지에 추가될것이다.
[P]
추가할것

wait_event() 관련

[P]
정리할것

DECLARE_WAIT_QUEUE_HEAD(queue);DECLARE_WAITQUEUE(wait,current);for(;;){add_wait_queue(&queue,&wait);set_current_state(TASK_INTERRUPTIBLE);if(condition)break;schedule();remove_wait_queue(&queue,&wait);if(signal_pending(current))return-ERESTARTSYS;}set_current_state(TASK_RUNNING);2.6.xDECLARE_WAIT_QUEUE_HEAD(queue);DEFINE_WAIT(wait);while(!condition){prepare_to_wait(&queue,&wait,TASK_INTERRUPTIBLE);if(!condition)schedule();finish_wait(&queue,&wait)}

LOGO

예전엔 fblogo로 png 이미지 파일을 *.h로 변환하고 fbcon.c에서 LOGO의 높이및 폭의크기를 지정해줘야 했지만 2.6.x에서는 이미지 변환과정이 필요없어졌다.커널소스 디렉토리 drivers/video/logo에 ppm이란 이미지파일을 넣고 logo.c와Makefile에서 정의해 주면 된다.ppm이란 파일 자체는 Gimp등에서 쉽게 변환할수 있다.
[P]
추가할것

Keyboard

handle_scancode()가 없어졌으며 input device로 만들어야 한다.ARM processor 등에서 버튼 드라이버를 만들때 이젠 그리 만만치 않을것으로 보인다.임시로 put_queue()를 EXPORT_SYMBOL해서 쓸수도 있을것이다.
[P]
추가할것

커널 config 등록및 컴파일

커널 2.6.x 소스를 받고 tar로 풀어보면 소스 디렉토리의 구조에 변화가 있음을 알수있는데원하는 디바이스 드라이버를 어떤 위치에서 만들것이며 커널 config는 어떤 식으로 추가하며 컴파일 하는지를 살펴보자.

Kconfig

Kconfig는 커널 2.6.x 버전 이전에 각각의 디렉토리내에 위치하던 Config.in과 Documentation 디렉토리에 위치하던 도움말 파일인 Configure.help가 합쳐진 형태의 커널 config 설정 파일이다. 우리가 'make menuconfig'등으로 커널 옵션을 설정할때보여지는 부분이 이 파일에 있다.커널 2.6.x의 sound 디렉토리밑에 있는 Kconfig를 예로 자세히 알아보자. 

sound/Kconfig

#sound/Config.in#menu"Sound"configSOUNDtristate"Soundcardsupport"helpIfyouhaveasoundcardinyourcomputer,i.e.ifitcansaymorethananoccasionalbeep,sayY.Besuretohavealltheinformationaboutyoursoundcardanditsconfigurationdown(I/Oport,interruptandDMAchannel),becauseyouwillbeaskedforit....

위는 커널소스 'sound/' 디렉토리의 Kconfig의 일부분이다.

여기 Kconfig는 'make menuconfig'등으로 커널 config 설정할때
+-DeviceDrivers--->+-Sound--->+-<>Soundcardsupport
위치에서 볼수있는데 위와 같이 'Device Drivers' 밑에 'Sound'라고 나타나는 까닭은 커널소스 'drivers/Kconfig'에서 'sound/Kconfig'를 다음과 같이 불러주기 때문이다.
source"sound/Kconfig"
'source'라는 것은 현재 Kconfig에서 'source' 다음위치에 있는 설정파일을 불러온다.일반적인 프로그래밍 언어에서 '#include'와 비슷한 역할이라고 보면되겠다.

Kconfig의 구성은 다음과 같다.
  • menu "Sound"
    커널 config 설정 make menuconfig등을 할때 'Sound  --->' 이렇게 보이는부분이다.

  • config SOUND
    커널 config 설정에서 실제 Sound를 선택했을때 CONFIG_가 붙어 CONFIG_SOUND와 같은 식으로 활성화 된다. 우리가 'make menuconfig'등을 하고 저장하고 빠져나왔을때 우리가 선택한 것들에 대한 기록이 모듈로 선택했을 경우는 'CONFIG_SOUND=m',커널내에 포함시켰을 경우는 'CONFIG_SOUND=y'로 남게된다.(커널 config 설정후 커널소스내 .config 파일을 열어보면 확인할 수 있다.)

  • tristate "Sound card support"
    tristate란 'Sound card support'를 3가지 상태로 둘수있는것을 의미하는데 3가지 상태란선택 안하던지, 모듈로 하던지 또는 커널내 포함(built-in)할 수 있다는 의미이다.여기서 tristate 대신 bool을 쓰게되면 선택 안하던지 아님 커널내 built-in 하던지 두가지를 선택할수 있으며 모듈로는 할수 없게된다. (커널 config 설정하다보면 'M' 즉 모듈로 선택할수없는것들이 모두 bool을 쓴것이다.)  

  • help
    타이틀 그대로 커널 config 화면에서 'Help'를 선택했을때 보여주는 도움말이다.

커널소스 'Documentation/kbuild/kconfig-language.txt'에서 좀더 상세한 내용을 볼수있으니 참고하기 바란다. 

Kconfig 만들기

앞에서 설명한 내용을 참고로 뒤에 나올 디바이스 드라이버 예제를 위해 간단한 Kconfig를 만들어 보자.위치는 앞으로 만들 디바이스 드라이버 예제와 성격이 맞는 커널소스 'drivers/misc'로 하겠다. (또 한가지 이유는 이 디렉토리에는 파일들이 별로없어서이다.)다음과 같은 내용으로 drivers/misc/Kconfig를 만들자.
##Miscstrangedevices#menu"Miscdevices"configSIMPLE_DRIVERtristate"SimpleDeviceDriver"helpThisisasimpledevicedriverforkernel2.6.x.endmenu
이미 Kconfig의 구성에 대해 설명했으므로 쉽게 이해할수 있을것이다.

이제 이 Kconfig가 다음과 같은 위치에 보이게 하기위해서는 'drivers/Kconfig'에 'source "drivers/misc/Kconfig"' 를 추가하자.(커널 버전에 따라 이미 '# source "drivers/misc/Kconfig"' 이와같이 추가되어 있는 경우에는 앞에 주석을 풀어주자.)
+-DeviceDrivers--->+-Miscdevices--->+-SimpleDeviceDriver

추가한 커널 컴파일 옵션http://pain.mizi.com/wikix/file/MyDocKernel26DeviceDriver/simple%2Dconfig.png
여기까지의 과정으로 커널 설정파일 '.config'에는 'CONFIG_SIMPLE_DRIVER=m'이 활성화된다.

Makefile

Makefile은 커널 config 설정(.config)에서 선택한 커널옵션을 위해 실제 어떤 소스파일을컴파일 해야하는지 알고 그파일을 컴파일 할수있게 해준다.

sound/Makefile

일단 앞에서 'sound/Kconfig'를 예로 들었으므로 Makefile은 커널소스 'sound/Makefile'을예로 설명하겠다. 

#MakefilefortheLinuxsoundcarddriver#obj-$(CONFIG_SOUND)+=soundcore.oobj-$(CONFIG_SOUND_PRIME)+=oss/obj-$(CONFIG_DMASOUND)+=oss/obj-$(CONFIG_SND)+=core/i2c/drivers/isa/pci/ppc/arm/synth/usb/sparc/parisc/pcmcia/ifeq($(CONFIG_SND),y)obj-y+=last.oendifsoundcore-objs:=sound_core.osound_firmware.o
만약 CONFIG_SOUND를 built-in 했다면 CONFIG_SOUND는 'y'로 대입되어 'obj-y += soundcore.o'가 된다. 마찬가지로 모듈로 선택했다면 'obj-m += soundcore.o' 된다.어찌되었든 CONFIG_SOUND를 모듈 또는 built-in으로 선택하면 soundcore.c라는 소스파일을 컴파일하도록 되어있는것은 분명한걸 알수있다. 

참고로 'Sound card support'를 모듈로 했다면 커널소스의 최상위 경로에서 다음과 같은 명령으로 sound 밑의 모듈만 컴파일해서 얻을수 있다.
makeSUBDIRS=soundmodules

Makefile에 추가하기

이제 우리가 만든 CONFIG_SIMPLE_DRIVER를 선택했을때 컴파일이 가능하도록'driver/misc/Makefile'을 만들어보자.컴파일할 파일은 simple_driver.c라고 가정하고 뒷부분에서 실제 이 테스트 디바이스 드라이버를 만들어 볼것이다.

##Makefileformiscdevicesthatreallydon'tfitanywhereelse.##obj-:=misc.o#Dummyruletoforcebuilt-in.otobemadeobj-$(CONFIG_SIMPLE_DRIVER)+=simple_driver.o

모듈로 컴파일하면 컴파일 시간이나 원하는 대로 테스트 디바이스 드라이버를 수정해서재부팅없이 테스트 가능하므로 다음과 같이 모듈로 컴파일 하도록 하자. 
makeSUBDIRS=drivers/miscmodules
simple_driver.c 파일이 있다면 simple_driver.ko라는 모듈이 생긴다.  

디바이스 드라이버 예제

이제 커널 2.6.x용 simple_driver.c라는 디바이스 드라이버를 만들어 보자.커널 2.4.x와 커널 2.6.x 디바이스 드라이버의 차이를 알아보기위해 simple_driver-2.4.c라는 2.4.x용 디바이스 드라이버를 커널 2.6.x용simple_driver.c로 변경하는 형식으로 설명하겠다.이 디바이스 드라이버는 user의 입력을 지정된 시간만큼 타이머가 돌면서 다시 출력해주는일을 한다. 실제 이런 디바이스 드라이버가 필요하진 않겠지만 커널 2.6.x에서 새로운 function이나 문법을 설명하기위해 예를 들어 만들어보았다.조금 억지스러운 면이나 불필요한 부분이 있더라도 그냥 이해하기 바란다.또 한가지 이 디바이스 드라이버는 x86이든 arm이든 범용적이므로 직접 테스트 해보기바란다.

simple_driver-2.4.c

1/*2*drivers/misc/simple_driver-2.4.c3*4*Copyright(C)2004,Won-youngChung5*6*Thisprogramisfreesoftware;youcanredistributeitand/ormodify7*itunderthetermsoftheGNUGeneralPublicLicenseversion2as8*publishedby