驱动描述:该驱动是一个完整的蜂鸣器驱动程序,考虑到了竟态的情况,实现了一个驱动只
能由一个应用程
序打开。该驱动面向应用层提供了强大的操作接口。应用程序操?作蜂鸣器只需要调用write函数写入相应的1或0即可,调用read可以查看当前蜂鸣器的电平状态。然后再驱动层的write和read就会进行相应的动作,当然在应用程序打开驱动时,将会调用open函数初始化gpio等资源,和实现竟态机制。
下面是源代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define?ALLOW_OPEN_TIMES?2
//定义硬件相关的数据结构
struct?button_resource?{
char?*name;
//名称
unsigned?int?gpio;
//GPIO编号
};
//定义驱动私有的数据结构
struct?button_priv{
struct?cdev?btn_cdev;
//为了利用container_of
atomic_t?av;
//整型原子变量
int?open_times;
//记录设备打开的次数
spinlock_t?lock;
//分配自旋锁
struct?semaphore?sema;?//分配信号量
};
static?struct?button_priv?*pbtn?=?NULL;
//主设备号
static?int?major;
//设备类
static?struct?class?*cls;
static?int?buzzer_open(struct?inode?*inode,?struct?file?*file)
{
unsigned?long?flags;
struct?button_priv?*pbtnp?=?container_of(inode->i_cdev,
struct?button_priv,?btn_cdev);
file->private_data?=?pbtnp;
gpio_request(S5PV210_GPD0(1),?”buzzer”);
gpio_direction_output(S5PV210_GPD0(1),?0);
#if?0
if?(!atomic_dec_and_test(&pbtnp->av))?{
printk(“button?can?be?open?only?once!\n”);
atomic_inc(&pbtnp->av);
return?-EBUSY;
}
spin_lock_irqsave(&pbtnp->lock,?flags);?//加锁
if?(pbtnp->open_times?>=?2)?{
printk(“allow?open?%d?times\n”,?ALLOW_OPEN_TIMES);
spin_unlock_irqrestore(&pbtnp->lock,?flags);//释放锁
return?-EBUSY;
}
pbtnp->open_times++;
spin_unlock_irqrestore(&pbtnp->lock,?flags);?//释放锁
#endif
#if?0
if(down_trylock(&pbtnp->sema))?{
printk(“button?can?be?open?only?once!\n”);
return?-EBUSY;
}
#endif
//down(&pbtnp->sema);
if?(down_interruptible(&pbtnp->sema))?{
printk(“Proccess?is?INT!\n”);
return?-EINTR;
}
printk(“open?button?successfully!\n”);
return?0;
}
static?int?buzzer_close(struct?inode?*inode,
struct?file?*file)
{
struct?button_priv?*pbtnp?=?file->private_data;
gpio_direction_output(S5PV210_GPD0(1),?0);
gpio_free(S5PV210_GPD0(1));
//atomic_inc(&pbtnp->av);
美国高防vps
#if?0
unsigned?long?flags;
spin_lock_irqsave(&pbtnp->lock,?flags);
pbtnp->open_times–;
spin_unlock_irqrestore(&pbtnp->lock,?flags);
#endif
up(&pbtnp->sema);
return?0;
}
static?int?status;
static?ssize_t?buzzer_read(struct?file?*file,?char?__user?*buf,
size_t?count,?loff_t?*ppos)
{
copy_to_user(buf,?&status,?4);
return?0;
}
static?ssize_t?buzzer_write(struct?file?*file,?char?__user?*buf,
size_t?count,?loff_t?*ppos)
{
int?val;
copy_from_user(&val,?buf,?4);
if?(val?==?1)?{
gpio_set_value(S5PV210_GPD0(1),?1);
}?else?{
gpio_set_value(S5PV210_GPD0(1),?0);
}
status?=?val;
return?0;
}
//设备的操作集合
static?struct?file_operations?btn_fops?=?{
.owner?=?THIS_MODULE,
.open?=?buzzer_open,
.release?=?buzzer_close,
.read?=?buzzer_read,
.write=?buzzer_write
};
static?int?button_init(void)
{
dev_t?dev_id;
if?(major)?{
dev_id?=?MKDEV(major,?0);
register_chrdev_region(dev_id,?1,?”button”);
}?else?{
alloc_chrdev_region(&dev_id,?0,?1,?”button”);
major?=?MAJOR(dev_id);
}
pbtn?=?kmalloc(sizeof(struct?button_priv),?GFP_KERNEL);
memset(pbtn,?0?,sizeof(struct?button_priv));
cdev_init(&pbtn->btn_cdev,?&btn_fops);
atomic_inc(&pbtn->av);
spin_lock_init(&pbtn->lock);
sema_init(&pbtn->sema,?1);?//互斥信号量
cdev_add(&pbtn->btn_cdev,?dev_id,?1);
cls?=?class_create(THIS_MODULE,?”button”);
device_create(cls,?NULL,?dev_id,?NULL,?”button”);
return?0;
}
static?void?button_exit(void)
{
dev_t?dev_id?=?MKDEV(major,?0);
device_destroy(cls,?dev_id);
class_destroy(cls);
cdev_del(&pbtn->btn_cdev);
unregister_chrdev_region(dev_id,?1);
kfree(pbtn);
pbtn?=?NULL;
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE(“GPL?v2”);