안녕하세요~ 이우영 입니다.


오늘은 간단한 실습을 해보기로 했습니다.


정말 간단하고 별로 권장하고 싶지 않은 방법으로 테스트 해보도록 하겠습니다.

(귀차니즘이 몰려와서 아주 간단하게 할깨요 ㅎㅎㅎ)


그럼 오늘도 복습!


1. 복습!




저번 시간에는 간단하게 arm CPSR 레지스터와  linux 2.6.29 커널에서 구현된 모습을 살펴 보았습니다.


소스코드가 어디있었는지 기억 나시나요?


/arch/arm/include/asm/irqflas.h  <--- 여기 입니다.


기억이 안나더라도 lxr.linux.no <-- 여기서 간단하게 검색 해볼 수 있습니다.


저도 저 사이트를 많이 이용하고 있습니다. 커널 분석을 위한 사이트입니다.


많이 많이 이용하세요~~


ARM에는 몇개의 레지스터가 있다고 했죠? 


R0~R15 + CPSR 해서 17개 있습니다.

(사실은 뱅크 레지스터를 통해서 더많은 레지스터가 있지만 바로바로 사용할 수 있는 레지스터는 17개 입니다,)


그림을 보시면 이해가 되실까요?  그림 추가 합니다.


k-20090608-857908_nigiro9.jpg


위 그림은 http://blog.naver.com/nigiro9?Redirect=Log&logNo=68407177  여기서 참조 하였습니다. 


레지스터에 대해서 설명이 나와있으니 한번쯤은 꼭 확인 해보세요.


그럼 간단하게 소스코드를 작성하러 가보겠습니다.


2. 소스 코드




다시 복습도 할 겸 저번에 타이머 인터럽트를 테스트 했던 소스를 이용해서 간단하게 확인해 보도록 하겠습니다.


timer_dev.c

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/version.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/sched.h>

#include <linux/interrupt.h>

#include <linux/wait.h>

#include <linux/ioport.h>

#include <linux/slab.h>   

#include <linux/poll.h>   

#include <linux/proc_fs.h>

#include <linux/workqueue.h>

#include <asm/system.h>    //인터럽트 금지 함수를 사용하기 위해서 추가

#include <asm/uaccess.h>

#include <asm/ioctl.h>

#include <asm/unistd.h>

#include <asm/io.h>

#include <asm/irq.h>

#include <asm/gpio.h>

#include <linux/irq.h>

#include <linux/time.h>                    

#include <linux/timer.h>    

#include <asm/mach/arch.h>

#include <plat/gpio-cfg.h>  

 

#define INT_DEV_NAME                  "timer_dev"

 

#define TIME_STEP                     HZ             //타이머 속도 지금 시스템은 1000

 

#define LED_GPIO_DATA_REGISTER        0x7F008184     //LED의 물리 주소

#define LED_ON                        (7<<2)

 

#define PAGE_SIZES                    0x1000

 

volatile u32                          *led_data;

u32                                   irq;

 

typedef struct                                        //타이머를 등록하면서 넘겨줄 데이터

{       //이런식도 가능한 것을 보여주고 있습니다.

        struct timer_list      timer;                 //이 변수는 필수

        unsigned long          led;

        u8                     flag;

__attribute__ ((packed)) KERNEL_TIMER_MANAGER;      

 

KERNEL_TIMER_MANAGER                *ptrmng = NULL;   

void kerneltimer_timeover(unsigned long arg);         //등록한 타이머가 동작할 때 호출하는 함수

 

void kerneltimer_registertimer(KERNEL_TIMER_MANAGER *pdata, unsigned long timeover)

{

        init_timer(&(pdata->timer));

        pdata->timer.expires   = get_jiffies_64( ) + timeover; //타이머가 동작할 시간 입력

        pdata->timer.data      = (unsigned long) pdata;        //함수에 넘겨줄 데이터

        pdata->timer.function  = kerneltimer_timeover;         //동작할 함수 등록

        add_timer(&(pdata->timer));       //타이머 등록

}

 

void kerneltimer_timeover(unsigned long arg)

{

        KERNEL_TIMER_MANAGER *pdata = NULL;

 

        if(arg)

        {

               pdata = (KERNEL_TIMER_MANAGER *) arg;

 

               *led_data = ~(*led_data);                        //LED 제어

               printk("timer!!\n");

 

               kerneltimer_registertimer(pdata, TIME_STEP);     //타이머를 다시 등록해준다.

        }

}

 

 

int timer_init() {

   int lp;

   unsigned long frags;


        printk("timer_dev_init!\n");

 

        led_data = ioremap(LED_GPIO_DATA_REGISTER, PAGE_SIZES);

 

        *led_data = LED_ON;

      

        ptrmng = kmalloc(sizeof(KERNEL_TIMER_MANAGER), GFP_KERNEL);

        if(ptrmng == NULL) return -ENOMEM;

 

        memset(ptrmng, 0, sizeof(KERNEL_TIMER_MANAGER));        //0으로 초기화

 

        ptrmng->led  = 0;

        ptrmng->flag = 0;

 

        kerneltimer_registertimer(ptrmng, TIME_STEP);           //타이머 등록


local_save_flags(frags); //CPSR 값 저장

        local_irq_disable(); //인터럽트 금지


        for(lp = 0; lp < 0x 10000; lp++) ; //금지 상태 확인용 루프


        local_irq_restore(frags); //인터럽트 복구


        return 0;

}

 

void timer_exit() {

        printk("timer_dev_exit!\n");

 

        if(ptrmng != NULL)

        {

               del_timer(&(ptrmng->timer));

               kfree(ptrmng);

        }

 

        iounmap( led_data );

}

 

module_init(timer_init);

module_exit(timer_exit);

 

MODULE_LICENSE("Dual BSD/GPL");


Makefile

cc := arm-generic-linux-gnueabi-gcc-4.3.2

obj-m := timer_dev.o

KDIR := /home/woo/device_driver/linux-2.6.29-ez-s3c6410

all:
make -C $(KDIR) SUBDIRS=$(PWD) modules
cp *.ko /nfs
clean:
rm -rf *.o
rm -rf *.ko
rm -rf *.mod.*
rm -rf .*.cmd
distclean:
rm -rf modules.order 
rm -rf Module.markers
rm -rf Module.symvers


새로 변경된 부분만 강조를 했지만 잘 보일려나요?.


별로 추가한것도 없습니다. 기존의 소스를 동작 시키면 LED가 깜빡 깜빡 하셨을 겁니다.


위에서 강제로 인터럽트를 금지 시키고 몇초 동안 루트를 돌렸습니다.


그럼 그동안 LED가 변하지 않겠죠?


그리고 루프가 끝나면 인터럽트를 복구 시켜서 다시 LED가 점멸 하게 됩니다.


완전 간단하게 확인 했습니다. ㅎㅎㅎ.;


그럼 오늘은 초간하게 끝을 내겠습니다.


그럼 다음시간에 만나요~


빠른만남을 원하시면 http://ms-osek.org/ 여기로 찾아오세요~