<출처 > http://www.fsp21.org/zbxe/?mid=FWP_daily&document_srl=9945
-----------------------------------------------------------------------------------------------
작성자 : 문경원 -imesu
날짜     :  2008.12.20
수정     :  2008.12.21

-----------------------------------------------------------------------------------------------
1.     
개요


터치스크린
, 마우스에 디바이스 드라이버를 사용하기 위한 입력 디바이스 드라이버에 대하여 이해하고, 이벤트 핸들러 디바이스 드라이버인 Mouse event 관련 자료형인 input_event 대하여 알아보자

문서의 내용은 8.1에 참고자료를  참조하여 작성 하였습니다.
상업적 목적 보다는 gxlib, 및 ex2440 보드  학습 목적으로 작성한 문서입니다. 


1.      입력 디바이스 드라이버

 

입력 장치에는 마우스, 터치 스크린, 조이스틱, 키보드 등 다양한 입력 장치가 존재합니다.

이런 입력 장치에 대하여 각각 특징에 맞는 디바이스 드라이버가 개발 되었습니다.

 

새로운 입력 장치가 추가 될 때 마다, 입력 디바이스 드라이버를 만드는 불편을 해소하기 위하여, 리눅스 개발자들은 다양한 입력 장치를 통합하는 입력 디바이스 드라이버를 만들게 되었다.

 

입력 디바이스 드라이버는 리눅스 운영체제에서 사용되는 모든 입력 장치를 지원하기 위해 만들어진 드라이버들의 묶음 입니다.

 

USB 뿐만 아니라 버스를 사용하는 입력 장치도 대응 될 수 있도록 디바이스 드라이버를 표준화 하였다.

 

 

입력 디바이스 드라이버는 개의 모듈간의 통신의 방법으로 사용됩니다.

개의 모듈은 디바이스 드라이버와 이벤트 드라이버 입니다.

 

l  디바이스 드라이버(Device Drivers)

이 모듈은 하드웨어에서 발생하며, 입력 모듈에 이벤트를 제공합니다

 

l  이벤트 핸들러(Event Handlers)

이 모듈은 입력으로부터 이벤트를 가져오며, 다양한 인터페이스로 이벤트가 필요한 곳에 이벤트를 전달합니다

 

 

2.      이벤트 핸들러 디바이스 드라이버

 

응용 프로그램이 입력 장치의 입력 값을 읽기 위한 실제 디바이스 드라이버 파일로 가지 기능을 수행합니다.

 

l  입력 장치에 의해 전달된 입력 값들은 내부 버퍼에 적절한 변환을 거쳐서 저장하는 기능을 수행합니다.

l  저장된 입력 값들을 응용 프로그램에서 읽을 있도록 파일 입출력처리를 담당합니다.

 

Kernel 2.6.12 포함된 이벤트 핸들러 디바이스 드라이버는 종류는 아래와 같습니다.

 

l  키보드 디바이스 드라이버(kdb)

l  마우스 디바이스 드라이버(mousedev, mice)

l  조이스틱 디바이스 드라이버(joydev)

l  이벤트 디바이스 드라이버(evdev)

l  터치 스크린 디바이스 드라이버(tsdev)

 

여기서 우리는 이벤트 디바이스 드라이버에 대해 알아보자.


 

2.1.   이벤트 드라이버 (evdev)

 

Evdev 입력 이벤트 인터페이스에서 발생한다. evdev 커널에서 발생한 이벤트를 프로그램에 직접 전달한다. 전달하는 정보는 시간 정보, 뿐만 아니라 가지 정보를 전달 한다. 현재 API 계속 진화 하고 있다.

디바이스 파일은 모든 입력 장치 (키보드, 터치 스크린, 마우스, 기타 등등) 마다 개씩 생성되고, 이벤트 코드는 하드웨어에 독립적이고, 모두 동일한 아키텍쳐를 가지고 있다.

 

이벤트 핸들러는 http://lxr.falinux.com/source/drivers/input/evdev.c 구현 되어 있다. 

 

이벤트 드라이버에서 읽어 오면 아래의 자료형으로 데이터가 넘어온다.

                  struct input_event{

                      struct timval   time;

                      unsigned short  type;

                      unsigned short  code;

                      unsigned int    value;

                  };


 

3.      마우스 입력 APP 만들기 준비단계

 

3.1.   입력 디바이스 드라이버 정보 읽어 오기

 

