Original URL: http://www.xuebuyuan.com/632893.html
Host: Vm-redhat 9.0
Development Board: fl2440,linux-2.6.12
arm-linux-gcc:3.4.1
(1) The key module on the schematic diagram, you can see the corresponding Gpio port, as well as the interrupt number.
The figure can be learned that the GPF0 high level, when the key is pressed, then the low level, so the interrupt response is set to the falling edge trigger.
(2) Driver gzliu_2440_key.c, implementation for the general character device driver, the complete source code is as follows, wherein:
Use of the timer reference: http://blog.csdn.net/gzliu_hit/article/details/6691355
S3c2410_gpio_cfgpin series Function Reference: http://blog.csdn.net/gzliu_hit/article/details/6689182
REQUEST_IRQ () Reference: http://blog.csdn.net/gzliu_hit/article/details/6688929
http://blog.csdn.net/gzliu_hit/article/details/6688816
Cdev_init () series function Reference: http://blog.csdn.net/gzliu_hit/article/details/6688684
#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/ input.h> #include <linux/init.h> #include <linux/interrupt.h> #include <asm/io.h> #include < linux/cdev.h> #include <asm/uaccess.h> #include <asm/arch/regs-gpio.h> #define DEV_NAME "S3c2440-key" # Define DEV_MAJOR 250//Master device number # define MAX_KEY_BUF 16//Key buffer size # define Key_n UM 4#define gzliu_key_down_x 0//Press button, unsure whether it is interfering with the # define Gzliu_key_down 1 Press the # define GZLIU_KEY_UP 2//button to lift the # define KEY_TIMER_DELAY_1 (HZ/50) Press delay 20ms#define key_timer_delay_2 (HZ/10)//push button to delay 100mstypedef unsigned char key_ret;/before lifting /device structural body static struct key_dev{unsigned int key_status[key_num]; 4-button state Key_ret buf[max_key_buf]; Key buffer unsigned int head, tail; Key buffer head, tail wait_queue_head_t Wq; Wait queue struct Cdev cdev; Cdev structure}dev;static struct timer_list key_timer[key_num]; 4-button Jitter Timer//Key hardware resource, key value information struct struct key_info{int IRQ; Interrupt number unsigned int port; Gpio Port int Port_type; Gpio port configuration char *key; Key name};//interrupt, GPIO macro definition is the same as s3c2410, from the header file://include/asm-arm/arch-s3c2410/regs-gpio.h//include/asm-arm/arch-s3c2410/ irqs.hstatic struct Key_info Key_info_tab[key_num] = {{irq_eint0, s3c2410_gpf0, s3c2410_gpf0_eint0, ' KEY_1 '}, { Irq_eint2, S3C2410_GPF2, S3c2410_gpf2_eint2, "key_2"}, {Irq_eint3, s3c2410_gpf3, S3c2410_gpf3_eint3, "KEY_3"}, { Irq_eint4, S3c2410_gpf4, S3c2410_gpf4_eint4, "Key_4"},};//interrupt handler static irqreturn_t S3C2440_KEY_IRQ (int irq, void *dev_ ID) {int key = (int) dev_id; Off interrupt, into the query mode//each keystroke only produces one interrupt Disable_irq (KEY_INFO_TAB[KEY].IRQ); Dev.key_Status[key] = gzliu_key_down_x; The status is pressed Key_timer[key].expires = jiffies + key_timer_delay_1; Delay Add_timer (&key_timer[key]); Start timer return irq_handled;} /* S3C2440_KEY_IRQ () *///Request system Interrupt, interrupt mode for falling edge trigger static int Request_irqs (void) {int i, RET; for (i=0; i<key_num; i++) {//Set 4 GPIO ports for interrupt triggering mode S3c2410_gpio_cfgpin (Key_info_tab[i].port, Key_info_tab [I].port_type]; Request interrupt, fast interrupt, set to drop edge trigger//Key number as parameter incoming interrupt service ret = REQUEST_IRQ (KEY_INFO_TAB[I].IRQ, (void *) s3c2440_key_i RQ, Sa_interrupt | Irqt_falling, Key_info_tab[i].key, (void *) i); if (ret) {return i; }} return 0; }/* Request_irqs () *///release interrupt static void Free_irqs (void) {int i; for (i=0; i<key_num; i++) {DISABLE_IRQ (KEY_INFO_TAB[I].IRQ); FREE_IRQ (KEY_INFO_TAB[I].IRQ, (void *) i); }}//Timer handler function static void S3c2440_key_timer (unsigned long data) {int key = data; int status= S3c2410_gpio_getpin (Key_info_tab[key].port); if (!status)//key is pressed state {if (dev.key_status[key] = = gzliu_key_down_x)//Enter {dev from interrupt . key_status[key] = Gzliu_key_down; Dev.buf[dev.tail] = (Key_ret) KEY; Dev.tail = (dev.tail + 1)% Max_key_buf; Wake_up_interruptible (&DEV.WQ); Wake up Wait Queue}//delay longer, wait for the button to lift key_timer[key].expires = jiffies + key_timer_delay_2; Add_timer (&key_timer[key]); } else//button has been lifted {dev.key_status[key] = gzliu_key_up; ENABLE_IRQ (KEY_INFO_TAB[KEY].IRQ); Press button to lift, enable interrupt}}/* s3c2440_key_timer */static int s3c2440_key_open (struct inode *inode, struct file *filp) {int I , ret; Dev.head = Dev.tail = 0; for (i=0; i<key_num; i++) {//Initialize key state for lift dev.key_status[i] = gzliu_key_up; Initialize Timer init_timer (&key_timer[i]); Key_timer[i].data = i; Pass the key sequence number as the parameter incoming timer processing function key_timer[i].function = S3c2440_key_timer; Timer corresponding Function} init_waitqueue_head (& (DEV.WQ)); Initialize wait queue//request Interrupt ret = Request_irqs (); if (Ret > 0)//If the application fails, release the interrupt that has been applied {PRINTK ("Request_irqs () failed, line:%d\n", __line__); for (I=ret; i>=0; i--) {DISABLE_IRQ (KEY_INFO_TAB[I].IRQ); FREE_IRQ (KEY_INFO_TAB[I].IRQ, (void *) i); } return-ebusy; } return 0; }/* S3c2440_key_open () */static ssize_t s3c2440_key_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos) { int ret; unsigned int size; if (Dev.head = = dev.tail)//No key pressed {if (Filp->f_flags & O_nonblock)//If the application is non-blocking, the error is returned false {Return-eagain; } else//enters blocking mode, which causes the application to hibernate {wait_event_interruptible (DEV.WQ, Dev.head! = Dev.tail); }} size = (dev.tail-dev.head)% Max_key_buf; ret = Copy_to_user (buf, (dev.buf+dev.head), size); Dev.head = Dev.tail; if (ret) {return ret; } return size; }/* s3c2440_key_read () */static int s3c2440_key_release (struct inode *inode, struct file *filp) {int i; for (i=0; i<key_num; i++) {Del_timer (&key_timer[i]); } Free_irqs (); return 0;} static struct File_operations S3c2440_key_fops = {. Owner=this_module,.open=s3c2440_key_open,.read=s3c2440_key_read, . release=s3c2440_key_release,};//S3c2440-key Driver module load function static int __init s3c2440_key_init (void) {int ret; dev_t Devno = MKDEV (dev_major, 0); Request character device Drive area//known master device number, if unknown, then dynamic request alloc_chrdev_region () ret = Register_chrdev_region (Devno, 1, dev_name); if (Ret < 0) {PRINTK (dev_name "Register failed, line:%d\n", __line__); PRINTK ("ret:%d\n", ret); return ret; }//Initialize and add Cdev structure body cdev_init (&dev.cdev, &s3c2440_key_fops); Dev.cdev.owner = This_module; Ret= Cdev_add (&dev.cdev, Devno, 1); if (ret) {PRINTK ("error%d when adding dev\n", ret); } return 0;} S3c2440-key Drive module unload function static void __exit s3c2440_key_exit (void) {Cdev_del (&dev.cdev); Delete the CDEV structure unregister_chrdev_region (MKDEV (dev_major, 0), 1); deregistration device Area}module_init (s3c2440_key_init); Module_exit (S3c2440_key_exit); Module_author ("Gzliu <[email protected]>"); Module_description ("s3c2440 key Driver"); Module_license ("GPL");
(3) Compile the makefile of the driver module:
# Makefile 2.6 ifneq ($ (kernelrelease),) obj-m:=gzliu_2440_key.oelsepwd:=$ (shell pwd) #KDIR: =/lib/modules/$ ( Shell uname-r)/build kdir:=/root/linux-2.6.12 all:$ (make)-C $ (Kdir) m=$ (PWD) clean:rm-rf. *.cmd *.o *.mod.c *.ko. t Mp_versionsendif
(4) Application Layer test program key_test.c:
#include <stdio.h> #include <fcntl.h> #define MAX_KEY_BUF //key buffer size int main () {unsigned char BUF [Max_key_buf];int fd_key;int ret, I;fd_key = open ("/dev/gzliu_2440_key", o_rdonly), if (Fd_key = =-1) {printf ("open" (fd_ Key) failed\n "); return-1;} while (1) {//block mode, when no keystrokes are pressed, the process is blocked by ret = Read (Fd_key, buf, Max_key_buf), for (i=0; i<ret; i++) {printf ("Key%d is down\n", Buf[i]);}} return 0;}
(5) Through the serial port to send the program to the Development Board file system, the test results on the FL2440 Development Board:
can also be implemented as a hybrid device driver, you can automatically create device nodes.
Key-driven actuation as a hybrid device: http://blog.csdn.net/gzliu_hit/article/details/6697568
"Turn" s3c2440 key driver-character device