panda.jpg 


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


저번 시간에 이어서 디바이스 드라이버를 구현해 보겠습니다.


1. 인터럽트를 사용하는 디바이스 드라이버



IOCTL 디바이스 드라이버를 동작 시키기 위한 인터럽트 디바이스 드라이버를 만들어 보겠습니다.

(그저 인터럽트를 키용도로 만들었을 뿐입니다 ㅎㅎ)


 #include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

 

#include <linux/version.h>

#include <linux/fs.h>

#include <linux/sched.h>

 

#include <linux/interrupt.h>

#include <linux/wait.h>

#include <linux/irq.h>

 

#include <linux/ioport.h>

#include <linux/slab.h>

#include <linux/poll.h>

#include <linux/proc_fs.h>

#include <linux/workqueue.h>

 

#include <linux/time.h>

#include <linux/timer.h>

 

#include <linux/poll.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 <asm/mach/arch.h>

 

#include <plat/gpio-cfg.h>

#include "ioctl-gpio-int.h"

 

#define INT_DEV_NAME                    "dev_int"

#define INT_DEV_MAJOR                   240

 

#define IRQT_FALLING                    IRQ_TYPE_EDGE_FALLING

 

DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Read_int);

 

static unsigned int        ReadQCount    = 0;

u32          irq6;

u32          irq5;

u32          irq4;

u32          irq3;

u32          irq_number;

 

irqreturn_t interrupt_6(int irq, void *dev_id, struct pt_regs *regs)

{

       unsigned long flags;

 

       printk("dev interrupt0\n");

 

       local_save_flags(flags);

       local_irq_disable();

       ReadQCount++;

       irq_number=0;

       local_irq_restore(flags);

 

       wake_up_interruptible(&WaitQueue_Read_int);

 

       return IRQ_HANDLED;

}

irqreturn_t interrupt_5(int irq, void *dev_id, struct pt_regs *regs)

{

       unsigned long flags;

 

       printk("dev interrupt1\n");

 

       local_save_flags(flags);

       local_irq_disable();

       ReadQCount++;

       irq_number=1;

       local_irq_restore(flags);

 

       wake_up_interruptible(&WaitQueue_Read_int);

 

       return IRQ_HANDLED;

}

irqreturn_t interrupt_4(int irq, void *dev_id, struct pt_regs *regs)

{

       unsigned long flags;

 

       printk("dev interrupt2\n");

 

       local_save_flags(flags);

       local_irq_disable();

       ReadQCount++;

       irq_number=2;

       local_irq_restore(flags);

 

       wake_up_interruptible(&WaitQueue_Read_int);

 

       return IRQ_HANDLED;

}

irqreturn_t interrupt_3(int irq, void *dev_id, struct pt_regs *regs)

{

       unsigned long flags;

 

       printk("dev interrupt3\n");

      

       local_save_flags(flags);

       local_irq_disable();

       ReadQCount++;

       irq_number=3;

       local_irq_restore(flags);

 

       wake_up_interruptible(&WaitQueue_Read_int);

      

       return IRQ_HANDLED;

}

 

int ioctl_int_open(struct inode *inode, struct file *filp)

{

       u32 gpio_6;

       u32 gpio_5;

       u32 gpio_4;

       u32 gpio_3;

 

       gpio_6 = S3C64XX_GPN(6);

       gpio_5 = S3C64XX_GPN(5);

       gpio_4 = S3C64XX_GPN(4);

       gpio_3 = S3C64XX_GPN(3);

 

       s3c_gpio_setpull( gpio_6, S3C_GPIO_PULL_UP );

       s3c_gpio_setpull( gpio_3, S3C_GPIO_PULL_UP );

       s3c_gpio_setpull( gpio_4, S3C_GPIO_PULL_UP );

       s3c_gpio_setpull( gpio_5, S3C_GPIO_PULL_UP );

 

       irq6 = IRQ_EINT(6);

       irq5 = IRQ_EINT(5);

       irq4 = IRQ_EINT(4);

       irq3 = IRQ_EINT(3);

 

       set_irq_type( irq6, IRQT_FALLING );

       set_irq_type( irq5, IRQT_FALLING );

       set_irq_type( irq4, IRQT_FALLING );

       set_irq_type( irq3, IRQT_FALLING );

 

       if( !request_irq( irq6, interrupt_6, IRQF_DISABLED, INT_DEV_NAME, NULL ));

       if( !request_irq( irq5, interrupt_5, IRQF_DISABLED, INT_DEV_NAME, NULL ));

       if( !request_irq( irq4, interrupt_4, IRQF_DISABLED, INT_DEV_NAME, NULL ));

       if( !request_irq( irq3, interrupt_3, IRQF_DISABLED, INT_DEV_NAME, NULL ));

 

       return 0;

}

 