S3C2440 보드에 USB 마우스가 연결되면 여기에 대한 정보를 아래처럼 읽어 있다.

 

     [root@falinux nfs]$ cat /proc/bus/input/devices

     I: Bus=0013 Vendor=dead Product=beef Version=0101

     N: Name="s3c2410 TouchScreen"

     P: Phys=

     S: Sysfs=/class/input/input1

     H: Handlers=mouse1 event1 ts1 evbug                

     B: EV=b

     B: KEY=400 0 0 0 0 0 0 0 0 0 0

     B: ABS=1000003

    

     I: Bus=0003 Vendor=046d Product=c01f Version=0110

     N: Name="Logitech USB-PS/2 Optical Mouse"

     P: Phys=usb-s3c24xx-2/input0

     S: Sysfs=/class/input/input3

     H: Handlers=mouse0 event2 ts0 evbug

     B: EV=7

     B: KEY=f0000 0 0 0 0 0 0 0 0

                  B: REL=103

 

B:

 ABS value 절대값을 의미한다

 REL value 상대값을 의미한다.

 

 

3.2.   이벤트 드라이버 정보 읽기

 

USB 마우스의 이벤트 핸들러 (event2) 정보를 읽어 오자

 

     [root@falinux nfs]$ cat /sys/class/input/event2/dev

         13:66 

 

l  주 번호(Major Number) : 13

l  부 번호(Minor Number): 66

 

 

3.3.   mknod

 

이벤트 정보를 읽어 와서 우리는 event2 의 주 번호(13)와 부번호(66)에 대한 정보를 얻었다.

장치를 사용하기 위해하여 target board(ez-2440)에서 mknod를 하자!!

 

[root@falinux nfs]$ mknod /dev/event2 c 13 66

 

실행 결과 에러가 나오는 사람이 있을 것이다. 왜냐 이미 ez-2440 보드의 Ramdisk event2 만들어 놓았기 때문입니다.

따라서 ez-2440 보드를 사용하는 사람은 mknod 따로 필요가 없습니다.

 

 

3.4.   hexdump

그럼 이벤트 드라이버를 통해서 과연 마우스의 입력 값을 받을 수 있는 지 어플리케이션을 작성하기 전에 확인해 봅시다.

 

마우스 디바이스 드라이버 hexdump하여 보면 input_event 형식으로 데이터가 읽혀 지는 것을 볼 수 있습니다.

아래의 명령을 시작하고 마우스를 움직이면 데이터 값을 확인 해볼 수 있습니다.  

   

    [root@falinux nfs]$ hexdump /dev/input/event2

                        time    type code   value

                       000cdf0 01ae 0000 8830 0003 0000 0000 0000 0000

                       000ce00 01ae 0000 a6c4 0003 0002 0000 ffdc ffff

                       000ce10 01ae 0000 a74f 0003 0002 0001 ffff ffff

                       000ce20 01ae 0000 a771 0003 0000 0000 0000 0000

                       000ce30 01ae 0000 c60c 0003 0002 0000 ffda ffff

                       000ce40 01ae 0000 c694 0003 0002 0001 ffff ffff

                       000ce50 01ae 0000 c6b4 0003 0000 0000 0000 0000

                       000ce60 01ae 0000 e552 0003 0002 0000 ffcc ffff

                       000ce70 01ae 0000 e5d8 0003 0002 0001 fffe ffff

                       000ce80 01ae 0000 e5f8 0003 0000 0000 0000 0000

                       000ce90 01ae 0000 0494 0004 0002 0000 ffda ffff

                       000cea0 01ae 0000 051c 0004 0002 0001 fffc ffff  

 

000ce70 01ae 0000 e5d8 0003 0002 0001 fffe ffff

 

:

                  struct input_event{

                      struct timval   time;       // e5f8 0003

                      unsigned short  type;      // 0002

                      unsigned short  code;      // 0001

                      unsigned int    value;     // fffe ffff

                  };

 

value little endian이라 반대로 나옵니다.  

      fffe ffff ->  ffff fffe 입니다.

 

 위에서 언급 했듯이 input 에 이벤트 드라이버에서 반환되는 값은 input_event 형식으로 넘어오고 hexdump 값을 통해 확인 했으니 input_event 값의 마우스의 경우 의미를 알아 봅시다.

 

3.5.   마우스의 input_event 값의 의미

 

마우스가 움직이면 input_evnet 구조체 형식으로 값을 얻을 있습니다.

그럼 우리가 알아 내용은 마우스의  , , , 하로 움직일 , 왼쪽, 오른쪽 버튼을 클릭 했을 경우 input_evnet 값이 어떻게 변화 되는지 알아 봅시다.

 

마우스의 value 값을 [root@falinux nfs]$ cat /proc/bus/input/devices 에서 확인했듯이 REL 상대값 이라는 것을 명심하자.

 

http://lxr.falinux.com/source/include/linux/input.h

 

마우스

input_event

매크로

매크로

X

code

REL_X

0x00

Y

code

REL_Y

Ox01

value

-

움직인 거리 만큼 음수(-) 증가한다.

value

-

움직인 거리 만큼 음수(+) 증가한다.

value

-

움직인 거리 만큼 음수(-) 증가한다.

value

-

움직인 거리 만큼 음수(+) 증가한다.

왼쪽 버튼 클릭

code

BTN_RIGHT

Ox111

오른쪽 버튼 클릭

code

BTN_LEFT

0x110

 


 

4.      마우스 입력 APP 만들기

 

#include <linux/input.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <fcntl.h>                     // O_RDWR , O_NOCTTY 등의 상수 정의

 

typedef struct input_event input_event_t;

 

int main( void)

{       

   int    fd;

   input_event_t  buf;

 memset(&buf, 0,sizeof(input_event_t));                                      // 변수 초기화

                   

   // mouse 드라이버를  open 한다,

   fd = open( "/dev/input/event2", O_RDWR | O_NOCTTY | O_NONBLOCK );        // 디바이스를 open 한다.

   if ( 0 > fd)

   {       

      printf("open errorn");

      return -1;

   }

 

   while ( 1)

   {

      read( fd, &buf, sizeof(input_event_t));                                    // mouse 입력 값을 읽어 온다.  

      switch(buf.code)

      {

              case BTN_LEFT :

                                  printf("왼쪽 버튼이 눌렸습니다.n");                                    

                            break;

                           

              case BTN_RIGHT : 

                                  printf("오른쪽 버튼이 눌렸습니다.n");

                            break;

                                            

              default :                break;

                                                                        

      }

      printf( "mouse read type:%x , cod:%x ,value:%xn", buf.type ,buf.code ,buf.value);    

 

   }

   close( fd);

   return 0;

}

 


 

5.      POLL 이용한 READ 함수 만들기

include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/poll.h>

#include <fcntl.h>                     // O_RDWR , O_NOCTTY 등의 상수 정의

#include <mouse_app.h>

#include <gx.h>

#include <gxbdf.h>

 

int main( void)

{       

   int    fd;

   input_event_t  buf;

   struct pollfd     poll_events;                   // 체크할 event 정보를 갖는 struct

   int    poll_state;

  

// mouse 드라이버를  open 한다,

   fd = open(“dev/input/event2”, O_RDWR | O_NOCTTY | O_NONBLOCK );        // 디바이스를 open 한다.

   if ( 0 > fd)

   {       

      printf("open errorn");

      return -1;

   }

 

   // poll 사용을 위한 준비  

   poll_events.fd        = fd;

   poll_events.events    = POLLIN | POLLERR;          // 수신된 자료가 있는지, 에러가 있는지

   poll_events.revents   = 0;

 

   while ( 1)

   {

      poll_state = poll(                                    // poll() 호출하여 event 발생 여부 확인    

                         (struct pollfd*)&poll_events,       // event 등록 변수

                                                   1,   // 체크할 pollfd 개수

                                                1000    // time out 시간

                       );

 

      if ( 0 < poll_state)                                   // 발생한 event 있음

      {    

         if ( poll_events.revents & POLLIN)                  // event 자료 수신

         {

            read( fd, &buf, sizeof(input_event_t));        // mouse 값을 읽어 온다.

 

switch(buf.code)

            {

                             case BTN_LEFT :   printf("왼쪽 버튼이 눌렸습니다.n");       break;

                                      

                       case BTN_RIGHT:    printf("오른쪽 버튼이 눌렸습니다.n"); break;

                                                                                  

                       default :   break;

            }

 

printf( "mouse read type:%x , cod:%x ,value:%xn", buf.type,buf.code,buf.value);     

         }

 

         else if ( poll_events.revents & POLLERR)      // event 에러?

         {

            printf( "마우스 입력에 에러 발생  프로그램 종료");

            break;

         }

      }

   }

   close( fd);

   return 0;

}


 

6.      마우스 입력을 LCD 표시하기

 

Gxlib 사용하여 ez-2440 보드에 LCD 설치하여 마우스 입력 값을 화면에 표시하기

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/poll.h>

#include <fcntl.h>                                 // O_RDWR , O_NOCTTY 등의 상수 정의

#include <mouse_app.h>

#include <gx.h>

#include <gxbdf.h>

 

mouse_t  g_mouse;

 

int main( void)

{       

   int    fd;

   int    cnt;

   input_event_t  buf;

   struct pollfd     poll_events;                    // 체크할 event 정보를 갖는 struct

   int    poll_state;

  

   dc_t    *dc_screen;                            // 화면 Device Context

   

                   memset(&buf, 0,sizeof(input_event_t));   // 변수 초기화

                   

   // mouse 드라이버를  open 한다,

   fd = open("/dev/input/event2", O_RDWR | O_NOCTTY | O_NONBLOCK );        // 디바이스를 open 한다.

   if ( 0 > fd)

   {       

      printf("open errorn");

      return -1;

   }

 

 

 

   // poll 사용을 위한 준비  

   poll_events.fd        = fd;

   poll_events.events    = POLLIN | POLLERR;          // 수신된 자료가 있는지, 에러가 있는지

   poll_events.revents   = 0;

 

   if( gx_init( "/dev/fb"))                              // gxLib 초기화

   {

                  gx_print_error("gx init errorn");           // 실행 에러 내용을 출력

   }

   else

   {

       if(!( dc_screen = gx_get_screen_dc()))             // 화면 출력을 위한 스크린 DC 구함

       {

           gx_print_error( "get dc errorn");              // 실행 에러 내용을

       }

       else

       {   // 화면을 지운다.  

           gx_clear( dc_screen, gx_color( 0, 0, 0, 255));

       }

   }

  

 

 

   while ( 1)

   {

      poll_state = poll(                                   // poll() 호출하여 event 발생 여부 확인    

                         (struct pollfd*)&poll_events,      // event 등록 변수

                                                1,     // 체크할 pollfd 개수

                                             1000     // time out 시간

                       );

 

      if ( 0 < poll_state)                             // 발생한 event 있음

      {    

         if ( poll_events.revents & POLLIN)            // event 자료 수신

         {

            cnt = read( fd, &buf, sizeof(input_event_t));   // mouse 값을 읽어 온다.

 

            //gxlib 그린다. 

            switch(buf.code)

            {

                         case BTN_LEFT:

                                       dc_screen->pen_color    = gx_color( 255, 255, 255, 0);

                                       dc_screen->brush_color  = gx_color( 255,   0,   0, 255); 

                                       gx_circle( dc_screen, 150, 150,  70);        

                                       printf("왼쪽 버튼이 눌렸습니다.n");                                    

                                       break;

                                      

                         case BTN_RIGHT: 

                                       gx_clear( dc_screen, gx_color( 0, 0, 0, 255)); 

                                       printf("오른쪽 버튼이 눌렸습니다.n");

                                       break;

                        

                         case REL_X:

                                       g_mouse.x += (int)buf.value;

 

                                       if(g_mouse.x <=0)

                                       {

                                                        g_mouse.x =0;                                                                    

                                       }

                                       else if(g_mouse.x >=gx_fb.width)       // x 최대 값을 벗어 나지 않게 한다.

                                       {

                                                        g_mouse.x=gx_fb.width;

                                       }

                                          break;

                                       

                        case REL_Y:

                                       g_mouse.y += (int)buf.value;

                                       if(g_mouse.y <=0)

                                       {

                                                        g_mouse.y =0;                                                                    

                                       }

                                       else if(g_mouse.y >=gx_fb.height)      // y 최대 값을 벗어나지 않게 한다.

                                       {

                                                        g_mouse.y=gx_fb.height;

                                       }                                         

                                       break;        

                                                                 

                                         default :                                              

                                                           break;

                                                                                    

            }

 

            // 화면에 표시 한다.

            dc_screen->pen_color    = gx_color( 255, 255, 255, 0);

            dc_screen->brush_color  = gx_color( 255,   0,   0, 255); 

           

            printf("x:%d  y:%dn",g_mouse.x,g_mouse.y);

            gx_circle( dc_screen, g_mouse.x, g_mouse.y,  5);

            //printf( "mouse read type:%x , cod:%x ,value:%xn", buf.type,buf.code,buf.value);    

         }

         else if ( poll_events.revents & POLLERR)      // event 에러?

         {

            printf( "마우스 입력에 에러 발생  프로그램 종료");

            break;

         }

      }

   }

   close( fd);

   gx_close();

 

   return 0;

}


 

7.      마치며

 

장치 파일 open , 현재는 무조건

 

 

7.1.   참고 자료

 

l  Poll 대한 자료 예제 소스

-          http://forum.falinux.com/zbxe/?mid=network_programming&page=2&document_srl=405838&listStyle=&cpage=

l  Gxlib 관련 자료 예제 소스

-          http://forum.falinux.com/zbxe/?mid=gxLib

l  입력 디바이스 드라이버 관련 자료

-          http://lxr.falinux.com/source/Documentation/input/input.txt

-          유영창 <터치 스크린과 리눅스 디바이스 드라이버>