강좌 & 팁
안녕하세요 판다 이우영입니다.
오늘부터 소스코드를 작성해 본다고 했었죠?
그럼 먼저 복습부터 하겠습니다.
1. 복습!!
실습에 들어가기 전 워크큐 간단한 사용방법을 확인하고 넘어가겠습니다.
1. DECLARE_WORK 메크로를 이용하여 work_struct 변수를 생성 및 초기화 합니다.
ex) DECLARE_WORK( my_work, my_work_func, NULL );
2. scahedule_work 함수를 통해 커널에 등록을 합니다.
ex) scahedule_work( &my_work );
3. queue_work(), queue_delayed_work() 를 호출한다.
4. keventd 스레드가 등록된 워크 큐를 실행 시켜 준다.
2,3 번 에서 사용되는 함수들은 성공 한다면 1을 실패한다면 0을 반환 합니다.
주의하세요!!
그럼 다음으로 넘어 가겠습니다.
2. 디바이스 드라이버 작성
먼저 오늘 부터 작성할 프로그램에 대해서 알려드리겠습니다.
프로그램은 간단 합니다. 응용프로그램은 디바이스 드라이버에 read와 write 를 하게 됩니다.
그러면 일반적으로 해당 기능을 수행 할 수 없다면 잠들게 되지요 이때 인터럽트가 발생하면 깨어나게 됩니다.
여기에 추가적으로 기능을 수행하는 부분을 워크 큐로 구현을 합니다.
그냥 인터럽트에서 처리하면 되지 왜 워크 큐를 사용할까요?
제가 생각하는 가장 큰 차이점은 인터럽트에서는 잠들 수 없습니다.
가끔 복잡한 처리를 위해 잠시 쉬어야 하는경우가 생길 수도 있습니다.
(네트워크에서 많이 생길 수 있습니다.)
그럴 때 간단한 처리는 인터럽트에서 해결하고 나머지 작업을 인터럽트에서 빠져나와 워크큐에서 수행하도록 할 수 있습니다.
그럼 디바이스 드라이버를 작성해 보겠습니다.
#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"); |
소스 코드를 보시면서 어떤 식으로 구성되어 있는지 다시한번 확인해 보세요.
위에 설명한것과 비슷하죠?
(아니라면 할말 없습니다 ㅎㅎㅎ)
그럼 오늘은 여기까지!!
다음시간에 만나요~