platform_device
/*
程序说明:基于platform bus的按键中断设备程序,与platform BUS的按键驱动程序匹配使用
作者:谢思源
时间:2010.7.16
*/
#include
#include
#include
#include
//中断
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("ECJTU CERT XIESIYUAN");
MODULE_LICENSE("GPL");
//适用于平台设备的按键设备资源
struct resource button_res[]={
[0]={
.start=IRQ_EINT8,
.end=IRQ_EINT8,
.name="0",
.flags= IORESOURCE_IRQ,
},
[1]={
.start=IRQ_EINT11,
.end=IRQ_EINT11,
.name="1",
.flags= IORESOURCE_IRQ,
},
[2]={
.start=IRQ_EINT13,
.end=IRQ_EINT13,
.name="2",
.flags= IORESOURCE_IRQ,
},
[3]={
.start=IRQ_EINT15,
.end=IRQ_EINT15,
.name="3",
.flags= IORESOURCE_IRQ,
},
[4]={
.start=IRQ_EINT14,
.end=IRQ_EINT14,
.name="4",
.flags= IORESOURCE_IRQ,
},
[5]={
.start=IRQ_EINT19,
.end=IRQ_EINT19,
.name="5",
.flags= IORESOURCE_IRQ,
},
};
//struct platform_device *button;
struct platform_device button ={
.name = "button_plat",
.id =-1,
.num_resources=ARRAY_SIZE(button_res),
.resource = button_res,
};
static int __init button_init(void)
{
int ret;
// button=platform_device_alloc("button_plat",-1);
// button->resource=button_res;
// button->num_resources=ARRAY_SIZE(button_res),
// ret=platform_device_add(button);
ret = platform_device_register(&button);
if(ret)
{
platform_device_put(&button);
printk(KERN_ALERT "device add error %d/n",ret);
}
else
printk(KERN_INFO"button device has hanged on the platform bus!/n");
return ret;
}
static void __exit button_exit(void)
{
platform_device_unregister(&button);
printk(KERN_INFO"button device has hanged off the platform bus!/n");
}
module_init(button_init);
module_exit(button_exit);
platform_driver
/*
程序说明:platform bus上的button device的驱动
作者:谢思源
时间:2010.7.16
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
bool en_button=0;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //申明一个等待队列
static char data_old[6]={'1','1','1','1','1','1'};
struct button_irq_desc {
int irq;
int pin;
int pin_setting;
int number;
char *name;
};
static struct button_irq_desc button_irq[]={
{IRQ_EINT8, S3C2410_GPG(0), S3C2410_GPG0_EINT8, 0, "KEY0"},
{IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"},
{IRQ_EINT13, S3C2410_GPG(5), S3C2410_GPG5_EINT13 , 2, "KEY2"},
{IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"},
{IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"},
{IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"},
};
static irqreturn_t button_irq_func(int irq,void *dev)
{
struct button_irq_desc *button=(struct button_irq_desc *)dev;
int data; //保存读取出来的数值
char ch;
data=!s3c2410_gpio_getpin(button->pin);
if(data==1) //按键被按下
ch='0';
else if(data==0)
ch='1';
if(ch!=data_old[button->number])
{
data_old[button->number]=ch;
en_button=1;
wake_up(&button_waitq);
printk(KERN_INFO"driver read data=%d!/n",data);
}
return IRQ_RETVAL(IRQ_HANDLED);
}
static int btn_open(struct inode *inode,struct file *filp)
{
//打开设备,为中断做准备
int i,ret,j;
for(i=0;i<6;i++)
{
if(button_irq[i].irq<0)
continue;
ret=request_irq(button_irq[i].irq,button_irq_func,IRQ_TYPE_EDGE_BOTH,button_irq[i].name,(void *)&button_irq[i]);
if(ret<0)
{
printk(KERN_INFO"%d interrupt request error!/n",button_irq[i].irq);
for(j=0;j<=i;j++)
{
disable_irq(button_irq[i].irq);
free_irq(button_irq[i].irq,(void *)&button_irq[i]);
}
return -1;
}
}
en_button=1;
return 0;
}
static int btn_read(struct file *filp,char __user *buf,size_t len,loff_t *offp)
{
int ret;
if(!en_button) //没有按下按键
{
if(filp->f_flags&O_NONBLOCK)
{
return -EAGAIN;
}
//.阻塞进程
wait_event_interruptible(button_waitq,en_button);
}
en_button=0;
ret=copy_to_user(buf,(void *)data_old,(len>sizeof(data_old))?sizeof(data_old):len);
if(ret!=0)
{
printk(KERN_INFO"copy_to_user error!/n");
return -1;
}
printk(KERN_INFO"read len = %d!/n",(len>sizeof(data_old))?sizeof(data_old):len);
return (len>sizeof(data_old))?sizeof(data_old):len;
}
static int btn_close(struct inode *inode,struct file *filp)
{
//关闭文件时候要关闭中断
int i;
for(i=0;i<6;i++)
{
if(button_irq[i].irq<0)
continue;
disable_irq(button_irq[i].irq);
free_irq(button_irq[i].irq,(void *)&button_irq[i]);
}
printk(KERN_INFO"xsy-plat-buttons released!/n");
return 0;
}
static unsigned int btn_poll(struct file *filp,struct poll_table_struct *wait)
{
int mask;
poll_wait(filp,&button_waitq,wait);
if(en_button)
mask=POLLIN|POLLRDNORM;
return mask;
}
static struct file_operations button_fops={
.open=btn_open,
.read=btn_read,
.release=btn_close,
.owner=THIS_MODULE,
.poll=btn_poll,
};
//为按键申请混杂设备
static struct miscdevice button_misc={
.minor=250, //混杂设备次设备号
.name="xsy-plat-buttons",
.fops=&button_fops,
};
static int __devinit btn_probe(struct platform_device *pdev)
{
int i,ret;
// struct device *dev;
// dev=&pdev->dev;
// struct resource *button_res
//匹配成功,进入probe,首先获取设备中断资源
for(i=0;i<6;i++)
{
button_irq[i].irq=platform_get_irq(pdev,i);
if(button_irq[i].irq<0)
{
printk(KERN_INFO"error:platform_get_irq: %d %d/n",i,button_irq[i].irq);
return -ENOENT;
}
printk("button_irq[%d] is %d/n",i,button_irq[i].irq);
}
//注册misc设备,只有在发现设备和驱动匹配时候才创建misc设备,
ret=misc_register(&button_misc);
return ret;
}
static int __devexit btn_remove(struct platform_device *dev)
{
misc_deregister(&button_misc);
return 0;
}
static struct platform_driver button={
.probe=btn_probe,
.remove=btn_remove,
.driver={
.name="button_plat",
.owner=THIS_MODULE,
},
};
static int __init button_init(void)
{
int ret;
ret=platform_driver_register(&button);
printk(KERN_INFO"按键驱动已经注册!/n");
return 0;
}
static void __exit button_exit(void)
{
platform_driver_unregister(&button);
}
module_init(button_init);
module_exit(button_exit);
MODULE_AUTHOR("ECJTU CERT XIESIYUAN");
MODULE_LICENSE("GPL");