9. Asynchronous notification of key usage (detailed)

Posted by sam06 on Sat, 25 May 2019 18:28:32 +0200

The application layers of previous studies were:

1)Query: Read Always

2)Interrupt mode. Also read until interrupt process wakes up

3)Poll mechanism: always sleep in poll function, read once at a certain time

All three of the above are for the application to read proactively. In this section, we learn about asynchronous notification. Its purpose is to tell the application proactively when the driver layer has data, and then read the application again so that the application can do other things without having to read all the time.

For example, kill-9 pid, actually kills the process by signaling, kills sending data 9 to the process with the specified id number

1. How do I receive the signal?

To get the signal through the signal function, let's look at the following examples:

Header function:

sighandler_t signal(int signum, sighandler_t handler); 

Function description: Make a signal correspond to a function and call the corresponding function whenever the signal is received.

Header file: #include <signal.h>

Parameter 1: Indicates the type of signal to be processed

There are several kinds of signals:

  • SIGINT Keyboard interrupt (e.g. break, ctrl+c key pressed)
  • SIGUSR1 User-defined signal 1,kill USR1(10) signal
  • SIGUSR2 user-defined signal 2, kill USR2(12) signal

Parameter 2: How the signal needs to be processed after it is generated, which can be a function

The code is as follows:

#include <stdio.h>
#include <signal.h>

void my_signal_run(int signum)       //Signal processing function
{
   static int run_cnt=0;
   printf("signal = %d, %d count\r\n",signum,++count);
}

int main(int argc,char **argv)
{
   signal(SIGUSR1,my_signal_run);  //call signal Function to give the specified signal SIGUSR1 And processing functions my_signal_run Corresponding.
  while(1)
  {
   sleep(
1000); //Do something else,Sleep 1 s   }    return 0; }

After running, using kill-10 802, you can see that my_signal_run() is called to print data when a single signal USR1(10) is generated.

# kill -10 802

# signal = 10, 1 count

# kill -10 802

# signal = 10, 2 count

2. Implement asynchronous notifications

Requirement:

  • 1. The application is to register the signal processing function and use the signal function
  • 2. Who is going to send it?Drive hair
  • 3. To whom?The driver is sent to the application, but the application must tell the driver PID,
  • 4. How?Driver calls kill_fasync function

3 Write the driver first, we modified on the previous interrupt program.

3.1 Defines the asynchronous signal structure variable:

static struct fasync_struct * button_async;

3.2 Add members to the file_operations structure.fasync function and write the function

static struct file_operations third_drv_fops={
         .owner = THIS_MODULE,
         .open = fourth_drv_open,
         .read = fourth _drv_read,
       .release= fourth _drv_class,   
      .poll = fourth _poll,
      .fasync = fourth_fasync             //Add Initialized Asynchronous Signal Function
};

static int fourth_fasync (int fd, struct file *file, int on)
{
  return fasync_helper(fd, file, on, & button_async); //Initialization button_async structural morphology,Can be used kill_fasync()Yes
}

What is the use of the member.fasync function?

Is called by the application, as you will see in Section 4 below.*

3.3 Signal sent in buttons_irq interrupt service function:

kill_fasync(&button_async, SIGIO, POLL_IN);

  //Send when there is an interrupt SIGIO Signal to Application Layer,The application layer triggers the SIGIO Functions corresponding to signals

The 3.4 driver code is as follows:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>  
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>                      
#include <linux/poll.h>                  


static struct class *fourthdrv_class;                 
static struct class_device   *fourthdrv_class_devs; 

 
/*    Declare wait queue type interrupt button_wait      */
static DECLARE_WAIT_QUEUE_HEAD(button_wait);

 
/*    Asynchronous signal structure variable    */
static struct fasync_struct * button_async;

 

/*
  * Define interrupt event flag
  * 0:Enter Waiting Queue 1: Exit Waiting Queue
  */
static int even_press=0;                          

 

/*
  * Define global variable key_val, save key state
  */
static int key_val=0;                          

 

/*
  *Pin Description Structure
  */
 struct pin_desc{

   unsigned int  pin;

   unsigned int  pin_status;

};


/*
  *key Initial state (not pressed): 0x01,0x02,0x03,0x04
  *key Status (press): 0x81,0x82,0x83,0x84
  */

         struct pin_desc  pins_desc[4]={
                   {S3C2410_GPF0,0x01 },
                   {S3C2410_GPF2, 0x02 },
                   {S3C2410_GPG3, 0x03 },
                   {S3C2410_GPG11,0x04},

} ;

 
int  fourth_drv_class(struct inode *inode, struct file  *file)  //Uninstallation Interrupt
{
  free_irq(IRQ_EINT0,&pins_desc[0]);
  free_irq(IRQ_EINT2,&pins_desc[1]);
  free_irq(IRQ_EINT11,&pins_desc[2]);
  free_irq(IRQ_EINT19,&pins_desc[3]);
  return 0;
}

 
/*
  *   Determine whether rising or falling edges
  */
static irqreturn_t  buttons_irq (int irq, void *dev_id)       //Interrupt Service Function
{
     struct pin_desc *pindesc=(struct pin_desc *)dev_id;     //Get Pin Description Structure
      unsigned int  pin_val=0;                                              
      pin_val=s3c2410_gpio_getpin(pindesc->pin);
        if(pin_val)
        {
                   /*No press (down edge), clear 0x80*/        
                   key_val=pindesc->pin_status&0xef;
         }
         else
         {
                   /*Press (Rise), plus 0x80*/
                   key_val=pindesc->pin_status|0x80;
         }
             
             even_press=1;                                        //Exit waiting queue
            wake_up_interruptible(&button_wait);                  //Wake Up Interrupt
            kill_fasync(&button_async, SIGIO, POLL_IN);        //Send out SIGIO Signal to Application Layer                        

         return IRQ_RETVAL(IRQ_HANDLED);                   
}

static int fourth_drv_open(struct inode *inode, struct file  *file)
{
   request_irq(IRQ_EINT0,buttons_irq,IRQT_BOTHEDGE,"S1",&pins_desc[0]);
   request_irq(IRQ_EINT2, buttons_irq,IRQT_BOTHEDGE, "S2", &pins_desc[1]);
   request_irq(IRQ_EINT11, buttons_irq,IRQT_BOTHEDGE, "S3", &pins_desc[2]);
   request_irq(IRQ_EINT19, buttons_irq,IRQT_BOTHEDGE, "S4", &pins_desc[3]);
   return 0;
}

static int fourth_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{       
         /*Will interrupt into waiting queue (hibernate)*/
         wait_event_interruptible(button_wait, even_press);           

        /*Press key, exit waiting queue, upload key_val s to user layer*/
         if(copy_to_user(buf,&key_val,sizeof(key_val)))
          return EFAULT;

         even_press=0;      
  return 0;
}

static unsigned fourth_poll(struct file *file, poll_table *wait)
 {
                   unsigned int mask = 0;
                   poll_wait(file, &button_wait, wait); // Will not sleep immediately        
                   if (even_press)
                            mask |= POLLIN | POLLRDNORM;     

                   return mask;
         }

 

static int fourth_fasync (int fd, struct file *file, int on)
{
         return fasync_helper(fd, file, on, & button_async); //Initialization button_async structural morphology,Can be used kill_fasync()Yes
}

 

static struct file_operations fourth_drv_fops={
         .owner = THIS_MODULE,
         .open = fourth_drv_open,
         .read = fourth_drv_read,
        .release=fourth_drv_class,    //Inside Add free_irq function,To release interrupt service functions
        .poll = fourth_poll,
        .fasync= fourth_fasync,     //Initialize Asynchronous Signal Function
};

 

volatile int fourth_major;
static int fourth_drv_init(void)
{
   fourth_major=register_chrdev(0,"fourth_drv",&fourth_drv_fops);  //Create Driver
   fourthdrv_class=class_create(THIS_MODULE,"fourth_dev");    //Create Class Name
   fourthdrv_class_devs=class_device_create(fourthdrv_class, NULL, MKDEV(fourth_major,0), NULL,"buttons");  
 return 0;

}

static int fourth_drv_exit(void)
{
 unregister_chrdev(fourth_major,"fourth_drv");            //Unload Driver
class_device_unregister(fourthdrv_class_devs);         //Uninstall Class Device
class_destroy(fourthdrv_class);                              //Unload Class
return 0;
}

module_init(fourth_drv_init);
module_exit(fourth_drv_exit);
MODULE_LICENSE("GPL v2");   
                    

4 Write application test program

The steps are as follows:

1) signal(SIGIO, my_signal_fun);  

Call the signal function, enter my_signal_fun when a SIGIO signal is received, and read the driver layer's data

2) fcntl(fd,F_SETOWN,getpid());  

