5-2 interrupt-based key driver instance

Source: Internet
Author: User

Interrupt-based key driver instance

1. circuit diagram:

2. Driver

2.1 driver source code int_key \ completion \ driver \ int_key_drv.c

# Include <Linux/module. h> # include <Linux/kernel. h> # include <Linux/Fs. h> # include <Linux/init. h> # include <Linux/delay. h> # include <Linux/poll. h> # include <Linux/IRQ. h> # include <ASM/IRQ. h> # include <Linux/Wait. h> # include <Linux/sched. h> # include <Linux/interrupt. h> # include <ASM/uaccess. h> # include <Linux/gpio. h> # include <Mach/regs-gpio.h> # include <Mach/hardware. h >#include <Linux/platform_device.h> # include <Linux/cdev. h> # include <Linux/miscdevice. h> # define using_taskletstatic int key_major = 0; struct key_irq_desc {// defines the struct unsigned int IRQ; /* The IRQ Number corresponding to the key. This value has been defined in the kernel header file */INT pin;/* The Pin corresponding to */INT pin_setting;/* The reason why the PIN is set, the following uses the external interrupt mode */INT number;/* consistent with the following table in the array */char * Name;/* name */}; /* specifies the External Interrupt pin used by the buttons and the interrupt trigger method. The value is */static struct key_irq_desc key_irqs [] ={{ irq_eint8, s3c2410_gpg (0), s3c2410_gpg0_eint8, 0 Ey1 "},/* K1 */{irq_eint11, s3c2410_gpg (3), s3c2410_gpg3_eint11, 1," key2 "},/* K2 */{irq_eint13, s3c2410_gpg (5 ), keys, 2, "key3"},/* K3 */{irq_eint14, s3c2410_gpg (6), s3c2410_gpg6_eint14, 3, "key4"},/* K3 */{irq_eint15, s3c2410_gpg (7), s3c2410_gpg7_eint15, 4, "key5"},/* K3 */{irq_eint19, s3c2410_gpg (11), s3c2410_gpg11_eint19, 5, "key6 "}, /* K4 */};/* Number of times the button is pressed (accurately, the number of times the button is interrupted) */Static volatile int key_values [] = {0, 0, 0, 0, 0};/* waiting queue: * when no buttons are pressed, if a process calls the key_read function, * It will sleep */static declare_wait_queue_head (key_waitq); // initialize a wait queue header key_waitq/* interrupt event flag, interrupt the service program to set it to 1, key_read clear it 0 */static volatile int ev_press = 0;/* mark whether the key is pressed */# ifdef using_taskletstatic struct tasklet_struct key_tasklet; /* define a task queue */static void key_do_tasklet (unsigned long);/* function declaration * // declare_tasklet (Key _ Tasklet, key_do_tasklet, 0); static void key_do_tasklet (unsigned long data)/* lower half function */{printk ("key_do_tasklet \ n ");} # endifstatic irqreturn_t key_interrupt (int irq, void * dev_id) {struct key_irq_desc * key_irqs = (struct failed *) dev_id; int up = encrypt (key_irqs-> pin ); // ARCH/ARM/plat-s3c24xx/gpio. c/* read key status press or raise */printk ("<1> up = % d \ n", up); If (up) key_values [key_irqs-> Number] = (key_irqs-> Number + 1) + 0x80; elsekey_values [key_irqs-> Number] + = 1; ev_press = 1;/* indicates that the interrupt occurred */wake_up_interruptible (& key_waitq ); /* wake up the sleep process */# ifdef using_tasklettasklet_schedule (& key_tasklet); # endif return irq_retval (irq_handled );} /* The application executes open (...) on the device file/dev/key (...) * The key_open function */static int key_open (struct inode * inode, struct file * file) {int I; int err; for (I = 0; I <sizeof (key_irqs)/sizeof (key_ir QS [0]); I ++) {// registers the interrupt handler function s3c2410_gpio_cfgpin (key_irqs [I]. pin, key_irqs [I]. pin_setting); err = request_irq (key_irqs [I]. IRQ, key_interrupt, 0,/* apply for interrupted sharing? */Key_irqs [I]. name, (void *) & key_irqs [I]);/* (void *) & key_irqs [I] transfer the struct address */set_irq_type (key_irqs [I]. IRQ, irq_type_edge_falling); // <Linux/IRQ. h> set the trigger mode. Here, set the trigger mode to descent edge. // irq_type_edge_rising, irq_type_edge_both, irq_type_edge_high, // irq_type_edge_low if (ERR) break) {// release the registered interrupt I --; For (; I> = 0; I --) {disable_irq (key_irqs [I]. IRQ); free_irq (key_irqs [I]. IRQ, (void *) & key_irqs [I]); // (void *) & Key_irqs [I] forced conversion type} return-ebusy;} return 0;}/* The application executes close (...) on the device file/dev/key (...) * The key_close function */static int key_close (struct inode * inode, struct file * file) {int I; for (I = 0; I <sizeof (key_irqs) /sizeof (key_irqs [0]); I ++) {// release the registered disable_irq (key_irqs [I]. IRQ);/* forbidden interrupt */free_irq (key_irqs [I]. IRQ, (void *) & key_irqs [I]);/* release interrupt Number */} return 0 ;} /* The application executes read (...) on the device file/dev/key (...) * Will call key_r EAD function */static int key_read (struct file * filp, char _ User * buff, size_t count, loff_t * OFFP) {unsigned long err; If (! Ev_press) {If (filp-> f_flags & o_nonblock)/* non-blocking */Return-eagain; else/* If ev_press is equal to 0, sleep until key_waitq is awakened, and ev_press is true */wait_event_interruptible (key_waitq, ev_press);/* is blocked */}/* when it is executed here, ev_press is equal to 1, clear it 0 */ev_press = 0;/* copy the key state to the user, and clear 0 */err = copy_to_user (buff, (const void *) key_values, min (sizeof (key_values), count); memset (void *) key_values, 0, sizeof (key_values); Return err? -Efault: min (sizeof (key_values), count );} /*************************************** * *********** when a user program calls the select function, this function is called * If key data exists, the Select function immediately returns * if no key data exists, this function uses poll_wait to wait *********************************** * *************/static unsigned int key_poll (struct file * file, struct poll_table_struct * Wait)/* implement non-blocking round robin */{unsigned int mask = 0; poll_wait (file, & key_waitq, wait ); /* Add key_waitq to the waiting queue */If (ev_press) mask | = Pollin | pollrdnorm; return mask ;} /* this structure is the core of the character device driver * Open, read, write, and other functions called when the application operates the device file, * the corresponding function */static struct file_operations key_fops = {will be called eventually {. owner = this_module,/* This is a macro that points to the _ this_module variable automatically created during compilation */. open = key_open ,. release = key_close ,. read = key_read ,. poll = key_poll,};/** set up the cdev structure for a device. */static void key_setup_cdev (struct cdev * Dev, int minor, struct file_operations * FoPs) {int err, devno = mkdev (key_major, minor); cdev_init (Dev, fops ); dev-> owner = this_module; Dev-> Ops = fops; err = cdev_add (Dev, devno, 1);/* fail gracefully if need be */If (ERR) printk (kern_notice "error % d adding key % d", err, minor);}/** we export one key device. there's no need for us to maintain any * Special housekeeping info, so we just deal with raw cdev. */static struct cdev key_cdev;/** this function is called when you execute the "insmod key_drv.ko" command */static int _ init userkey_init (void) // static int key_init (void) {int result; dev_t Dev = mkdev (key_major, 0); char dev_name [] = "key";/* figure out our device number. */If (key_major) Result = register_chrdev_region (Dev, 1, dev_name); else {result = alloc_chrdev_region (& Dev, 0, 1, dev_name ); key_major = major (Dev);} If (result <0) {printk (kern_warning "key: Unable to get Major % d \ n", key_major); return result ;} if (key_major = 0) key_major = result; # ifdef using_tasklettasklet_init (& key_tasklet, key_do_tasklet, 0); # endif/* now set up cdev. */key_setup_cdev (& key_cdev, 0, & key_fops); printk ("key device installed, with major % d \ n", key_major); printk ("the device name is: /dev/% s \ n ", dev_name); Return 0 ;} /** call this function when executing the rmod key_drv command */static void _ exit userkey_exit (void) // static void key_exit (void) {cdev_del (& key_cdev ); unregister_chrdev_region (mkdev (key_major, 0), 1); # ifdef using_tasklettasklet_kill (& key_tasklet); # endif printk ("key device uninstalled \ n ");} /* specify the initialization and uninstallation functions of the driver */module_init (userkey_init); module_exit (userkey_exit);/* describes some information about the driver, not required */module_author ("Hanson he"); // The driver author module_description ("S3C2410/S3C2440 key driver "); // some descriptive information module_license ("dual BSD/GPL"); // The following protocol

