panda.jpg


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


회사에서 전시회 준비로 바쁜 일주일을 보냈습니다.


그래도 해야할껀 해야죠 ㅎㅎ


그럼 오늘도 디바이스 드라이버 공부를 시작하겠습니다.


1. 복습!!!




저번 시간에는 디바이스 드라이버에서 해주어야 하는 것을 알아 보았습니다.


그럼 다시 한번 확인해 볼까요?


블록킹 I/O를 사용하기위해서는 다음 해더 파일을 추가 해야 합니다.


 #include <linux/wait.h>


사용하는 법을 다시 보도록 하겠습니다.


▪ DECLARE_WAIT_QUEUE_HEAD( WaitQueue );


위와 같이 매크로를 사용해서 “wait_queue_head_t” 구조체를 선언하고 초기화를 해야합나다. 


사용할때는 다음 함수를 통해서 응용프로그램을 재우고 깨워 줍니다.


▪ interrupible_sleep_on(&WaitQueue);

▪ wake_up_interruptible(&WaitQueue);


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


2. 응용 프로그램에서 해야할 일!!




응용 프로그램은 복잡한 관정은 필요 없습니다. 


그냥 평소와 같이 만들어 주면 끝입니다. ㅎㅎㅎ


하지만 응용프로그램이 잠들고 싶지 않은 경우가 있겠죠?


그런 경우에는 디바이스를 오픈 할 때 옵션을 하나 더주면 끝입니다.


예를 들어 볼까요?


기존의 a 라는 디바이스를 오픈 할 때는 다음과 같이 진행합니다.



 #define DEVICE_FILENAME        "/dev/a"


 int main()

 {

        int   dev;

        dev = open( DEVICE_FILENAME, O_RDWR );                                                


        close(dev);

 } 



그럼 응용프로그램이 잠들지 않는 방법은 어떤 걸까요?  다음과 같습니다.



 #define
 DEVICE_FILENAME        "/dev/a"                                                      


 int main()

 {

        int   dev;

        dev = open( DEVICE_FILENAME, O_RDWR | O_NDELAY );   


        close(dev);

 }

 


간 단 하죠?


그럼 눈으로 집접 확인해 봐야겠죠?


확인하러 가봅시다.


3. TEST 프로그램




먼저 디바이스 드라이버 소스 코드 입니다.



                                                                                                                                                                     

 blockio_dev.c

 

                                                                                                                                                                    

#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 <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>

 

#define BLOCKIO_DEV_NAME                     "blockio_dev"

#define BLOCKIO_DEV_MAJOR                    240

 

#define IRQT_FALLING                         IRQ_TYPE_EDGE_FALLING

 

#define LED_GPIO_DATA_REGISTER               0x7F008184

#define LED_ON                               (7<<2)

 

#define DATA_SIZE                            0x1000

 

#define BLOCKIO_BUFF_MAX                     64


typedef struct

{

        unsigned long time;

__attribute__ ( (packed) ) R_BLOCKIO_INFO;

 

R_BLOCKIO_INFO intbuffer[ BLOCKIO_BUFF_MAX ];

int                           intcount = 0;

volatile u32                  *led_data;

u32                           irq;

 

DECLARE_WAIT_QUEUE_HEAD( WaitQueue_Read );

 

void blockio_clearvoid )

{

        int lp;

 

        for( lp = 0; lp < BLOCKIO_BUFF_MAX; lp++ )

        {

               intbuffer[ lp ].time = 0;

        }

 

        intcount = 0;

}

 

irqreturn_t blockio_interruptint irq, void *dev_id, struct pt_regs *regs )

{

        if( intcount < BLOCKIO_BUFF_MAX )

        {

               intbuffer[ intcount ].time = get_jiffies_64();

               intcount++;

        }

 

        wake_up_interruptible( &WaitQueue_Read );

 

        return IRQ_HANDLED;

}

 

int blockio_openstruct inode *inode, struct file *filp )

{

        u32 gpio;

 

        gpio = S3C64XX_GPN(6);

        s3c_gpio_setpull( gpio, S3C_GPIO_PULL_UP );

        irq = IRQ_EINT(6);

        set_irq_type( irq, IRQT_FALLING );

 

        if( !request_irq( irq, blockio_interrupt, IRQF_DISABLED, BLOCKIO_DEV_NAME, NULL ));

 

        blockio_clear();

 

        return 0;

}

 

ssize_t blockio_readstruct file *filp, char *buf, size_t count, loff_t *f_pos )

