In the above-mentioned Drive series blog, we have learned about blocking and non-blocking, asynchronous notification, polling, memory and I/O port access, concurrency control and other knowledge, the key device driver is relatively simple, this chapter content can deepen our character device driver architecture, blocking and non-blocking, Interrupt timer and other relevant knowledge of the understanding. In the embedded system, the hardware of the key is simple, that is, the external interrupt pin of the processor is pulled high by a pull-up resistor, and the other end of the resistor is connected to the button and grounded.
1. The confirmation process of the key is as follows
2 Key data structures in the drive
2.1 Key device structure and timer
#define MAX Key BUF 16//Key buffer size typedef unsigned char key RET;//device structure: typedef struct { unsigned int keystatus[k EY NUM]; 4 key key State key RET Buf[max key BUF];//key buffer unsigned int head, tail;//Key buffer header and tail wait queue head T Wq;//wait queues struct Cdev cdev; Cdev Structural Body
2.2 Keys hardware resource, key value information structure body
static struct Key info { int IRQ no; Interrupt number unsigned int gpio port;//gpio Port int key no; Key value } key Info tab [4] = The CPU resource used by the {/* key */ { IRQ EINT10, GPIO G2, 1 } , { IRQ E INT13, Gpio G5, 2 } , { IRQ EINT14, Gpio G6, 3 } , { IRQ EINT15, Gpio G7, 4 } ,
2.3 Key device driver file operation structure
Static struct file operations s3c2410 Key FoPs = { owner:this MODULE, open:s3c2410 key Open, //boot device c30/>release:s3c2410 key release, //Shutdown device read:s3c2410 key read,// read key key value
module load and unload functions for 3-button devices
3.1 Load function
static int init s3c2410 key init (void) { ...//apply for device number, add Cdev request IRQs ();//register interrupt function Keydev. Head = Keydev. tail = 0; Initialize struct for (i = 0; i < KEY NUM; i++) keydev.keystatus[i] = keystatus up; Init waitqueue Head (& (Keydev. Wq)); Wait for the queue//initialization timer to implement the software's jitter for (i = 0; i < KEY NUM; i++) Setup timer (&key timer[i], KEY timer handler, i); Use the key ordinal as the parameter of the incoming timer handler function }
3.2 Unload function
static void exit s3c2410 key exit (void) { free IRQs ();//Logoff interrupt ...//release device number, delete Cdev
3.3 Interrupt Request function
/* Request system Interrupt, interrupt mode for falling edge trigger * /static int request IRQs (void) { struct key info *k; int i; for (i= 0; i < sizeof (key info tab)/sizeof (Key Info tab [1]); i++) { k = key info tab + i; Set external IRQ (K->IRQ No, EXT lowlevel, GPIO pullup DIS); Set the low-level trigger if (Request IRQ (K->IRQ No, &buttons IRQ, SA INTERRUPT, DEVICE NAME, i ) //Application interrupt, the key sequence number as a parameter into the Interrupt service program { return -1; } } return 0; }
3.4 Interrupt Release function
/* Release Interrupt * /static void free IRQs (void) { struct key info *k; int i; for (i= 0; i < sizeof (key info tab)/sizeof (Key Info tab [1]); i++) { k = key info tab + i; Free IRQ (K->irq no, buttons IRQ); Release Interrupt }
4 Key device driver interrupt and timer handler
After the key is pressed, an interrupt will occur, in the interrupt handler, the interrupt in the query mode should be closed first, delay to eliminate the following interrupt processing process only the top half, no bottom half of the.
4.1 Interrupt Handlers
static void s3c2410 eint key (int IRQ, void *dev ID, struct PT regs *reg) { int key = Dev ID; Disable IRQ (Key Info tab [KEY].IRQ NO); Off interrupt, into query type keydev.keystatus[key] = keystatus downx;//status is pressed _ key Timer [key].expires = jiffies + key Timer delay1;//delay Add timer (&key Timer[key]);//Start Timer
4.2 Timer Processing Flow
When the key is pressed, the key will record the word buffer, while the timer starts the delay, each time the new key value is recorded, the waiting queue is awakened, its code is as follows.
Key device-driven timer handler function static void key Timer handler (unsigned Long data) { int key = data; if (IsKey down (key)) { if (keydev.keystatus[key] = = Keystatus downx) //Enter { Keydev from interrupt. keystatus[ Key] = Keystatus down; Key Timer[key].expires = = jiffies + key timer DELAY; Delayed keyevent (); Record key value, wake wait queue Add timer (&key timer [key]); } else { key timer[key].expires = = jiffies + key timer delay;//delay Add timer (&key timer [key]); } } else //key lifted { Keydev.keystatus[key] = keystatus up; Enable IRQ (Key Info tab [KEY].IRQ NO);
5 opening and releasing functions
Here is mainly set Keydev.head and Keydev.tail and key event function pointer keyevent value, key device driver open, release function as follows:
static int s3c2410 key open (struct inode *inode, struct file *filp) { Keydev. Head = keydev. Tail = 0;//clear Key action buffer Zone keyevent = KeyEvent raw;//function pointer to key handling function KeyEvent raw return 0; } static int s3c2410 key release (struct inode *inode, struct file *filp) { keyevent = KeyEvent dummy;//function pointer pointing to NULL function
return 0;}
6 Read function
Read function is mainly to provide the key device structure buffer read and copy to the user space, when keydev.head! = keydev.tail, the description buffer has data, using the Copy_to_user () function to copy to the user space, Conversely, depending on whether the user space is blocked or non-blocking reads are divided into the following two scenarios:
- Non-blocking read: No key cache, direct return-eagain;
- Blocking reads: Sleeps on the keydev.wq wait queue until a keystroke is logged to the buffer and is awakened.
Key device-driven read function static ssize t s3c2410 key Read (struct file *filp,char *buf,ssize t count, loff t*ppos) { re Try:if (Keydev.head! = Keydev. Tail) //Current loop queue has data { key ret = Keyread ();//Read button copy to user (..);//Data from The kernel space is transferred to user space } else { if (filp->f flags &o nonblock) //If the user reads { by non-blocking mode} return -eagain; } Interruptible Sleep On (& (Keydev. Wq)); The user reads in a blocking manner, calling the function to make the process sleep goto retry; } return 0;
All rights reserved, reprint please specify reprint address: http://www.cnblogs.com/lihuidashen/p/4498025.html
In layman's ~linux device driven key device driver