150 lines
5.0 KiB
C
150 lines
5.0 KiB
C
|
|
#include <linux/module.h>
|
|||
|
|
#include <linux/kernel.h>
|
|||
|
|
#include <linux/fs.h>
|
|||
|
|
#include <linux/init.h>
|
|||
|
|
#include <asm/io.h> //含有iomap函数iounmap函数
|
|||
|
|
#include <asm/uaccess.h> //含有copy_from_user函数
|
|||
|
|
#include <linux/device.h> //含有类相关的处理函数
|
|||
|
|
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
|||
|
|
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
|||
|
|
#include <linux/cdev.h>
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
static dev_t btn_cdev_num; //定义一个设备号
|
|||
|
|
static struct cdev *btn_cdev; //定义一个设备管理结构体指针
|
|||
|
|
static struct class *btn_class; //定义一个设备类
|
|||
|
|
static struct device *btn; //定义一个设备
|
|||
|
|
|
|||
|
|
#define KEYADC_BASE (0x01C22800)
|
|||
|
|
#define KEYADC_CTRL_REG (KEYADC_BASE+0x00)
|
|||
|
|
#define KEYADC_INTC_REG (KEYADC_BASE+0x04)
|
|||
|
|
#define KEYADC_INTS_REG (KEYADC_BASE+0x08)
|
|||
|
|
#define KEYADC_DATA_REG (KEYADC_BASE+0x0C)
|
|||
|
|
|
|||
|
|
ssize_t volatile *keyadc_ctrl;
|
|||
|
|
ssize_t volatile *keyadc_intc;
|
|||
|
|
ssize_t volatile *keyadc_ints;
|
|||
|
|
ssize_t volatile *keyadc_data;
|
|||
|
|
|
|||
|
|
|
|||
|
|
static unsigned int ev_press; //一个全局变量,记录中断事件状态
|
|||
|
|
DECLARE_WAIT_QUEUE_HEAD(btn_waitq);//注册一个等待队列button_waitq,用宏来申明一个全局变量
|
|||
|
|
static unsigned int key_value = 0; //定义一个变量保存按键值
|
|||
|
|
|
|||
|
|
static irqreturn_t btn_irq(int irq, void *dev_id)
|
|||
|
|
{
|
|||
|
|
wake_up_interruptible(&btn_waitq); /* 唤醒休眠的进程,即调用read函数的进程 */
|
|||
|
|
ev_press = 1;
|
|||
|
|
*keyadc_ints |= ((1<<0)|(1<<1) | (1<<2) |(1<<3)|(1<<4));
|
|||
|
|
return IRQ_HANDLED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int btn_cdev_open (struct inode * inode, struct file * file)
|
|||
|
|
{
|
|||
|
|
*keyadc_intc |= ((1<<0)|(1<<1)|(1<<4));
|
|||
|
|
*keyadc_ctrl |= (1<<7);
|
|||
|
|
*keyadc_ctrl &= ~(0xf<<8);
|
|||
|
|
*keyadc_ctrl |= (1<<0);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int btn_cdev_close(struct inode * inode, struct file * file)
|
|||
|
|
{
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static ssize_t btn_cdev_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
|||
|
|
{
|
|||
|
|
int ret;
|
|||
|
|
unsigned int adc_value;
|
|||
|
|
adc_value = *(keyadc_data);
|
|||
|
|
//将当前进程放入等待队列button_waitq中,并且释放CPU进入睡眠状态
|
|||
|
|
wait_event_interruptible(btn_waitq, ev_press!=0);
|
|||
|
|
ret = copy_to_user(userbuf, &adc_value, 4);//将取得的按键值传给上层应用
|
|||
|
|
|
|||
|
|
printk(KERN_WARNING"key adc = %d\n",(adc_value&(0x3f)));
|
|||
|
|
printk(KERN_WARNING"key statue = 0x%x\n",*(keyadc_ints));
|
|||
|
|
ev_press = 0;//按键已经处理可以继续睡眠
|
|||
|
|
if(ret)
|
|||
|
|
{
|
|||
|
|
printk("copy error\n");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static struct file_operations btn_cdev_ops = {
|
|||
|
|
.owner = THIS_MODULE,
|
|||
|
|
.open = btn_cdev_open,
|
|||
|
|
.read = btn_cdev_read,
|
|||
|
|
.release = btn_cdev_close,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
static int btn_cdev_init(void)
|
|||
|
|
{
|
|||
|
|
int ret;
|
|||
|
|
|
|||
|
|
btn_cdev = cdev_alloc(); //动态申请一个设备结构体
|
|||
|
|
if(btn_cdev == NULL)
|
|||
|
|
{
|
|||
|
|
printk(KERN_WARNING"cdev_alloc failed!\n");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
ret = alloc_chrdev_region(&btn_cdev_num,0,1,"button"); //动态申请一个设备号
|
|||
|
|
if(ret !=0)
|
|||
|
|
{
|
|||
|
|
printk(KERN_WARNING"alloc_chrdev_region failed!\n");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
btn_cdev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
|||
|
|
btn_cdev->ops = &btn_cdev_ops; //初始化设备操作函数指针为led_ops函数
|
|||
|
|
cdev_add(btn_cdev,btn_cdev_num,1); //将设备添加到内核中
|
|||
|
|
btn_class = class_create(THIS_MODULE, "button"); //创建一个名为led_class的类
|
|||
|
|
if(btn_class == NULL)
|
|||
|
|
{
|
|||
|
|
printk(KERN_WARNING"btn_class failed!\n");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
btn = device_create(btn_class,NULL,btn_cdev_num,NULL,"button0"); //创建一个设备名为led0
|
|||
|
|
if(IS_ERR(btn))
|
|||
|
|
{
|
|||
|
|
printk(KERN_WARNING"device_create failed!\n");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
keyadc_ctrl = ioremap(KEYADC_CTRL_REG, 4);//重映射
|
|||
|
|
keyadc_intc = ioremap(KEYADC_INTC_REG, 4);//重映射
|
|||
|
|
keyadc_ints = ioremap(KEYADC_INTS_REG, 4);//重映射
|
|||
|
|
keyadc_data = ioremap(KEYADC_DATA_REG, 4);//重映射
|
|||
|
|
ret = request_any_context_irq(35, btn_irq, 0 , "btn",(void*)&key_value);
|
|||
|
|
if(ret) //返回不为0,表示申请失败
|
|||
|
|
{
|
|||
|
|
printk("request irq failed!\n");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void btn_cdev_exit(void)
|
|||
|
|
{
|
|||
|
|
cdev_del(btn_cdev); //从内核中删除设备管理结构体
|
|||
|
|
unregister_chrdev_region(btn_cdev_num,1); //注销设备号
|
|||
|
|
device_destroy(btn_class,btn_cdev_num); //删除设备节点
|
|||
|
|
class_destroy(btn_class); //删除设备类
|
|||
|
|
|
|||
|
|
iounmap(keyadc_ctrl);//取消重映射
|
|||
|
|
iounmap(keyadc_intc);//取消重映射
|
|||
|
|
iounmap(keyadc_ints);//取消重映射
|
|||
|
|
iounmap(keyadc_data);//取消重映射
|
|||
|
|
free_irq(35,(void*)&key_value);//释放中断
|
|||
|
|
printk("unregister btn_cdev\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
module_init(btn_cdev_init);
|
|||
|
|
module_exit(btn_cdev_exit);
|
|||
|
|
|
|||
|
|
MODULE_LICENSE("GPL");
|