Obtain the key value in linux drive interruption mode and in linux drive interruption Mode
How to get the key value in linux drive interruption Mode
Certificate ------------------------------------------------------------------------------------------------------------------------------------------------------
Review of interrupt handling in Single Chip Microcomputer -------------------------------------------------------------------------------------------------------------------------------------------------------
1. Interrupt framework
Constructed in trap_int
Trap_intA function is a jump command.
B...
B...
B vector_irq + stubs_offset; vector_irq is the link address stubs_offset is the offset address
Vector_irq:Asm_do_IRQ:
Handling of interruptions.
Request_irq registration interrupted
Request_irq (irq, handle, irqflags, devname, dev_id)
1. Allocate irqaction Structure
2. setup_irq (irq, action)
0. Allocate an irqaction Structure
A. In irq_desc [irq]-> action
B. desc-> chip-> settype
C. desc-> chip-> startup/enable
| Irq |
Hardware Interrupt number to be applied |
+ |
| Handle |
Is the interrupt processing function registered with the System |
Is a callback function. When the main function is short, the system will call this function and pass dev_id to it. |
| Irqflags |
Is the Interrupt Processing attribute |
|
Free_irq unmount interrupted
Free_irq (irq, dev_id)
1. outbound links
2. Interruption prohibited
2. coding 1. Apply for IRQ
Here I would like to explain: (To Me, I encountered a problem when using the request_irq function. IRQ_EINT1, IRQ_EINT4, IRQ_EINT2, and IRQ_EINT0 macros cannot be found. The final cause is found, there are some minor issues with the kernel tree path when I configure eclipse. The irqs. h file is in/Linux-2.6.30.4/arch/arm/mach-s3c2410/includeUnder this path, I thought this will also have this path in the mach-s3c2440, in fact, it is not. Some pins are also defined in the 2410 path. Note that ).
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]);
Here, pins_desc is a struct array.
struct pin_desc pins_desc[4] ={{S3C2410_GPF1,0x01},{S3C2410_GPF4,0x02},{S3C2410_GPF2,0x03},{S3C2410_GPF0,0x04},};
The array contains the four interrupt pins and the key values of the pins.
The struct prototype is as follows:
struct pin_desc{unsigned int pin;unsigned int key_value;};
2. Write interrupt processing functions
Static irqreturn_t buttons_irq (int irq, void * dev_id) {struct pin_desc * pindesc = (struct pin_desc *) dev_id; unsigned int pinval; pinval = trim (pindesc-> pin ); if (pinval) // release {keyval = 0x80 | pindesc-> key_value;} else {keyval = pindesc-> key_value;} ev_press = 1; // wake_up_interruptible (& button_wait_q); printk ("button is pressed: % d \ n", irq); return IRQ_HANDLED ;}Note:
Pindesc: This structure shows which button is pressed
S3c2410_gpio_getpin: this function is provided by the kernel to obtain the high and low levels of the current pin.
Ev_press: indicates the interrupt event. The interrupt service sets it to 1, and the read function sets it to 0.
Wake_up_interruptible (& button_wait_q); the sleep process is wakened and the process registered to the waiting queue is wakened. In this case, button_wait_q is obtained in the following way:
Static DECLARE_WAIT_QUEUE_HEAD (button_wait_q); generates a waiting queue header wait_queue_head_t named button_wait_q
3. Modify the read function
Ssize_t button_dev_read (struct file * file, char _ user * buf, size_t size, loff_t * ppos) {if (size! = 1) {return-EINVAL;}/* if no button action occurs, sleep */wait_event_interruptible (button_wait_q, ev_press);/* If a button action occurs, directly return */copy_to_user (buf, & keyval, 1); ev_press = 0; return 0 ;}
Where:
Wait_event_interruptible (button_wait_q, ev_press); If ev_press is false, it will sleep
Ev_press = 0; the interruption event flag is cleared every time you finish reading.
4. Fill in the file_operations struct
static struct file_operations button_sdv_fops ={.owner = THIS_MODULE,.open = button_dev_open,.read = button_dev_read,.release = button_dev_close,};
The button_dev_close function is:
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;}
Free_irq indicates the release interruption, which requires two parameters.
This code is modified on the basis of the previous key blog.
Complete driver 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> MODULE_LICENSE ("Dual BSD/G PL "); static struct class * buttondrv_class; static struct class_devices * buttondrv_class_dev;/*/static DECLARE_WAIT_QUEUE_HEAD (button_wait_q);/* indicates the interrupt event, which is set to 1 by the interrupt program, the read function sets it to 0 */static volatile int ev_press = 0; volatile unsigned long * gpfcon = NULL; volatile unsigned long * gpfdat = NULL; static unsigned keyval; struct pin_desc {unsigned int pin; unsigned int key_value ;};/* press 0x01 0x02 0x03 0x04 * // * when the key is released Yes: 0x81 0x82 0x83 0x84 */struct pin_desc pins_desc [4] = {S3C2410_GPF1, 0x01}, {S3C2410_GPF4, 0x02 }, {S3C2410_GPF2, 0x03}, {S3C2410_GPF0, 0x04},};/** determine the 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 (pinval) // release {keyval = 0x80 | pindesc-> key_value;} else {keyval = pindesc-> key_va Lue;} ev_press = 1; // wake_up_interruptible (& button_wait_q); printk ("button is pressed: % d \ n", irq); return IRQ_HANDLED ;} static int button_dev_open (struct inode * inode, struct file * file, "key1", & pins_desc [0]); request_irq (IRQ_EINT4, buttons_irq, encrypt, "key2", & pins_desc [1]); request_irq (IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", & pins_desc [2]); request_irq (IRQ_EINT0, buttons_irq, cosine, "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;}/* if no button action occurs, sleep */wait_event_interruptible (button_wait_q, ev_press);/* If a button action occurs, directly return */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 (records, & pins_desc [2]); free_irq (records, & pins_desc [3]); return 0;} static struct file_operations button_sdv_fops = {. owner = THIS_MODULE ,. open = button_dev_open ,. read = button_dev_read ,. release = button_dev_close,}; int major; static int button_dev_init (void) // entry function {major = equals (0, "button_drv", & signature); buttondrv_class = class_create (THIS_MODULE, "button_drv"); if (IS_ERR (buttondrv_class) return response (buttondrv_class); response = device_create (buttondrv_class, NULL, MKDEV (major, 0), NULL, "wq_button "); if (unlikely (IS_ERR (buttondrv_class_dev) return PTR_ERR (buttondrv_class_dev);/* ing physical address */gpfcon = (volatile unsigned long *) ioremap (0x56000050, 16 ); gpfdat = gpfcon + 1; return 0;} static void button_dev_exit (void) {encrypt (major, "button_drv"); device_unregister (batch); class_destroy (buttondrv_class ); iounmap (gpfcon);} module_init (button_dev_init); module_exit (button_dev_exit );
Test code:
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>/* * wq_device <dev> <on|off> */int main(int argc, char **argv){int cnt=0;int fd;unsigned char key_val;fd = open("/dev/wq_button",O_RDWR);if(fd<0){printf("can't open \n");}while(1){read(fd,&key_val,1);printf("key_val = 0x%x\n",key_val);}return 0;}