AT91SAM9260按键驱动bug(一加载就死机,搞了2天没搞定,请各位给看看),附源码!
//**************按键驱动,读取方式*******************//*********************2010-6-1******************************
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/atmel_pdc.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/input.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/at91_pio.h>
#include <linux/timer.h>
#define DEVICE_NAME "key"
#define KEY_TIMER_DELAY1(HZ/50) //按键按下去抖延时20ms
#define KEY_TIMER_DELAY2(HZ/10) //按键抬起去抖延时100ms
#define KEYSTATUS_DOWN 0 //按键按下
#define KEYSTATUS_UP 1 //按键抬起
#define KEYSTATUS_DOWNX 2 //按键不确定
#define KEY_NUM 4 // 4个按键
#define DP_MAJOR 0 //主设备号
#define DP_MINOR 0 //次设备号
staticint key_major = DP_MAJOR;
//***********设备结构体********************************
#define MAX_KEY_BUF 16 // 按键缓存区大小
typedef unsigned char KEY_RET;
typedef struct
{
unsigned int keyStatus; // 4个按键的按键状态
KEY_RET buf;
unsigned int head,tail; // 按键缓存区头和尾
wait_queue_head_t wq; // 等待队列
struct cdev cdev; // cdev 结构体
}KEY_DEV;
KEY_DEV key_dev,*key_devp;
// **************去抖定时器*****************************
static struct timer_list key_timer;
//***************管理按键缓冲区**********************
#define BUF_HEAD (key_dev.buf) //缓冲头
#define BUF_TAIL (key_dev.buf) //缓冲尾
#define INCBUF(x,mod) ((++(x))&((mod)-1))
// **************按键硬件资源**************************
static struct key_info
{
int irq_no; // 中断号
int irq_type; // 中断类型
unsigned int gpio_port; // GPIO端口
int key_no; // 键值
}key_info_tab={
{AT91_PIN_PB0,AT91_AIC_SRCTYPE_LOW,AT91_PIN_PB0,1},
{AT91_PIN_PB1,AT91_AIC_SRCTYPE_LOW,AT91_PIN_PB1,2},
{AT91_PIN_PB2,AT91_AIC_SRCTYPE_LOW,AT91_PIN_PB2,3},
{AT91_PIN_PB3,AT91_AIC_SRCTYPE_LOW,AT91_PIN_PB3,4},
};
//***************硬件初始化*****************************
static void key_io_init(void)
{
at91_set_gpio_input(AT91_PIN_PB0, 1);
at91_set_deglitch(AT91_PIN_PB0, 1);
at91_set_gpio_input(AT91_PIN_PB1, 1);
at91_set_deglitch(AT91_PIN_PB1, 1);
at91_set_gpio_input(AT91_PIN_PB2, 1);
at91_set_deglitch(AT91_PIN_PB2, 1);
at91_set_gpio_input(AT91_PIN_PB3, 1);
at91_set_deglitch(AT91_PIN_PB3, 1);
}
//****************按键处理********************************
static void keyEvent(unsigned int key)
{
BUF_HEAD = key_info_tab.key_no; // 记录键值
key_dev.head = INCBUF(key_dev.head, MAX_KEY_BUF); // 调整缓冲区头指针
wake_up_interruptible(&(key_dev.wq)); // 唤醒等待队列
}
//****************中断处理函数**************************
static irqreturn_t key_irq_handler(int irq,void *dev_id/*,struct pt_regs *reg*/)
{
int key = (int)dev_id; //从0开始
int found = 0;
int i;
for (i = 0; i < ARRAY_SIZE(key_info_tab); i++) // 查找产生中断的按键
{
if (key_info_tab.irq_no == irq)
{
found = 1;
break;
}
}
if (!found) // 没找到
{
printk(KERN_ALERT "bad irq %d in button\n", irq);
return IRQ_NONE; //错误的中断
}
//printk(KERN_ALERT "int happens!\n");
if(key_dev.keyStatus == KEYSTATUS_UP) //前一个状态
{
disable_irq(key_info_tab.irq_no);
if(!at91_get_gpio_value(key_info_tab.gpio_port))
{
key_dev.keyStatus = KEYSTATUS_DOWNX;// 不确定是否为按下
key_timer.expires = jiffies + KEY_TIMER_DELAY1;// 延迟
key_timer.data = key;
add_timer(&key_timer);// 启动定时器
}
else
enable_irq(key_info_tab.irq_no);
}
return IRQ_HANDLED; //正确的中断
}
//****************定时器处理函数***********************
static void key_timer_handler(unsigned long data)
{
int key = data;
int up = at91_get_gpio_value(key_info_tab.gpio_port);
if (!up)
{
if (key_dev.keyStatus == KEYSTATUS_DOWNX)
{
key_dev.keyStatus = KEYSTATUS_DOWN;
key_timer.expires = jiffies + KEY_TIMER_DELAY2; //延迟
keyEvent(key);//记录键值,唤醒等待队列
}
else
key_timer.expires = jiffies + KEY_TIMER_DELAY2; //延迟
add_timer(&key_timer);
}
else //滤波成功
{
key_dev.keyStatus = KEYSTATUS_UP;
del_timer(&key_timer);
enable_irq(key_info_tab.irq_no);
}
}
// ***************申请系统中断**************************
static int request_irqs(void)
{
struct key_info *k;
int i;
int ret;
for(i = 0; i < sizeof(key_info_tab)/sizeof(key_info_tab); i++)
{
k = key_info_tab + i;
set_irq_type(key_info_tab.irq_no, key_info_tab.irq_type);
//申请中断,将按键序列号作为参数传入中断服务程序
ret = request_irq(k->irq_no,key_irq_handler,0,DEVICE_NAME,(void *)i);
if(ret)
{
printk(KERN_NOTICE "buttons:ret is %d\r\n",ret);
return -1;
}
}
return 0;
}
// ***************释放系统中断*************************
static void free0_irqs(void)
{
struct key_info *k;
int i;
for(i = 0; i < sizeof(key_info_tab)/sizeof(key_info_tab); i++)
{
k = key_info_tab + i;
free_irq(k->irq_no,(void *)i);
}
}
//***************文件操作******************************
static int key_open(struct inode *inode, struct file *filp)
{
key_dev.head = key_dev.tail = 0; //清空按键动作缓冲区
return 0;
}
static int key_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t key_read(struct file *filp, char __user *buf, size_t count,
loff_t*ppos)
{
unsigned int key_ret;
unsigned long flags;
retry:
if (key_dev.head != key_dev.tail) // 缓冲区有数据?
{
local_irq_save(flags); // 进入临界区 ,关中断
key_ret = BUF_TAIL; // 读出键值
key_dev.tail = INCBUF(key_dev.tail, MAX_KEY_BUF); // 调整缓冲区尾指针
local_irq_restore(flags); // 退出临界区,开中断
if(copy_to_user(buf, (void *)&key_ret, sizeof(unsigned int))) // 拷贝到用户空间
return -EFAULT;
else
return sizeof(unsigned int);
}
else // 缓冲区没数据
{
if (filp->f_flags & O_NONBLOCK) // 若采用非阻塞方式读取则返回错误
return -EAGAIN;
interruptible_sleep_on(&(key_dev.wq)); // 使进程睡眠
if (signal_pending(current)) //在这里等中断
return -ERESTARTSYS;
goto retry;
}
return sizeof(unsigned int);
}
//****************文件操作结构体**********************
static struct file_operations key_fops =
{
.owner = THIS_MODULE,
.open = key_open, // 启动设备
.release = key_release, // 关闭设备
.read = key_read, // 读取按键的键值
};
// ********************************************************
static int __init key0_init(void)
{
int i;
int result;
dev_t devnum = MKDEV(key_major, DP_MINOR);
if (key_major)
result = register_chrdev_region(devnum, 1, DEVICE_NAME);
else //动态申请
{
result = alloc_chrdev_region(&devnum, 0, 1, DEVICE_NAME);
key_major = MAJOR(devnum);
printk(KERN_INFO "Todo: mknod /dev/%s c %d 0\n", DEVICE_NAME, key_major);
}
key_devp = &key_dev;
/*
key_devp = (KEY_DEV*)kmalloc(sizeof(key_dev),GFP_KERNEL);
if(!key_devp)
{
result = - ENOMEM;
goto fail_malloc;
}
*/
//memset(key_devp,0,sizeof(key_dev));
//cdev_init(&key_devp->cdev, &key_fops); //设备注册
//key_devp->cdev.owner=THIS_MODULE;
//key_devp->cdev.ops=&key_fops;
//if(cdev_add(&key_devp->cdev, devnum, 1)) //
// printk(KERN_ALERT"Add char dev error!\n");
cdev_init(&key_dev.cdev, &key_fops); //设备注册
key_dev.cdev.owner=THIS_MODULE;
key_dev.cdev.ops=&key_fops;
if(cdev_add(&key_dev.cdev, devnum, 1)) //
printk(KERN_ALERT"Add char dev error!\n");
for(i = 0; i < KEY_NUM; i++) // 初始化结构体
key_dev.keyStatus = KEYSTATUS_UP;
key_dev.head = key_dev.tail = 0;
init_waitqueue_head(&(key_dev.wq));// 等待队列
init_timer(&key_timer); //去抖定时器初始化
key_timer.function=key_timer_handler;
key_io_init(); //硬件 初始化
if(-1 == request_irqs())
printk(KERN_NOTICE "request_irqs failed!\r\n");
return 0;
printk(KERN_ALERT "INIT ERROR !!!\r\n");
/*
fail_malloc:
unregister_chrdev_region(devnum,1);
return result;
*/
}
// ********************************************************
static void __exit key0_exit(void)
{
free0_irqs();
cdev_del(&key_dev.cdev);
kfree(key_devp);
unregister_chrdev_region(MKDEV(key_major,DP_MINOR),1);
}
module_init(key0_init);
module_exit(key0_exit);
MODULE_AUTHOR("caohaiming");
MODULE_LICENSE("Dual BSD/GPL"); 能把死机的信息提供一下,好分析的 你最好给个信息截图,这样好分析。有可能模块初始化函数有问题 什么问题? 代码好长,超过20行的,从来不分析:sleepy:
页:
[1]