相关代码在资源中下载。
按键程序是以中断方式写的,至于中断的内核相关的知识看中断框架和注册一节,
所用到的函数和结构:
/*用来注册中断*/
/*irq:中断号,handler:中断处理函数,flags:中断触发方式,
*name:中断名字,dev:用来传给中断函数的*/
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags,const char *name, void *dev)
/*用来释放住的request_irq*/
void free_irq(unsigned int irq, void *dev_id);
驱动程序:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/irqs.h>
/*不同的linux版本的头文件会有所不同*/
static int major;
static struct class *second_key_class;
static struct device *second_key_device;
volatile unsigned long *GPFCON = NULL;
volatile unsigned long *GPFDAT = NULL;
static irqreturn_t buttons_irq(int irq,void *dev_id){
printk("irq= %d \n",irq);
return IRQ_HANDLED;
}
static int second_key_open(struct inode *inode, struct file *file)
{
/*设置相应引脚设置成中断方式*/
*GPFCON &= ~((3<<0)|(3<<2)|(3<<4)|(3<<8));
*GPFCON |= (1<<1)|(1<<3)|(1<<5)|(1<<7);
/*中断注册*/
request_irq(IRQ_EINT1,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s1",1);
request_irq(IRQ_EINT4,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s2",1);
request_irq(IRQ_EINT2,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s3",1);
request_irq(IRQ_EINT0,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s4",1);
return 0;
}
static ssize_t second_key_read(struct file *file, char __user *user_buffer,
size_t count, loff_t *ppos)
{
unsigned long reval;
int i;
unsigned long key_val[4];
/*读出引脚状态*/
reval = *GPFDAT;
if(count != sizeof(key_val))
return -EINVAL;
key_val[0] = (reval & (0x01<<0)) ? 1 : 0;
key_val[1] = (reval & (0x01<<1)) ? 1 : 0;
key_val[2] = (reval & (0x01<<2)) ? 1 : 0;
key_val[3] = (reval & (0x01<<4)) ? 1 : 0;
/*把内核的数据传到用户空间*/
copy_to_user(user_buffer,key_val,4);
return 4;
}
static int second_key_close(struct inode *inode, struct file *file)
{
/*释放分配的request_irq*/
free_irq(IRQ_EINT1,1);
free_irq(IRQ_EINT4,1);
free_irq(IRQ_EINT2,1);
free_irq(IRQ_EINT0,1);
return 0;
}
/*定义一个file_operations结构*/
static struct file_operations second_key_fops =
{
.owner = THIS_MODULE,
.open = second_key_open,
.read = second_key_read,
.release = second_key_close,
};
/*入口函数*/
static int second_key_init(void)
{
/*注册*/
major =register_chrdev(0,"second_key1",&second_key_fops);
/*分配一个类*/
second_key_class = class_create(THIS_MODULE,"second_key_class");
/*类下面创建一个设备*/
second_key_device =
device_create(second_key_class,NULL,MKDEV(major,0),NULL,"buttons");
/*映射物理地址到虚拟地址*/
GPFCON = (volatile unsigned long *)ioremap(0x56000050,16);
GPFDAT = GPFCON + 1;
return 0;
}
/*出口函数*/
static void second_key_exit(void)
{
/*注销*/
unregister_chrdev(major,"second_key1");
/*从系统中注销设备*/
device_unregister(second_key_device);
/*销毁创建的类*/
class_destroy(second_key_class);
/*取消虚拟地址的映射*/
iounmap(GPFCON);
}
/*修饰*/
module_init(second_key_init);
module_exit(second_key_exit);
MODULE_LICENSE("GPL");
下面测试:
1,加载到内核 insmod second_key1.ko
2,打开中断设备 exec 5</dev/buttons
3, 按下按键 终端出现中断号
4,关闭中断设备 exec 5<&-
exec 5</dev/buttons 是用shell打开文件
你可以用ps查看/bin/sh的进程号,然后用ls -l /proc/进程号/fd
可以看到lr -x 1 root root 64 Apr 29 17:04 5 -> /dev/buttons