5.3.4.1 设备驱动模板

5.3.4.1 设备驱动模板

http://book.51cto.com  2007-08-16 09:37  苏东  电子工业出版社易飞思公司   我要评论(0)
5.3.4  设备驱动程序模板与实现
Linux下的驱动程序虽然复杂,但是总结下来还是有很多的规律可寻。Linux下的设备驱动开始编程时显得比较容易,可以轻松地开始驱动编写,但是要把驱动写好也的确需要花一定的时间去研究。
1.设备驱动模板
设备驱动模板代码如例程5-4所示。
例程5 4  Mydriver.c
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/irqs.h>
#include <asm/irq.h>
#include <asm/signal.h>
#include <asm/uaccess.h>
/*定义设备的从设备号*/
#define MYDRIVER_MINOR  174
/*定义设备相关数据结构*/
typedef struct _MYDRIVER_DEV
{
spinlock_t            dev_lock;
wait_queue_head_t     oWait;     
int                  open_count;

}MYDRIVER_DEV, *PMYDRIVER_DEV;
/*定义设备状态数据结构*/
typedef struct _MYDRIVER_DEV_STATS
{
unsigned long         rx_intrs;
unsigned long         rx_errors;
unsigned long         rx_blocks;
unsigned long         rx_dropped;
unsigned long         tx_intrs;
unsigned long         tx_errors;
unsigned long         tx_missed;
unsigned long         tx_blocks;
unsigned long         tx_dropped;
}MYDRIVER_DEV_STATS, * MYDRIVER_DEV_STATS;
unsigned int IntInit=0;
/*定义设备open接口函数*/
static int mydriver_open(struct inode *inode, struct file * filp)
{
int  minor;
DBGPRINT("mydriver_open/n");
minor = MINOR(inode->i_rdev);
if ( minor != MYDRIVER_MINOR )  { return -ENODEV; }

#ifdef MODULE
MOD_INC_USE_COUNT;    /*打开使用次数累加*/
#endif

mydriver_dev.open_count++;
if ( mydriver_dev.open_count == 1 )
{
DBGPRINT("mydriver_open: first opne/n");
/*第一次打开设备,在这里可以放些设备初始化代码*/
}
return 0;
}
/*定义设备close接口函数*/
static int mydriver_release(struct inode *inode, struct file *filp)
{
DBGPRINT("mydriver_release/n");
mydriver_dev.open_count--;
if ( mydriver_dev.open_count == 0 )
{
DBGPRINT("mydriver_release: last close/n");
/*设备彻底关闭,这里可以放一些使设备休眠,或者poweroff的代码*/
}
#ifdef MODULE
MOD_DEC_USE_COUNT;    /*打开次数递减*/
#endif
return 0;
}
/*定义设备read接口函数*/
static ssize_t mydriver_read(struct file *filp, char *buf, size_t size,
                   loff_t *offp)
{
if(size> 8192) size = 8192;
/* copy_to_user()*/
/*copy kernel space to user space. */
/*把数据从内核复制到用户空间的代码,可以根据实际添加*/
return size;                      /*返回字节数*/
}
/*定义设备write接口函数*/
static ssize_t mydriver_write(struct file *filp, const char *buf, size_t
                   size, loff_t *offp)
{
lock_kernel();
DBGPRINT("mydriver_write/n");
if(size> 8192)  size = 8192;
/*copy_from_user()*/
/*copy user space to kernel space. */   /*把数据从用户空间复制到内核空间*/
unlock_kernel();        
return size;                      /*返回字节数*/
}
/*定义设备ioctl接口函数*/
static int mydriver_ioctl(struct inode *inode, struct file *filp, unsigned
                   int cmd, unsigned long arg)
{
int  ret = 0;
DBGPRINT("mydriver_ioctl: cmd: 0x%x/n", cmd);
switch(cmd)
{
case cmd1:      /*命令字,注意幻数的使用*/
…..
break;
…..
case cmd3:
…..
break;
default:
DBGPRINT("mydriver_ioctl: bad ioctl cmd/n");
ret = -EINVAL;
break;
}
return ret;
}
/*定义设备select函数接口*/
static unsigned int mydriver_poll(struct file *filp, poll_table *wait)
{
poll_wait(filp,&mydriver_dev.oWait,wait);
if(IntInit)

IntInit=0;
return POLLIN|POLLRDNORM;  //可以写
}
else {  return POLLOUT;      //可以读 }
}
/*定义设备的file_operations*/
static struct file_operations  mydriver_fops =
{
owner:      THIS_MODULE,
open:       mydriver_open,
release:     mydriver_release,
read:       mydriver_read,
write:      mydriver_write,
ioctl:       mydriver_ioctl,
poll:       mydriver_poll,
};
/*定义设备结构体*/
static struct miscdevice  mydriver_miscdev =
{
MYDRIVER_MINOR,
" mydriver ",
& mydriver_fops
};
/*定义设备init函数*/
int __init mydriver_init(void)
{
int  ret;
DBGPRINT("mydriver_init/n");
ret =misc_register(&mydriver_miscdev); //注意这里调用misc_register()来注册
if ( ret )
{
 DBGPRINT("misc_register failed: 0x%x/n", ret);
return ret;
}
memset(&mydriver_dev, 0, sizeof(mydriver_dev));
init_waitqueue_head(&mydriver_dev.oWait);
spin_lock_init(&mydriver_dev->dev_lock);
/*这里可以放一些硬件初始化的函数*/   
return 0;
}
/*定义设备exit函数*/
void __exit mydriver_exit(void)
{
DBGPRINT("mydriver_exit/n");
misc_deregister(&mydriver_miscdev);  //注销misc dev
}
module_init(mydriver_init);
module_exit(mydriver_exit);
MODULE_LICENSE("GPL");
从上面的模板代码可以看出,设备驱动主要给上层提供file_operation和ioctl功能,实现上层对于底层设备的管理和读、写操作等。另外不同的设备调用的设备注册和注销函数有所不同,大家可以区分一下:misc_register()函数、register_chardev()函数、register_netdev()函数及misc_deregister()函数。也可以去分析一下deregister_chardev()函数和deregister_netdev() 函数的不同之处。
通常的设备驱动参照上面的模板就可以实现基本的框架了,当然还需要注意有关硬件的一些操作,包括初始化、参数设置、中断服务等。这些代码可以根据系统的设计放在driver_init里面,或者放在第一次打开的时候。
【责任编辑: 雪花 TEL:(010)68476606-8007】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值