专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > 驱动开发

容易驱动实现

发布时间:2010-06-14 16:41:10 文章来源:www.iduyao.cn 采编人员:星星草
简单驱动实现
源代码及编译好的模块在以下链接,如有不懂请请看readme文件(我是在linux下写的,包括代码,如果有乱码请在linux下用VI打开 )
http://download.csdn.net/detail/qixing1115/5694401


类似于内核fifo的源码,实现有open/read/write方法,内部有信号机制及阻塞、非阻塞模型的简单应用,可能会有一些BUG,可能只对初学者有些用吧,只供参考
信号机制
阻塞、非阻塞模型
private_data:一个驱动对应多个设备节点的相似设备
fifo采用的是循环队列
首先看下设备的结构体定义
typedef struct fifo_device_t
{
char *buffer; //内存空间
char *buffer_end; //指向内存的结尾
char *rp, *wp; //读/写指针
int buffer_size; //内存空间的大小
int nreader, nwriter;//读者/写者的个数(目前没有用到)
struct cdev cdev; //设备
struct semaphore sem; //信号号
wait_queue_head_t inq, outq; //等待队列头
}fifo_dev_t;

1:static int fifo_init(void)
功能:设备号申请、注册,为设备申请内存空间,主要代码如下:
devno1 = MKDEV(fifo_major, 0);
devno2 = MKDEV(fifo_major, 1);
ret = register_chrdev_region(devno1,devnr, devname); 
//为设备申请内存空间,
//注意,1:这里并没有为buffer申请空间,为什么没有在这里申请???
//2:可不可以在这里申请??
//3:为什么申请了两倍的(fifo_dev_t)空间???
fifo_dev = kmalloc(2 * sizeof(fifo_dev_t), GFP_KERNEL);
if(fifo_dev == NULL)
goto err1;

memset(fifo_dev, 0,2 * sizeof(fifo_dev_t));

ret = cdev_setup(&(fifo_dev[0].cdev), devno1);
ret = cdev_setup(&(fifo_dev[1].cdev), devno2);

cdev_setup函数很简单:初始化并添加设备

cdev_init(cdev, &fifo_ops);
cdev->owner = THIS_MODULE;
ret = cdev_add(cdev, devno, devnr);


2:static int fifo_open(struct inode *inode, struct file *filp)
功能:增加使用计数、识别次设备号、初始化private data、为buffer申请空间并进行一些初始化
	//找到对应的设备, 原理可以看下container_of(宏)函数的具体实现
tmp_dev = container_of(inode->i_cdev, fifo_dev_t, cdev);
filp->private_data = tmp_dev;
//为buffer 申请空间并对结构体成员进行初始化
tmp_dev->buffer = kmalloc(tmp_dev->buffer_size, GFP_KERNEL);
//注意以下三条初始化是不可以放在fifo_init函数里的
init_MUTEX(&tmp_dev->sem);
init_waitqueue_head(&tmp_dev->inq);
init_waitqueue_head(&tmp_dev->outq);



3:ssize_t fifo_read(struct file *filp, char __user *buf, size_t size, loff_t *off)
    功能:读(虽然功能 简单,只是一个读操作,但实现 起来可不简单
    
fifo_dev_t *tmp_dev = filp->private_data;	//这句不要忘 了
    //这里获取信号量
if(down_interruptible(&tmp_dev->sem) != 0)
return -ERESTARTSYS;
//如果buffer为空的话不是进行读操作
while(fifo_isempty(tmp_dev))
{
up(&tmp_dev->sem);
//如果以非阻塞模式打开的话直接返回,
//如果以阻塞模式打开的话则睡眠
if((filp->f_flags & O_NONBLOCK) != 0)
return -EAGAIN;
else
{
if(wait_event_interruptible(tmp_dev->inq, !fifo_isempty(tmp_dev)) != 0)
return -ERESTARTSYS;
if(down_interruptible(&tmp_dev->sem) != 0)
return -ERESTARTSYS;
}
}
//把buffer 里的内容放在一个临时申请的空间里,我感觉这样操作起来简单一些
//如果你认为这样多余的话可以试着不用临时空间,
for(i = 0; i < n; i ++)
{
if(tmp_dev->rp > tmp_dev->buffer_end)
tmp_dev->rp = tmp_dev->buffer;

*(p + i) = *tmp_dev->rp;
tmp_dev->rp++;
}
//这时是真正的读取了
if(copy_to_user(buf, p, n))
{
up(&tmp_dev->sem);
return -EFAULT;
}



4://write的操作基本和read一样,就不多解释了
static ssize_t fifo_write(struct file *filp,const char __user *buf, size_t size, loff_t *off)
------解决方案--------------------
楼主遇到什么问题?
------解决方案--------------------
你好,想问下,为什么不能在Init里面申请buffer?
------解决方案--------------------
你阻塞的方式实现了,实现poll很容易啊。
static unsigned int fifo_poll(struct file *filp, poll_table *wait)
{
    struct scull_pipe *dev = filp->private_data;
    unsigned int mask = 0;

    poll_wait(filp, &tmp_dev->inq,  wait);
    poll_wait(filp, &tmp_dev->outq, wait);

    if (tmp_dev->rp != tmp_dev->wp)
        mask 
------解决方案--------------------
= POLLIN 
------解决方案--------------------
 POLLRDNORM;    /* readable */
    if (spacefree(tmp_dev)) // check if has space for read
        mask 
------解决方案--------------------
= POLLOUT 
------解决方案--------------------
 POLLWRNORM;   /* writable */

    return mask;
}
友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

热门推荐: