panda.jpg 


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


오늘부터 소스코드를 작성해 본다고 했었죠?


그럼 먼저 복습부터 하겠습니다.


1. 복습!!



실습에 들어가기 전 워크큐 간단한 사용방법을 확인하고 넘어가겠습니다.


1. DECLARE_WORK 메크로를 이용하여 work_struct 변수를 생성 및 초기화 합니다.

ex) DECLARE_WORK( my_work, my_work_func, NULL );


2. scahedule_work 함수를 통해 커널에 등록을 합니다.

exscahedule_work( &my_work );


3. queue_work(), queue_delayed_work() 를 호출한다.


4. keventd 스레드가 등록된 워크 큐를 실행 시켜 준다.


2,3 번 에서 사용되는 함수들은 성공 한다면 1 실패한다면 0을 반환 합니다.


주의하세요!!


그럼 다음으로 넘어 가겠습니다.


2. 디바이스 드라이버 작성




먼저 오늘 부터 작성할 프로그램에 대해서 알려드리겠습니다.


프로그램은 간단 합니다. 응용프로그램은 디바이스 드라이버에 readwrite 를 하게 됩니다.


그러면 일반적으로 해당 기능을 수행 할 수 없다면 잠들게 되지요 이때 인터럽트가 발생하면 깨어나게 됩니다.


여기에 추가적으로 기능을 수행하는 부분을 워크 큐로 구현을 합니다.


그냥 인터럽트에서 처리하면 되지 왜 워크 큐를 사용할까요?


제가 생각하는 가장 큰 차이점은 인터럽트에서는 잠들 수 없습니다.


가끔 복잡한 처리를 위해 잠시 쉬어야 하는경우가 생길 수도 있습니다.

(네트워크에서 많이 생길 수 있습니다.)


그럴 때 간단한 처리는 인터럽트에서 해결하고 나머지 작업을 인터럽트에서 빠져나와 워크큐에서 수행하도록 할 수 있습니다.


그럼 디바이스 드라이버를 작성해 보겠습니다.


#include <linux/proc_fs.h>   /* Necessary because we use the proc fs */

#include <linux/module.h>

#include <linux/init.h>

#include <linux/sched.h>

#include <linux/delay.h>

#include <linux/errno.h>

#include <linux/interrupt.h>

#include <linux/ioport.h>

#include <linux/kernel.h>

#include <linux/slab.h>

#include <linux/pci.h>

#include <linux/pnp.h>

#include <linux/sysctl.h>

 

#include <linux/timer.h>

#include <linux/workqueue.h>

 

#include <asm/io.h>

#include <asm/dma.h>

#include <asm/uaccess.h>

#include <asm/system.h>

#include <asm/uaccess.h>

#include <asm/ioctl.h>

#include <asm/unistd.h>

#include <asm/irq.h>

#include <asm/gpio.h>

 

 

#include <linux/irq.h>

#include <linux/time.h>

#include <linux/timer.h>

#include <linux/delay.h>

#include <linux/types.h>

#include <asm/mach/arch.h>

#include <plat/gpio-cfg.h>

#include <linux/jiffies.h>

 

#include "debug.h"

 

 

#define     DEV_NAME                                 "/dev/workqueue"

#define     DEV_MAJOR                                240

 

#define IRQT_FALLING                           IRQ_TYPE_EDGE_FALLING

 

unsigned long irq_read;

unsigned long irq_write;

 

void call_workqueuefunc( void *data );

 

static struct work_struct work_queue;

 

static DECLARE_WAIT_QUEUE_HEAD( waitqueue_read );

static DECLARE_WAIT_QUEUE_HEAD( waitqueue_write );

static DECLARE_WORK( work_queue, call_workqueuefunc);

 

void call_workqueuefunc( void * data )

{

      printk("[WORK QUEUE] Enter workqueue function\n");  

}

 

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

{

      printk("[WORK QUEUE] Enter workqueue_interrupt in interrupt\n");

     

      schedule_work( &work_queue ); // 워크 구조체 등록

      wake_up_interruptible( &waitqueue_read );

      printk("[WORK QUEUE] After schedule_work in interrupt\n");

 

      return IRQ_HANDLED;

}

 

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

{

      printk("[WORK QUEUE] Enter workqueue_interrupt in interrupt\n");

     

      schedule_work( &work_queue );

      wake_up_interruptible( &waitqueue_write );

      printk("[WORK QUEUE] After schedule_work in interrupt\n");

 

      return IRQ_HANDLED;

}

 

 

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

{

 

      printk("[WORK QUEUE] Enter workqueue_read in read\n");

      schedule_work( &work_queue );

      interruptible_sleep_on( &waitqueue_read );

      printk("[WORK_QUEUE] After schedule_work in read\n");

 

      return 1;

}

 

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

{

      printk("[WORK QUEUE] Enter workqueue_write in write\n");

      schedule_work( &work_queue );

      interruptible_sleep_on( &waitqueue_write );

     

      printk("[WORK_QUEUE] After schedule_work in write\n");

      return 1;

}

 

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

{

      u32 gpio_read;

      u32 gpio_write;

     

      gpio_read = S3C64XX_GPN(6);

      s3c_gpio_setpull( gpio_read, S3C_GPIO_PULL_UP   );

      irq_read = IRQ_EINT(6);

      set_irq_type( irq_read, IRQT_FALLING );

 

      gpio_write = S3C64XX_GPN(5);

      s3c_gpio_setpull( gpio_write, S3C_GPIO_PULL_UP   );

      irq_write = IRQ_EINT(5);

      set_irq_type( irq_write, IRQT_FALLING );

 

      if( 0 == request_irq( irq_read, workqueue_interrupt_read, IRQF_DISABLED, DEV_NAME, NULL ))

      {

                  printk("request irq read ok\n");

      }    

     

      if( 0 == request_irq( irq_write, workqueue_interrupt_write, IRQF_DISABLED, DEV_NAME, NULL ))

      {

                  printk("request irq wrtie ok\n");

      }    

     

      return 0;

     

}

 

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

{

      free_irq( irq_read, NULL );

      free_irq( irq_write, NULL );

      return 0;  

}

 

struct file_operations workqueue_fops =

{

      .owner            = THIS_MODULE,

      .read             = workqueue_read,

      .write            = workqueue_write,

      .open             = workqueue_open,

      .release    = workqueue_release,

};

 

int workqueue_init( void )

{

      int result;

     

      result = register_chrdev( DEV_MAJOR, DEV_NAME, &workqueue_fops );

      if( result < 0 )

      {

                  printk("register error\n");

                  return result;   

      }    

           

      return 0;

                 

}

 

void workqueue_exit( void )

{

      unregister_chrdev( DEV_MAJOR, DEV_NAME );

}

 

module_init( workqueue_init );

module_exit( workqueue_exit );

 

MODULE_LICENSE("Dual BSK/GPL"); 


소스 코드를 보시면서 어떤 식으로 구성되어 있는지 다시한번 확인해 보세요.


위에 설명한것과 비슷하죠?

(아니라면 할말 없습니다 ㅎㅎㅎ)


그럼 오늘은 여기까지!!


다음시간에 만나요~