2.2makefile

ifeq ($(KERNELRELEASE),)#KERNELDIR ?= /your/target/source/directory/KERNELDIR ?=/home/student/linux-2.6.32.2PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions.PHONY: modules modules_install cleanelse    obj-m := int_key_drv.oendif

3. 1 user program

3.1 User source code int_key \ completion \ User \ key_test.c

# Include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <sys/IOCTL. h> # include <sys/types. h> # include <sys/STAT. h> # include <fcntl. h> # include <sys/select. h> # include <sys/time. h> # include <errno. h> int main (void) {int I; int key_fd; int key_value [] = {0, 0, 0, 0 }; /* Open the keyboard Device File */key_fd = open ("/dev/Key", 0); If (key_fd <0) {perror ("open device key "); exit (1) ;}for (;) {fd_set RDS;/* fd_set data structure, which is actually a long class * // * Can each array element be associated with an open file sentence? // * (Whether it is a socket handle, or another file or named pipe or device handle) establish a connection * // * the programmer completes the connection establishment. When select () is called, * // * the content of fd_set is modified by the kernel according to the IO status, so as to notify the select () process * // * which socket or file has a readable or writable event. */Int ret; fd_zero (& RDs);/* zeroes the RDS so that the set does not contain any key_fd */fd_set (key_fd, & RDs ); // place the key_fd in the read collection/* place the key_fd In the RDS collection ** // use the System Call select to check whether data can be read from the/dev/key device */ret = select (key_fd + 1, & RDS, null);/* exit the program when an error occurs in Reading */If (Ret <0) {perror ("select"); exit (1 );} if (ret = 0) {printf ("timeout. \ n ");}/* can read data */else if (fd_isset (key_fd, & RDs) {/* after the select () function is called, use fd_isset to check whether the status of key_fd changes in the rdst set. Return an integer * // *. If the FD status changes, the system returns true. Otherwise, Returns false (0) * // * to start reading the data sent by the keyboard driver. Note that the key_value and the keyboard driver are of the same type. */int ret = read (key_fd, key_value, sizeof key_value); If (Ret! = Sizeof key_value) {If (errno! = Eagain) perror ("read key \ n"); continue;} else {/* print key value */for (I = 0; I <6; I ++) printf ("K % d % s, key value = 0x % 02x \ n", \ I + 1, (key_value [I] & 0x80 )? "Released": \ key_value [I]? "Pressed down": "", key_value [I]); key_value [I] = 0 ;}}/* close the device file handle */close (key_fd ); return 0 ;}

3.2makefile

KERNELDIR ?=/opt/linux-2.6.34/includeall: key_test key_test : key_test.c#arm-linux-gcc -I$(KERNELDIR) -s -Wl,-warn-common --static -o $@ $^arm-linux-gcc -I$(KERNELDIR) -o $@ $^clean :rm key_test

4. Pay attention to the skills used above.

Printf ("K % d % s, key value = 0x % 02x \ n ",\

I + 1, (key_value [I] & 0x80 )? "Released": key_value [I]? "Pressed down": "", key_value [I]);

Similar to: # define min (A, B) (a) <= (B )? (A) (B ))

Statement: This article is not original and organized from application embedding.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.