内核驱动模块程序
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
#include <linux/irq.h>
#include <linux/device.h>
static struct class *third_drv_class;
struct class_device
*third_drv_class_dev;
struct pin_desc{
unsigned int pin;
unsigned int key_value;
};
struct pin_desc pins_desc[4]={
{S3C2410_GPG0,0x01},
{S3C2410_GPG3,0x02},
{S3C2410_GPG5,0x03},
{S3C2410_GPG6,0x04},
};
//定义一个按键值
unsigned char vkey_value;
//定义是否处理完中断
unsigned char ev_press;
//定义一个等待队列
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
struct pin_desc *pindesc = (struct pin_desc *)dev_id;
unsigned int vpin_value;
vpin_value = s3c2410_gpio_getpin(pindesc->pin);
if(vpin_value)
{
//按键释放
vkey_value= (pindesc->key_value)|0x80;
}
else
{
//按键按下
vkey_value= pindesc->key_value;
}
ev_press = 1;
//表示中断发生了
wake_up_interruptible(&button_waitq);
//打印中断号码,16进制显示
//printk("irq = 0x%0x\n",irq);
return IRQ_RETVAL(IRQ_HANDLED);
}
//---------------------------------
static int third_drv_open(struct inode *inode, struct file *file)
{
//注册中断函数到内核 GPG0 GPG3 GPG5 GPG6
request_irq(IRQ_EINT8, buttons_irq,IRQT_BOTHEDGE,"K1",&pins_desc[0]);
request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"K2",&pins_desc[1]);
request_irq(IRQ_EINT13,buttons_irq,IRQT_BOTHEDGE,"K3",&pins_desc[2]);
request_irq(IRQ_EINT14,buttons_irq,IRQT_BOTHEDGE,"K4",&pins_desc[3]);
printk("third_drv_open\n");
return 0;
}
static int third_drv_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT8, &pins_desc[0]);
free_irq(IRQ_EINT11,&pins_desc[1]);
free_irq(IRQ_EINT13,&pins_desc[2]);
free_irq(IRQ_EINT14,&pins_desc[3]);
printk("third_drv_close\n");
return 0;
}
static ssize_t
third_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
//读取一个字节,如果不是报错
if (count != 1)
return -EINVAL;
/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);
copy_to_user(buf, &vkey_value, 1);
ev_press = 0;
//清零
//----------------------------------
//printk("third_drv_open\n");
return 1;
}
static struct file_operations third_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = third_drv_open,
.read
=
third_drv_read,
.release=
third_drv_close,
};
int major;
static int third_drv_init(void)
{
major = register_chrdev(0,"thirddrv",&third_drv_fops);
third_drv_class = class_create(THIS_MODULE, "thirddrv");
third_drv_class_dev = class_device_create(third_drv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
printk("third_drv_init initial\n");
return 0;
}
static void third_drv_exit(void)
{
unregister_chrdev(major, "thirddrv");
class_device_unregister(third_drv_class_dev);
class_destroy(third_drv_class);
printk("third_drv_init exit\n");
}
module_init(third_drv_init);
module_exit(third_drv_exit);
MODULE_LICENSE("GPL");
测试应用程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
//测试开发板led开关
int main(int argc, char **argv)
{
int fd;
int vcnt;
unsigned char key_value;
fd = open("/dev/buttons",O_RDWR);
if(fd < 0)
{
printf("can't open device\n");
}
while(1)
{
read(fd,&key_value,1);
printf("key_value =0x%0x\n",key_value);
}
return 0;
}
打开中断设备
exec 5</dev/buttons_irq
关闭中断设备
exec 5<&-
查看挂载内核模块
cat /proc/devices
查看中断设备
cat /proc/interrupts