Specifies that the process is the "owner" of the fd file. When the kernel receives the F_SETOWN command, it sets the PID (driver does not need to process), so the fd driver knows which process to send

3) oflags=fcntl(fd,F_GETFL);

Get fd's file status flag

4) fcntl(fd,F_SETFL, oflags| FASYNC );

Adding a FASYNC status flag invokes the member.fasync function in the driver and executes fasync_helper() to initialize the asynchronous signal structure

Once these four steps are executed, the process receives the SIGIO signal from the driver layer

The application layer code is as follows:

#include <sys/types.h>    
#include <sys/stat.h>    
#include <stdio.h>
#include <string.h>
#include <poll.h>               
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>


int fd,ret;
void my_signal_fun(int signame)      //There's a signal coming
{
   read( fd, &ret, 1);              //Read Driver Layer Data
   printf("key_vale=0X%x\r\n",ret); 

}

 
/*useg:    fourthtext   */
int main(int argc,char **argv)
{
  int oflag;
  unsigned int val=0;      
  fd=open("/dev/buttons",O_RDWR); 
  if(fd<0)
        {printf("can't open!!!\n");
       return -1;}

   signal(SIGIO,my_signal_fun); //Specified signal SIGIO And processing functions my_signal_run Corresponding
   fcntl( fd, F_SETOWN, getip());  //Specify the process as fd Owner of,Send out pid Give Driver
   oflag=fcntl( fd, F_GETFL);   //Obtain fd File Flag Status
   fcntl( fd, F_SETFL, oflag|FASYNC);  //Add to FASYNC Status flag, calling driver layer.fasync Member function 

   while(1)
   {
         sleep(1000);                  //Do something else
   }
   return 0;

}

5 Run to view results

 

 

Start next section: Mutual exclusion and blocking mechanism of keys

Topics: Linux Hibernate