intput subsystem

1, a first version of the key driver: day07 / 04
   
   // kernel module of the basic requirements
   init.h the module.h the LICENSE
   
   struct the cdev btn_cdev;
   
   btn_read (...)
   {
       // blocked
         queue sleep
       // nonblocking
       
       will copy data to user space
   }
   
   struct the file_operations btn_fops =
   {
        .Open
        .release // exclusive access device race
        .read = btn_read // wait queue
   }
   
   timer_func / delay_work_func ()
   {
       determines which key is triggered
       by reading electrical pins Analyzing the trigger is pressed flat position or release trigger
       to save key
       wake sleeping processes
   }
   btn_isr ()
   {
       delay jitter or the bottom half of the way to debounce
   }
   int the __init btn_drv_init (void)
   {
        Application device number register
        initialization operation of the set of functions cdev //
        Register cdev
        automatically generated device file
        registering interrupt
   }
   void btn_drv_exit The __exit (void)
   {
   }
   the module_init (btn_drv_init);
   the module_exit (btn_drv_exit)
 
  above procedures problems:
     1) the normalized key value problem
     
     2) key buffer
        circular buffer queue
        attention to solve a race condition
     3) hold the button
        to open a new timer key after pressing the key save
        the timer time to time to keep a key buffer key
        until you release the key to stop the timer   
        
2, the second version of the key drivers: input subsystem
  2.1 What is the input subsystem
   with the linux kernel to support the growing number of hardware
   found in a class of devices, not only the input output: keyboard mouse touch screen ...
   this type of equipment in the realization of the driver must resolve
      device number
      cdev
      Device automatically creates a file
      of the key buffer
      hold the
      ... ...
   core designer of the type of equipment and hardware independent code implemented in the kernel finished
   the portion of the code is referred to as input subsystem
 2.2 input subsystem acting  
   driving section engineer in achieving a particular input device driver
   can reuse the part of the code, the code focused on driving-related programming hardware
   to shorten the time of programming input device drivers
 use 2.3 input subsystem (the portion of the code multiplexing method )
     
     the INPUT subsystem core file: drivers / input / input.c
     
     core data structure
         struct input_dev
         {
             name
             // the device will identify which events trigger which events will not
             evbit
             / * report which identifies EV_KEY key code does not report what
               buttons encoding * /
             keybit
             . . .
         }
     Using the steps:
         1) apply a variable input_dev (kmalloc)
            * input_allocate_device input_dev struct (void)
         2) variable initialization input_dev
         
         3) registered input_dev variable
            int input_register_device (struct input_dev * dev)
         4) hardware operations
            registered interrupt
            remove jitter
            which key trigger judgment
            judgment is to press the trigger or trigger the release of
         
         5) report events (save key wake the sleeping process)   
            void input_event (struct input_dev * dev,
         unsigned int type, unsigned int code, int value)
         dev, who report
         type, report the event type
         code, when different types of events is not the same meaning
               if when EV_KEY , its meaning is the key code
         value, different event types different meaning
               if EV_KEY when, on behalf of the trigger or press release trigger
               0, release trigger
               1, press the trigger
         6) cancellation input_dev variable
            void input_unregister_device (struct input_dev * dev)
         7) release input_dev variable
            void input_free_device (struct input_dev * dev)
            
   Note: After installing the module corresponds to experiment to find a device file how?
         There are two ways, may determine the corresponding device file
         . 1) LS / dev / INPUT / * Event
            the insmod btn_drv.ko
            LS / dev / INPUT / * Event
         2) CAT / proc / Bus / INPUT / Devices
   verification: Driver effective of
         hexdump / dev / input / event5      
serial No. second code value microseconds type
0000000 d7c4 54a4 1e63 0001 0001 0067 0001 0000
0000010 0001 0000 0000 d7c4 54a4 1e70 0000 0000
0.00002 million d7c4 54a4 1BFC 0004 0001 0067 0000 0000
0000030 d7c4 54a4 1c00 0004 0000 0000 0000                        0000
 
  requirements class: possible key driver 7 according to the above steps (can read)
 
  and higher requirements: Study linux subsystem code
      
    Drivers / INPUT / to the input.c
    input_init ()
    {
        // main function operating device number corresponding to a set of device 13 is input_fops
        the register_chrdev (INPUT_MAJOR, "INPUT", & input_fops);
    }

     
    Open ( "/ dev / the INPUT / event5", ....)                
    ---------------------------------- ---------
    SYS_OPEN ()
    {
       struct File btn_file; // global
       
       input_fops.open (the inode, & btn_file) input_open_file //
       {
          // the minor number corresponds to locate the device Handler
          // find it for a key device the handler is evdev_handler
          handler input_table = [iminor (the inode) >>. 5];
          
          // evdev_handler the recorded address set operation function returns
          new_fops = fops_get (handler-> FOPS)
          
          // handler to modify btn_file.f_op recorded the set of functions operating
          File-> = new_fops the f_op;
       }  
    }

 