ssize_t ioctl_int_read( struct file *filp, char *buf, size_t count, loff_t *f_pos )

{

       unsigned long flags;

       int retstate;

 

       retstate = wait_event_interruptible(WaitQueue_Read_int,ReadQCount);

 

       if(retstate) return retstate;

 

       local_save_flags(flags);

       local_irq_disable();

       ReadQCount = 0;

//     copy_to_user(buf,&irq_number,1);

       put_user(irq_number,(char *)buf);

       local_irq_restore(flags);

 

       return 0;

}

 

unsigned int ioctl_int_poll( struct file *filp, poll_table *wait)

{

       unsigned int mask = 0;

 

       poll_wait(filp, &WaitQueue_Read_int, wait);

 

       if(ReadQCount > 0)

             mask |= POLLIN | POLLRDNORM;

      

       return mask;

}

 

int ioctl_int_release(struct inode *inode, struct file *filp)

{

       free_irq( irq6, NULL );

       free_irq( irq5, NULL );

       free_irq( irq4, NULL );

       free_irq( irq3, NULL );

 

       return 0;

}

 

struct file_operations poll_fops =

{

             .owner       = THIS_MODULE,

             .read        = ioctl_int_read,

             .poll        = ioctl_int_poll,

             .open        = ioctl_int_open,

             .release     = ioctl_int_release,

};

 

int ioctl_int_init( void )

{

       int result;

 

       result = register_chrdev(INT_DEV_MAJOR,INT_DEV_NAME,&poll_fops);

 

       if( result < 0)

             return result;

 

       return 0;

}

 

void ioctl_int_exit( void )

{

       unregister_chrdev(INT_DEV_MAJOR, INT_DEV_NAME);

}

module_init( ioctl_int_init );

module_exit( ioctl_int_exit );

  MODULE_LICENSE("Dual BSD/GPL");


이 디바이스는 여러 인터럽트를 만들어 각 이터럽트 마다 특정 값을 응용프로그램에 전달합니다.


그리고 응용 프로그램은 전달 받은 값을 통해 IOCTL cmd를 만듭니다.


그리고 IOCTL 디바이스 드라이버에 전달하겠죠?


(소스코드는 동작을 시키기 위해서 생각난대로만 했기 때문에 많이많이 허접합니다. ㅎㅎㅎ )

(그저 기억을 떠올리는 용도로 사용해 주세요 ㅎㅎ)


2. 실습!!!




그럼 실습을 해보겠습니다.


먼저 디바이스 드라이버를 등록 해야겠죠?



   mknod /dev/dev_int    c 240 0                                                                                      

  mknod /dev/dev_ioctl  c 241 0  



위와 같이 먼저 dev 폴더에 노드를 생성해 줍니다.

(open 해서 사용하기 위해서는 파일 형태가 필요합니다!! 옛 기억을 떠올려 보세요!)


그럼 insmod를 통해 모듈을 등록 하겠습니다.


                                                                                                                                                                                              

  insmod dev_int.ko

  insmod dev_ioctl.ko



그럼 응영프로그램을 실행해 봅시다.


./ioctl_app


그럼 다음과 같이 동작을 합니다.


1.png


아무 응답이 없을경으 위와 같이 no wake up 메시지가 나옵니다.


gpio 핀을 통해 인터럽트를 발생 시키면 각 해당하는 인터럽트 메시지도 나옵니다.


그리고 그에 따른 IOCTL 동작을 하겠죠?


LED가 켜지거나 꺼지고, 또는 토글 형식으로 동작 합니다.


마지막 명령어를 동작 시키면 아래와 같이 시간이 출력 됩니다.


2.png


그럼 오늘은 여기까지!!


그럼 다음시간에 만나요~~

(준비해 두었던 자료가 떨어져서 다음은 언제가 될지 모르겠어요~~)


제 모든 자료는 다음 책을 참고 하였습니다.


리눅스 드바이스 드라이버(유영창 저) -