本帖最后由 widpj 于 2011-11-4 11:15 编辑
下面是我的oops信息,希望大侠帮帮忙,给点提示也行!菜鸟,刚学习驱动,有许多不懂之处,望各位大侠指点迷津!
下面是我的驱动程序,(是一个mini2440的按键驱动程序)采用的是平台总线platform编写的,希望各位帮忙!
#include<linux/module.h>
#include<linux/types.h>
#include<linux/miscdevice.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<linux/platform_device.h>
#include<linux/interrupt.h>
#include<linux/clk.h>
#include<linux/uaccess.h>
#include<linux/io.h>
#include<mach/map.h>
#include<mach/regs-gpio.h>
#include<mach/gpio-fns.h>
#include<linux/sched.h>
#include<linux/poll.h>
#include<linux/irq.h>
#include<asm/unistd.h>
#include<linux/device.h>
#include<linux/kernel.h>
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
#define KEY_TIMER_DELAY1 (HZ/50) //按键按下去抖延时20毫秒
#define KEY_TIMER_DELAY2 (HZ/10) //按键抬起去抖延时100毫秒
static volatile int press=0;
static int key_value;
static struct resource *button_mem;
static struct resource *button_irq;
static void __iomem *button_base; //基地址
static struct timer_list key_timers[6]; //定义6个按键去抖动定时器
static int pin[]={S3C2410_GPG(0),S3C2410_GPG(3),S3C2410_GPG(5),S3C2410_GPG(6),S3C2410_GPG(11)}; //定义引脚
static int button_irqs[6];
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
int i;
for(i=0; i<6; i++){
if(irq == button_irqs){
//设置当前按键按下去抖定时器的延时并启动定时器
key_timers.expires = jiffies + KEY_TIMER_DELAY1;
add_timer(&key_timers);
}
}
return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer(unsigned long arg)
{
//获取当前按键资源的索引
int key = arg;
//获取当前按键引脚上的电平值来判断按键是按下还是抬起
int up = s3c2410_gpio_getpin(pin[key]);
if(!up)//低电平,按键按下
{
//标识当前按键已按下并唤醒等待队列
press = 1;
key_value=key;
wake_up_interruptible(&button_waitq);
//设置当前按键抬起去抖定时器的延时并启动定时器
key_timers[key].expires = jiffies + KEY_TIMER_DELAY2;
add_timer(&key_timers[key]); //由于定时器超时后系统会自动将定时器删除,故应重新开启定时器
}
else//高电平,按键抬起
{
//标识当前按键状态为抬起
press = 1;
}
}
static int s3c24xx_button_open(struct inode *inode, struct file *file)
{
int i;
int err = 0;
/*注册中断*/
for(i=0; i<6; i++){
if (button_irqs < 0)
continue;
/*中断触发方式:上升沿触发*/
err = request_irq(button_irqs,buttons_interrupt,IRQ_TYPE_EDGE_RISING,NULL,NULL);
if(err)
break;
//初始化并设置6个去抖定时器
setup_timer(&key_timers, buttons_timer, i);
}
if (err) {
i--;
for (; i >= 0; i--) {
if (button_irqs < 0) {
continue;
}
disable_irq(button_irqs);
free_irq(button_irqs, NULL);
}
return -EBUSY;
}
press = 0;
return 0;
}
static int s3c24xx_button_close(struct inode *inode,struct file *file)
{
int i;
//释放6个定时器和中断
for(i = 0; i < 6; i++)
{
del_timer(&key_timers);
disable_irq(button_irqs);
free_irq(button_irqs, (void *)i);
}
return 0;
}
static int s3c24xx_button_read(struct file *file,char __user *buff,size_t count,loff_t *offp)
{
unsigned long ret;
if(!press)//判断按键按下产生标识,0没有产生
{
if(file->f_flags & O_NONBLOCK)
{
//应用程序若采用非阻塞方式读取则返回错误
return -EAGAIN;
}
else
{
//以阻塞方式读取且按键按下没有产生,让等待队列进入睡眠
wait_event_interruptible(button_waitq, press);
}
}
//1为按键按下产生,并清除标识为0,准备给下一次判断用
press = 0;
//将内核中的按键状态数据拷贝到用户空间给应用程序使用
ret = copy_to_user(buff, &key_value, sizeof(key_value));
return ret;
}
static unsigned int s3c24xx_button_poll(struct file *file,struct poll_table_struct *wait)
{
unsigned int mask = 0;
//添加等待队列到等待队列表中(poll_table)
poll_wait(file, &button_waitq, wait);
if(press)
{
//标识数据可以获得
mask |= POLLIN | POLLRDNORM;
}
return mask;
}
static struct file_operations mini2440button_fops={
.owner = THIS_MODULE,
.open = s3c24xx_button_open,
.release = s3c24xx_button_close,
.read = s3c24xx_button_read,
.poll = s3c24xx_button_poll,
};
static struct miscdevice mini2440_miscdev=
{
.minor = MISC_DYNAMIC_MINOR,
.name = "button"
// .fops = mini2440button_fops,
};
static int mini2440_button_probe(struct platform_device *pdev)
{
struct resource *res;
struct device *dev;
int size;
int ret;
int i;
dev=&(pdev->dev);
/*获取内存资源*/
res=platform_get_resource(pdev,IORESOURCE_MEM,0);
if(res==NULL)
{
dev_err(dev,"no memory resource specified\n");
return -ENOENT;
}
size=(res->start-res->end)+1;
button_mem = request_mem_region(res->start,size,pdev->name);
if(button_mem==NULL)
{
dev_err(dev,"Faild to get memory region\n");
ret= -ENOENT;
goto err_req;
}
button_base = ioremap(res->start,size);
if(button_base==NULL)
{
dev_err(dev,"failed to ioremap() region\n");
ret = -EINVAL;
goto err_req;
}
printk(KERN_DEBUG "probe: mapped button_base=%p\n",button_base);
/*获取中断号*/
for(i=0;i<6;i++)
{
button_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);
if(button_irq==NULL)
{
dev_err(dev,"no irq resource specified\n");
ret= -ENONET;
goto err_map;
}
button_irqs= button_irq->start;
}
ret=misc_register(&mini2440_miscdev);
mini2440_miscdev.fops=&mini2440button_fops;
return 0;
err_map:
iounmap(button_base);
err_req:
release_resource(button_mem);
kfree(button_mem);
return ret;
}
int mini2440_button_remove(struct platform_device *dev)
{
release_resource(button_mem);
kfree(button_mem);
button_mem = NULL;
iounmap(button_base);
misc_deregister(&mini2440_miscdev);
return 0;
}
struct platform_driver button_driver=
{
.probe = mini2440_button_probe,
.remove = mini2440_button_remove,
.driver =
{
.owner = THIS_MODULE,
.name = "mini2440_buttons",
},
};
static int __init init_driver(void)
{
return platform_driver_register(&button_driver);
}
static void __exit driver_exit(void)
{
platform_driver_unregister(&button_driver);
}
module_init(init_driver);
module_exit(driver_exit);
MODULE_AUTHOR("Linux-wu");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Mini2440_button_driver"); |
|