#include " ../../global.h " 

#include <Linux / Input.h> 
#include <Linux / interrupt.h> 
#include <Linux / gpio.h> 
#include <Mach / platform.h> static struct input_dev btn_input * = NULL; 
typedef struct btn_desc 
{ char * name; // name int IRQ; // interrupt number 
    unsigned Short code; // key code value int GPIO; // pin numbers } btn_desc_t; 
btn_desc_t buttons [] = 
{ 
    {

 

    
    
    
"up", IRQ_GPIO_A_START+28, KEY_UP, PAD_GPIO_A+28},
    {"down", IRQ_GPIO_B_START+30, KEY_DOWN, PAD_GPIO_B+30},
    {"left", IRQ_GPIO_B_START+31, KEY_LEFT, PAD_GPIO_B+31},
    {"right", IRQ_GPIO_B_START+9, KEY_RIGHT, PAD_GPIO_B+9},

};
struct timer_list btn_timer;

irqreturn_t btn_isr(int irq, void *dev) 
{ 
    / * pass key description * / 
    btn_timer.data = (unsigned Long ) dev; 

    mod_timer ( & btn_timer, of jiffies + HZ / 100 ); 

    return IRQ_HANDLED; 
} 
void btn_timer_func (unsigned Long Data) 
{ 
    int STAT = 0 ;
     / * get the keys which triggered * / 
    btn_desc_t * pData = (btn_desc_t * ) the Data;
     / * judge is to press the trigger or trigger release * / 
    STAT = gpio_get_value (pdata-> the GPIO); 

    / * 5 report events (save key wake up the sleeping process) * /
    input_event (btn_input, EV_KEY, pData -> code,! STAT); 
    input_event (btn_input, EV_SYN, 0 , 0 ); 

} 
int the __init btn_drv_init ( void ) 
{ 
    int I = 0 ;
     int RET = 0 ;
     / * . 1 Application input_dev variable * / 
    btn_input = input_allocate_device ();
     / * 2 input_dev initialize variables * / 
    btn_input -> name = " mybuttons " ;
     // segment error
     //strcpy (btn_input-> name, "mybuttons"); 
    / * 2.1 Configuring the device will report the event type * / 
    __set_bit (EV_SYN, btn_input -> evbit); 
    __set_bit (EV_KEY, btn_input -> evbit); 
    __set_bit (EV_REP, btn_input -> evbit);
     / * report the 2.2 configuration EV_KEY key code * / 
    for (; I <ARRAY_SIZE (buttons); I ++ ) 
    { 
        __set_bit (buttons [I] .code, btn_input -> keybit); 
    } 
    / * . 3 Register input_dev variables * / 
    RET = input_register_device (btn_input);
     / * . 4 hardware operations * / 
    for (I =0; i<ARRAY_SIZE(buttons); i++)
    {
        ret = request_irq(buttons[i].irq, btn_isr,
            IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
                          buttons[i].name,
                          buttons+i);
    }
    init_timer(&btn_timer);
    btn_timer.function = btn_timer_func;


    return 0;
}
void __exit btn_drv_exit(void)
{
    int i = 0;

    del_timer(&btn_timer);
    for(; i<ARRAY_SIZE(buttons); i++)
    {
        free_irq(buttons[i].irq, buttons+i);
    }

    /*6注销input_dev变量*/
    input_unregister_device(btn_input);
    /*7释放input_dev变量空间*/
    input_free_device(btn_input);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);


#include <stdio.h>
#include <fcntl.h>
#include <linux/input.h>


//struct input_event key_info;
struct key
{
    long sec;
    long usec;
    unsigned short type;
    unsigned short code;
    int val;
}key_info;

int main(void)
{
    int fd = open("/dev/input/event5",
                   O_RDONLY);

    while(1)
    {
        read(fd, &key_info, sizeof(key_info));
        if(key_info.type == EV_KEY)
        {
            printf("type=%d code=%d value=%d\n",
                    key_info.type, key_info.code,
                    key_info.val);
        }
    }
    close(fd);
    return 0;
}
 
 

 

 

 

Guess you like

Origin www.cnblogs.com/DXGG-Bond/p/11899419.html