相關代碼在資源中下載。
按鍵程序是以中斷方式寫的,至於中斷的內核相關的知識看中斷框架和註冊一節,
所用到的函數和結構:
/*用來註冊中斷*/
/*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