Poll operation
1, poll operation process:
Poll is a system call, and its kernel entry function for Sys_poll,sys_poll almost no matter what processing directly calls the Do_sys_poll,do_sys_poll run process can be divided into three parts:
1, copy the user's incoming POLLFD array to the kernel space due to the copy operation and array length correlation. Time this is an O (n) operation, this step of the code in Do_sys_poll contains the part from the beginning of the function to the call to Do_poll.
2, query each file describes the status of the corresponding device, assuming that the device is not ready, add an entry in the waiting queue for the device and continue to query the status of the next device.
After querying the complete device, it is assumed that none of the devices are ready, then the current process waits are suspended. Until the device is ready or timed out, the suspend operation is performed by calling Schedule_timeout. After the device is ready, the process is notified to continue execution, and then traverses all the devices again to find the ready device. This step is due to traverse all devices two times. The time complexity is also O (n), where the face does not contain the wait time. The relevant code is in the Do_poll function.
3, the acquisition of data to the user space and run the release of memory and the stripping wait queue, such as the aftermath of work, to the user space copy data and stripping wait queue operations such as the time complexity of the same is O (n), the detailed code contains the Do_sys_poll function in the call Do_poll to the end of the section.
2, code Writing 1, in the file_operations structure to add poll
static struct file_operations button_sdv_fops ={.owner = This_module,.open = Button_dev_open,.read = Button_dev_ Read,.release = Button_dev_close,.poll= Button_dev_poll,};
2, complete Button_dev_poll function
static unsigned int button_dev_poll (struct file *file, poll_table * wait) {unsigned int mask =0;poll_wait (file, &button _wait_q, wait);//Hang the current process into the queue, not immediately hibernate if (ev_press) Mask |=pollin | Pollrdnorm;return Mask;}
Ev_press is the interrupt event occurrence flag in the previous blog post, assuming that the interrupt action occurred, the mask value will be told to the kernel. The meaning of the value of mask:
Constant |
Description |
Pollin |
Normal or priority with data-readable |
Pollrdnorm |
Plain Data readable |
Pollrdband |
Priority with data-readable |
Pollpri |
High-priority data readable |
Pollout |
Plain data can be written |
Pollwrnorm |
Plain data can be written |
Pollwrband |
Priority with data writable |
Pollerr |
Error occurred |
Pollhup |
Occurs pending |
Pollnval |
Descriptive narrative word is not an open file |
3. Test program Writing
RET = Poll (FDS, 1, 3000);
Poll function Prototypes:
int poll (struct POLLFD *fds, nfds_t nfds, int timeout);
Among them: The POLLFD structure is:
struct POLLFD { int fd; /* File descriptor */short events; /* Requested events */short revents; /* Returned events * * };
FD is the device to query. Events is expected to get the event, here we set him to: Pollin
FDS defines an array that stores all the devices that need to be poll. The poll operation will query these devices at the same time.
Nfds the number of files to query
Timeout is time-out
Driver Complete code:
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h > #include <asm/io.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/irq.h > #include <asm/uaccess.h> #include <asm/irq.h> #include <mach/regs-gpio.h> #include <mach/ irqs.h>//this in/opt/embedsky/linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach path # include <linux/interrupt.h > #include <linux/poll.h>module_license ("Dual BSD/GPL"); static struct class *buttondrv_class;static struct Class_devices *buttondrv_class_dev;/* */static declare_wait_queue_head (BUTTON_WAIT_Q);/* Interrupt event Flag, interrupt service program will set him 1, The read function resets 0*/static volatile int ev_press =0;volatile unsigned long *gpfcon = null;volatile unsigned long *gpfdat = null;st atic unsigned keyval;struct pin_desc{unsigned int pin;unsigned int key_value;};/ * When the button is pressed: 0x01 0x02 0x03 0x04*//* When the button is released: 0x81 0x82 0x83 0x84*/struct pin_desc pins_desc[4] ={{s3c2410_gpf1,0x01},{s3c2410_ gpf4,0x02},{s3c2410_gpf2,0x03},{s3c2410_gpf0,0x04},};/* * Determine key value */static irqreturn_t buttons_irq (int irq,void *dev_id) {struct Pin_desc * Pindesc = (struct Pin_desc *) dev_id;unsigned int pinval;pinval = S3c2410_gpio_getpin (Pindesc-pin); if (pin val)//Loosen {keyval = 0x80|pindesc->key_value;} Else{keyval = Pindesc->key_value;} Ev_press =1;//interrupt occurs wake_up_interruptible (&button_wait_q);p rintk ("button is pressed:%d \ n", IRQ); return irq_ HANDLED;} The static int button_dev_open (struct inode *inode, struct file* file) {//Configure the PIN gpf0,1,2,4 for the key to the input pin REQUEST_IRQ (irq_eint1, BUTTONS_IRQ, Irq_type_edge_both, "Key1", &pins_desc[0]); REQUEST_IRQ (IRQ_EINT4,BUTTONS_IRQ, IRQ_TYPE_EDGE_BOTH, "Key2", &pins_desc[1]); REQUEST_IRQ (IRQ_EINT2,BUTTONS_IRQ, Irq_type_edge_both, "Key3", &pins_desc[2]); REQUEST_IRQ (IRQ_EINT0,BUTTONS_IRQ, Irq_type_edge_both, "Key4", &pins_desc[3]); return 0;} ssize_t button_dev_read (struct file *file,char __user *buf,size_t size,loff_t *ppos) {if (size!=1) {return-einval;} /* Assume that no keystroke action occurs on the Hibernate */waIt_event_interruptible (button_wait_q,ev_press);/* Assuming that a keystroke action occurs, return directly to */copy_to_user (buf,&keyval,1); ev_press = 0; return 0;} int button_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 unsigned int button_dev_poll (struct file *file, poll_table * wait) {unsigned int mask =0;poll_wait (file, &button _wait_q, wait);//Hang the current process into the queue, not immediately hibernate if (ev_press) Mask |=pollin | Pollrdnorm;return Mask;} static struct file_operations button_sdv_fops ={.owner = This_module,.open = Button_dev_open,.read = Button_dev_read,.re Lease = button_dev_close,.poll= button_dev_poll,};int major;static int button_dev_init (void)//Entry function {major = Register_ Chrdev (0, "Button_drv", &button_sdv_fops); buttondrv_class = Class_create (This_module, "button_drv"); if (IS_ERR ( Buttondrv_class)) return Ptr_err (Buttondrv_class); buttondrv_class_dev= device_create (buttondrv_class,nUll,mkdev (major,0), NULL, "Wq_button"), if (Unlikely (Is_err)) return Buttondrv_class_dev (Ptr_err dev);/* Map Physical Address */gpfcon = (volatile unsigned long *) Ioremap (0x56000050, +); Gpfdat = Gpfcon + 1;return 0;} static void Button_dev_exit (void) {Unregister_chrdev (Major, "Button_drv");d Evice_unregister (Buttondrv_class_dev); Class_destroy (Buttondrv_class); Iounmap (Gpfcon);} Module_init (Button_dev_init); Module_exit (Button_dev_exit);
Test procedure complete code:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <poll.h>int Main (int argc, char **argv) {int ret=0;int cnt=0;int fd;unsigned char key_val;struct pollfd fds[1];fd = O Pen ("/dev/wq_button", O_RDWR), if (fd<0) {printf ("can ' t open \ n");} FDS[0].FD = fd;fds[0].events = Pollin;while (1) {ret = poll (FDS, 1, +); if (ret = = 0) {printf ("Time Out \ n");} Else{read (fd,&key_val,1);p rintf ("Key_val = 0x%x\n", key_val);}} return 0;}
Poll operation of Linux drivers