character device-driven interrupt key to analyze another technique for character device drivers: Asynchronous notifications-a way to make the driver very active
First, the goal:
When the key is pressed, the driver sequence actively notifies the application that the data is readable, so that the application does not always take the initiative to read the data, concentrate on doing their own thing, the need to come to the door, you can come to the moment on the tall up
Questions to think about:
① Registered Signal Processing function
②, who's signaling? Kernel driver
Who is ③ sent to? APP. The premise is that the app will tell the PID that drives it
How ④? Kell_fasync () function
Second, first on the Ubuntu experience this service:
(1) man signal see how to use the signal function:
Synopsis
#include <signal.h>
typedef void (*sighandler_t) (int);//sighandler_t is a function pointer whose return value is void and the argument is int
sighandler_t signal (int signum, sighandler_t handler);
DESCRIPTION
Signal () Sets the disposition of the signal Signum to handler, which are
Either Sig_ign, SIG_DFL, or the address of a programmer-defined function (a
"Signal handler").
This means: the signal function is to pass the SIGUNM value to the handler function, and the defined handler function takes a parameter Signum
(2) Program content: FASYNC_TESC.C file
compiler directive: Gcc-o fasync fasync_test.c#include <stdio.h> #include <signal.h>void sig_handle (int signum)//Signal value { printf ("Running in sig_handle\n");} int main () {signal (sigusr1,sig_handle); while (1) {sleep (1000);} return 0;}
(3) Run Program & Send signal
./fasync &//Background operation
PS //View the currently running process to find out the PID value
Sending a signal to a process using kill
Man Kill
Kill [-signal |-S signal] pid ...
Kill signal PID means: Send signal to PID corresponding process
KILL-USR1 PID
Print Results
*************************************************************************************************************** ****************************************************************************
Three, Arm-linux application programming
What the app does: Register a signal handler, tell the driver his own PID
The function called by the application is Fcntl (), which has a description in the file
App_fasync.c
/* file compiled instructions are ARM-LINUX-GC C-static-o APP_IRQ app_fasync.c * * #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h># Include <unistd.h>//sleep #include <stdio.h> #include <signal.h>int fd;void signal_handler (int Signum) {unsigned char key_val; Read (fd,&key_val,1); printf ("Key_val = 0x%x\n", key_val); } int main (int argc, char **argv) {int flag; unsigned char key_val;signal (sigio,signal_handler);//signal processing function of the registration process, The processing function receives the Sigio type signal FD = open ("/dev/buttons", O_RDWR); Request External pin Interrupt Service if (FD < 0) {printf ("Can ' t open!\n");} ①app tells the kernel its own pid:f_setown that this time the Fcntl () function "signals to whom?" "The premise of the operation, the app tells the FD pointing device Driver" My PID is a getpid () "Fcntl (FD, F_setown, Getpid ());//② read the status of the current file flag = Fcntl (FD,F_GETFL); ③ Modify the status of the current file, add the asynchronous notification function, add the premise is not to change some of the original state, so the previous step is to read it first, and then here to a bit or fcntl (Fd,f_setfl,flag | Fasync); while (1) {sleep (1000);} return 0;}
Four, drive programming
What to do: the process of using the Kell_fasync () function to signal to the application layer of the PID when there is data
FASYNC.C file
#include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/module.h> #include <linux/device.h>//class_create#include < Mach/regs-gpio.h>//s3c2410_gpf1 #include <mach/hardware.h> #include <linux/interrupt.h>//wait_event _interruptible#include <linux/fs.h> #include <linux/fcntl.h>/* define and initialize the wait queue header */static Declare_wait_queue_ HEAD (BUTTON_WAITQ), static struct class *buttondev_class;static struct device *buttons_device;static struct pin_desc{ unsigned int pin;unsigned int key_val;}; static struct Pin_desc Pins_desc[4] = {{s3c2410_gpf1,0x01},//S3C2410_GPF1 is the GPF1 pin for this "device" number dev_id{s3c2410_gpf4,0x02} , {s3c2410_gpf2,0x03},{s3c2410_gpf0,0x04},}; static int ev_press = 0;static unsigned char key_val;int major;static struct fasync_struct *button_fasync;//button_fasync The struct contains the send to WHO (PID specified)/* Interrupt handler function */static irqreturn_t HANDLE_IRQ (int irq, void *dev_id) {struct Pin_desc *irq_pIndesc = (struct Pin_desc *) dev_id;//unsigned int pinval;pinval = S3c2410_gpio_getpin (Irq_pindesc->pin);//Get Key value: Keys are pressed to return key values 0/*: When pressed, 0x01, 0x02, 0x03, 0x04 *//* key values: Release, 0x81, 0x82, 0x83, 0x84 */if (pinval) {/* Release */key_val = 0x80 | ( Irq_pindesc->key_val);} else{/* Press */key_val = Irq_pindesc->key_val;} Ev_press = 1;/* Indicates that the interrupt has occurred *///wake_up_interruptible (&BUTTON_WAITQ); /* Wake up hibernation *///No Sleep no wake nice!!! Kill_fasync (&button_fasync, SIGIO, poll_in); Signal to app,poll_in is the cause of the signal, Sigio indicates the type of signal to send return irq_handled;} static int Buttons_dev_open (struct inode * inode, struct file * Filp) {/* k1-eint1,k2-eint4,k3-eint2,k4-eint0 * config GPF1, GPF4, GPF2, GPF0 for the corresponding external interrupt pin * Irqt_bothedge should be changed to Irq_type_edge_both */request_irq (Irq_eint1, HANDLE_IRQ, Irq_type_edge_ Falling, "K1", &pins_desc[0]); REQUEST_IRQ (Irq_eint4, HANDLE_IRQ, irq_type_edge_falling, "K2", &pins_desc[1]) ; Request_irq (Irq_eint2, HANDLE_IRQ, irq_type_edge_falling, "K3", &pins_desc[2]); REQUEST_IRQ (IRQ_EINT0, Handle_ IRQ, IRQ_type_edge_falling, "K4", &pins_desc[3]); return 0;} static int buttons_dev_close (struct inode *inode, struct file *file) {FREE_IRQ (irq_eint1,&pins_desc[0]); FREE_IRQ ( IRQ_EINT4,&PINS_DESC[1]); FREE_IRQ (irq_eint2,&pins_desc[2]); FREE_IRQ (irq_eint0,&pins_desc[3]); return 0;} Static ssize_t buttons_dev_read (struct file *file, char __user *user, size_t size,loff_t *ppos) {if (size! = 1) RETURN-EINV al;/* when no key is pressed, hibernate. * i.e. ev_press = 0; * When a button is pressed, an interrupt occurs, and the interrupt handler function wakes up * i.e. ev_press = 1; * After wake up, then continue to pass the data through the Copy_to_user function to the application *///wait_event_interruptible (BUTTON_WAITQ, ev_press);//From here there is no need to sleep for the sake of waiting copy_ To_user (User, &key_val, 1);/* will ev_press clear 0 */ev_press = 0;return 1;} static int Button_drv_fasync (int fd, struct file *filp, int.) {return Fasync_helper (FD, Filp, ON, &button_fas Ync); Initialize/Release Fasync_struct}/* File operations struct for character device */static const struct File_operations buttons_dev_ FoPs = {. owner= this_module,.open= buttons_dev_open,.read= BUTTONS_DEV_READ,.RElease = Buttons_dev_close,.fasync = Button_drv_fasync,//When the application calls Fcntl (FD, F_SETFL, Oflags | Fasync); The final call to the driver's Fasync function, the button_drv_fasync};/* driver entry function */static int buttons_dev_init (void) {/* main device number set to 0 indicates that the main device number is automatically assigned by the system */major = Register_chrdev (0, "Buttons_dev", &buttons_dev_fops);/* Create Buttondev class */buttondev_class = Class_create (THIS_ MODULE, "Buttondev");/* Create a buttons device under the Buttondev class for the application to open the device */buttons_device = Device_create (Buttondev_class, NULL, MKDEV (Major, 0), NULL, "buttons");//return 0;} /* Drive Exit Function */static void buttons_dev_exit (void) {Unregister_chrdev (Major, "Buttons_dev");d Evice_unregister (buttons_ Device); Unload the device under the class Class_destroy (Buttondev_class);//Unload Class}/* module loading and unloading function modification */module_init (buttons_dev_init); Module_exit (Buttons_dev_exit); Module_author ("Clbiao"); Module_description ("Just for Demon"); Module_license ("GPL"); Follow the GPL agreement
Test Results:
V. Summary
The driver supports asynchronous notification mechanism programming steps:
①: API interface for Application layer
static const struct File_operations xxx_dev_fops={
...
. Fasync = Xxx_drv_fasync,//call to the application layer to initialize the fasync_struct struct
...
}
②: The bottom-level implementation of the application layer api- : for setting up fasync_struct, telling the driver "phone number", just come to me when something's wrong.
The static struct fasync_struct *xxx_button_fasync;//process will transmit the PID "phone number" to the side.
static int Xxx_drv_fasync (int fd, struct file *filp, int on)
Return Fasync_helper (FD, Filp, on, &xxx_fasync_struct); Initialize/release fasync_struct
Application Test Programming:
Signal processing function for ① registration process
Signal (Sigio,signal_handler);
② write the signal handler function: Put the operation to get the resource in the face, usually read () or Operation function
void Signal_handler (int signum)
{
...
Action
...
}
③ actively tell the kernel "phone number", let him notice when something happens
int fd;//Process Device file
int flag;//is used to save the identity of the process before adding the asynchronous notification identity
Fcntl (FD, F_setown, Getpid ());
Flag = Fcntl (FD,F_GETFL);
Fcntl (Fd,f_setfl,flag | Fasync);
Asynchronous communication of character devices