{

        int     readcount;

        char    *ptrdata;

        int     loop;

 

        if( !intcount )

        {

               if( !( filp->f_flags & O_NONBLOCK ) )

               {

                       interruptible_sleep_on( &WaitQueue_Read );

               }

               else

               {

                       return -EAGAIN;

               }

        }

       

        readcount = count / sizeofR_BLOCKIO_INFO );

        if( readcount > intcount )    readcount = intcount;

 

        ptrdata = (char *) &intbuffer[ 0 ];

 

        for( loop = 0; loop < readcount * sizeofR_BLOCKIO_INFO ); loop++ )

        {

               put_user( ptrdata[ loop ], (char *) &buf[ loop ] );

        }

 

        return readcount * sizeofR_BLOCKIO_INFO );

}

 

ssize_t blockio_writestruct file *filp, const char *buf, size_t count, loff_t *f_pos )

{

        unsigned char  status;

        int                    loop;

 

        blockio_clear();

 

        get_user(status, (char *) buf );

 

        if( status == 0 )

               *led_data = LED_ON;

        else

               *led_data = 0;

 

        return count;

}

 

int blockio_releasestruct inode *inode, struct file *filp )

{

        free_irq( irq, NULL );

        return 0;

}

 

struct file_operations blockio_fops =

{

        .owner   = THIS_MODULE,

        .read    = blockio_read,

        .write   = blockio_write,

        .open    = blockio_open,

        .release = blockio_release,

};

 

int blockio_initvoid )

{

        int result;

 

        printk( "module_init\n");

 

        led_data = ioremap( LED_GPIO_DATA_REGISTER,  DATA_SIZE );

        result = register_chrdev( BLOCKIO_DEV_MAJOR, BLOCKIO_DEV_NAME, &blockio_fops );

        if( result < 0 )       return result;

 

        return 0;

}

 

void blockio_exitvoid )

{

        printk( "module_exit\n");

        iounmap( led_data );

        unregister_chrdev( BLOCKIO_DEV_MAJOR, BLOCKIO_DEV_NAME );

}

 

module_init( blockio_init );

module_exit( blockio_exit );

 

MODULE_LICENSE("Dual BSD/GPL");



다음은 Makefile 입니다. 평소와 다를것이 없습니다.


                                                                                                                                                                    

 Makefile

 

                                                                                                                                                                    

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


 obj-m  := blockio_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

 


그럼 마지막으로 응용프로그램 입니다. 



 blockio_app.c


 

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/ioctl.h>

#include <fcntl.h>

#include <unistd.h>

 

#define DEVICE_FILENAME        "/dev/blockio_dev"

 

typedef struct

{

        unsigned long time;

__attribute__ ((packed)) R_INT_INFO;

 

#define INT_BUFF_MAX           64

 

int main()

{

        int                    dev;

        R_INT_INFO     intbuffer[ INT_BUFF_MAX ];

        int                    intcount;

        char                   buff[ 128 ];

        int                    loop;

 

        dev = open( DEVICE_FILENAME, O_RDWR );

        if( dev >= 0 )

   {

               printf( "start.....\n" );

               buff[ 0 ] = 0xFF;

               write( dev, buff, 1 );

 

               printf( "wait... input\n" );

 

               intcount = read( dev, (char *) &intbuffer[ 0 ], sizeofR_INT_INFO ) ) / sizeof(R_INT_INFO );

               printf( "input ok.....\n" );

               sleep( 1 );

               memset( intbuffer, 0, sizeof( intbuffer ) );

 

               printf( "read interrupt times\n" );

               intcount = read( dev, (char *) intbuffer, sizeof( intbuffer ) ) / sizeof(R_INT_INFO );

               for( loop = 0; loop < intcount; loop++ )

               {

                       printf( "index = %d    time = %ld\n", loop, intbuffer[ loop ].time );

               }

 

               printf( "led flashing.....\n" );

               for( loop = 0; loop < 5; loop++ )

               {

                       buff[ 0 ] = 0xFF;

                       write( dev, buff, 1 );

                       sleep( 1 );

                       buff[ 0 ] = 0x00;

                       write( dev, buff, 1 );

                       sleep( 1 );

               }

               close( dev );

        }

        return 0;

}



실행은 

지금 확인이 불가능 하기 때문에 추후에 업데이트 하도록 하겠습니다. 



그럼 오늘은 여기까지 입니다.


다음시간에 만나요~~


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