Driver
# Include <Linux/module. h> # include <Linux/init. h> # include <Linux/types. h >#include <Linux/kdev_t.h> # include <Linux/kernel. h> // you can use the ptintk function # include <Linux/Fs. h> # include <Linux/interrupt. h> // The interrupt-related header file # include <Linux/cdev. h> // register character devices # include <Linux/err. h> // error check function # include <Linux/slab. h> // related to memory allocation # include <Linux/sched. h> // The interrupt-related header file # include <ASM/Io. h> // operate the IO port # include <Linux/Wait. h> // waiting queue # include <ASM/uaccess. h> // User and kernel space data copy # include <ASM/ARCH/regs-gpio.h> // I/O port Register address and usage (input, output, interrupt or others) # include <ASM/ARCH/regs-irq.h> // interrupt-related registers # include <ASM/arch-s3c2410/irqs. h> // definition of the platform-related interrupt number # include <Linux/delay. h> // time delay function # define key_major 234 // defines the master device number # define key_minor 0 // defines the next device number # define device_name "key_interrupt"/static struct cdev * key_cdev; // static dev_t dev_num; static volatile int key_flags = 0; // declare_wait _ Queue_head (Queue); // initialize the wait queue static volatile int key_value [] = {1, 2, 4}; // press the key value static volatile int key_press = 0; // record the key that was pressed static dev_t dev_num; // The dev_t of the device number indicates static struct cdev * key_cdev; struct key_irq_description {unsigned int IRQ; unsigned long flags; const char * dev_name;}; struct key_irq_description key_irq [] ={{ irq_eint0, sa_interrupt, "key" },{ signature, sa_interrupt, "key" },{ signature, sa_interrupt, "key" },{ Irq_eint4, sa_interrupt, "key" },};/* interrupt processing function */static irqreturn_t key_interrupt (int irq, void * dev_id, struct pt_regs * regs) {__ raw_writel (_ raw_readl (s3c2410_srcpnd) & 0 xffffffda, s3c2410_srcpnd); // clear srcpnd 0 2 3 4 (this is important) mdelay (1 ); key_press = * (int *) dev_id; // pay the key value to key_presskey_flags = 1; // set the queue sign to wake_up_interruptible (& Queue ); // wake up Wait queue return irq_handled;}/* only apply for interruption here, which can save interrupted Resources */static int key_open (Struct inode * inode, struct file * filp) {printk ("now in key_open \ n"); int ret; int I; for (I = 0; I <sizeof (key_irq) /sizeof (key_irq [0]); I ++) {ret = request_irq (key_irq [I]. IRQ, key_interrupt, key_irq [I]. flags, key_irq [I]. dev_name, (void *) & key_value [I]); // request to interrupt printk ("Please IRQ \ n"); If (RET) break;} If (RET) {printk ("now at free_irq \ n"); I --; For (; I> = 0; I --) {free_irq (key_irq [I]. IRQ, (void *) & key_value [I]); Return-ebusy ;}} Return 0;}/* release interruption when related resources are not used */static int key_close (struct inode * inode, struct file * filp) {int I; for (I = 0; I <sizeof (key_irq)/sizeof (key_irq [0]); I ++) {free_irq (key_irq [I]. IRQ, (void *) & key_value [I]);} return 0 ;} /* Copy data from the kernel space to the user control */static ssize_t key_read (struct file * filp, char _ User * Buf, size_t count, loff_t * OFFP) {unsigned long err; wait_event_interruptible (queue, key_flags); // enable the waiting queue key_flags = 0; // when K When ey_flags = 1, the waiting queue err = copy_to_user (BUF, (const void *) & key_press, count) can be released; // note that the method key_press = 0; return err? -Efault: 0;} static struct file_operations key_fops = {. owner = this_module ,. read = key_read ,. open = key_open ,. release = key_close,};/* fill in the cdev structure */static void key_cdev_setup (void) {int err; cdev_init (key_cdev, & key_fops ); // initialize the allocated structure key_cdev-> owner = this_module; // set the owner field key_cdev-> Ops = & key_fops; err = cdev_add (key_cdev, dev_num, 1 ); // inform the kernel of the structure information if (is_err (& ERR) {// check whether the returned pointer is an error code printk (kern_notice "error % d add Ing key_interrupt ", err) ;}/ * initialization register */static void initbutton (void) {__ raw_writel (_ raw_readl (s3c2410_gpfcon )&(~ (3 <8) | (3 <6) | (3 <4) | (3 <0) | (2 <8) | (2 <6) | (2 <4) | (2 <0), s3c2410_gpfcon); // gpf2, 0, 3, 4 set Eint _ raw_writel (_ raw_readl (s3c2410_extint0 )&(~ (7 | (7 <8) | (7 <12) | (7 <16), s3c2410_extint0 ); _ raw_writel (_ raw_readl (s3c2410_extint0) | (0 | (0 <8) | (0 <12) | (0 <16 ))), s3c2410_extint0); // set eint0, 2, 3, 4 falling edge int _ raw_writel (_ raw_readl (s3c2410_eintpend) | (1 <4), s3c2410_eintpend ); // clear Eint 4 _ raw_writel (_ raw_readl (s3c2410_eintmask )&(~ (1 <4), s3c2410_eintmask); // enable Eint 4}/* module initialization function, assign device numbers, initialize registers, allocate memory for the cdev structure and initialize the cdev structure */static int _ init key_init (void) {int ret; initbutton (); // initialize the relevant register if (key_major) {dev_num = mkdev (key_major, key_minor); ret = primary (dev_num, 1, device_name); // statically assigned device ID} else {ret = alloc_chrdev_region (& dev_num, key_minor, 1, device_name); // dynamically allocate the device number} If (Ret <0) {printk (kern_warning "key: Can't Get key_majo R % d \ n ", key_major); return ret;} key_cdev = kmalloc (sizeof (struct cdev), gfp_kernel); // allocate memory for the cdev structure if (! Key_cdev) {printk ("Can't get this ram \ n"); ret =-enomem;} memset (key_cdev, 0, sizeof (struct cdev )); // key_cdev_setup () is cleared in the memory area of the cdev structure; // register the device structure cdevreturn 0;}/* the module exits the function, the execution sequence of internal functions must be the opposite to that of module initialization */static void _ exit key_exit (void) {cdev_del (key_cdev); // Delete the cdev structure kfree (key_cdev ); // release the allocated memory unregister_chrdev_region (dev_num, 1); // release the device number} module_init (key_init); module_exit (key_exit); module_license ("GPL "); module_author ("lizhibin"); module_description ("key and interrupt ");Test procedure
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> int main(int argc,char **argv) { int i; int ret; int fd; char press_cnt; printf("Hi I am come in\n"); sleep(5); printf("5 seconds after\n"); fd=open("/dev/key_interrupt",0); printf("key_interrupt by open\n"); if(fd<0) { printf("Can't open /dev/interrupt \n"); return -1; } while(1) { printf("come in while(1)\n"); ret = read(fd,&press_cnt,sizeof(press_cnt)); if(ret<0) { printf("read err !\n"); continue; } if(press_cnt) printf("Key%d has been pressed \n",press_cnt); } }After compilation, download it to the Development Board, use insmod to load the driver, create a device node for mknod, run the test program, and press the button to view the result on dnw.