linux device driver —— 环形缓冲区的实现
还是没有接触到怎么控制硬件,但是在书里看到了一个挺巧妙的环形缓冲区实现。
此环形缓冲区实际为一个大小为bufsize的一维数组,有一个rp的读指针,一个wp的写指针。
在数据满时写进程会等待读进程读取数据,数据为空时读进程会等待写进程写入数据。
在上次代码上改的,所以名字还是ioctldemo
ioctldemo.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/semaphore.h>
#include <asm-generic/uaccess.h>
#include <asm-generic/ioctl.h>
#include <asm-generic/current.h>
#define IOCTLDEMO_MAJOR 0
#define MODULE_NAME "ioctldemo"
#define DEMO_MAGIC 'm'
#define DEMO_SIZE int
#define DEMO_NR_MAX 1
#define MY_IOCTL_READ _IOR(DEMO_MAGIC,1,DEMO_SIZE);
static int ioctldemo_major = IOCTLDEMO_MAJOR;
void ioctldemo_exit(void);
int ioctldemo_init(void);
long my_unlocked_ioctl(struct file*, unsigned int, unsigned long);
int my_cdev_open(struct inode*, struct file*);
int my_cdev_release(struct inode*,struct file*);
ssize_t my_cdev_read (struct file*, char __user*, size_t, loff_t *);
ssize_t my_cdev_write(struct file*, const char __user*, size_t, loff_t *);
MODULE_LICENSE("Dual BSD/GPL");
module_param(ioctldemo_major,int,S_IRUGO);
module_init(ioctldemo_init);
module_exit(ioctldemo_exit);
struct dev_driver
{
wait_queue_head_t inq,outq; //read and write queues
char *buffer, *end; //begin of buff, end of buff
int bufsize;//为了方便取余,必须为2的n次幂
char *rp,*wp;
struct semaphore sem;
struct cdev my_cdev;
}my_driver;
static struct file_operations cdev_ops =
{
.owner = THIS_MODULE,
.open = my_cdev_open,
.release = my_cdev_release,
.read = my_cdev_read,
.write = my_cdev_write,
};
int __init ioctldemo_init(void)
{
int ret;
dev_t devno;
printk(KERN_NOTICE "=== ioctldemo_init start\n");
devno = MKDEV(ioctldemo_major,);
if(ioctldemo_major)
{
printk(KERN_NOTICE "=== ioctldemo_init try register\n");
ret = register_chrdev_region(devno,,MODULE_NAME);
}else
{
printk(KERN_NOTICE "=== ioctldemo_init auto register\n");
ret = alloc_chrdev_region(&devno,,,MODULE_NAME);
ioctldemo_major = MAJOR(devno);
}
)
{
printk(KERN_NOTICE "=== ioctldemo_init register fail\n");
return ret;
}
cdev_init(&my_driver.my_cdev,&cdev_ops);
my_driver.my_cdev.owner = THIS_MODULE;
ret = cdev_add(&my_driver.my_cdev,MKDEV(ioctldemo_major,),);
)
{
printk(KERN_NOTICE "=== ioctldemo_init add cdev fail\n");
return ret;
}
//init buffer
my_driver.bufsize= <<;
my_driver.buffer = (char*)kmalloc(my_driver.bufsize,GFP_KERNEL);
my_driver.end = my_driver.buffer + my_driver.bufsize;
my_driver.rp = my_driver.wp = my_driver.buffer;
printk(KERN_DEBUG "ioctldemo buf->%p, end->%p",my_driver.buffer,my_driver.end);
//init semaphore
sema_init(&my_driver.sem,);
//init wait queue
init_waitqueue_head(&my_driver.inq);
init_waitqueue_head(&my_driver.outq);
printk(KERN_NOTICE "=== ioctldemo_init finish\n");
;
}
void __exit ioctldemo_exit(void)
{
printk (KERN_NOTICE "=== ioctldemo_exit");
kfree(my_driver.buffer);
cdev_del(&my_driver.my_cdev);
unregister_chrdev_region(MKDEV(ioctldemo_major,),);
}
int my_cdev_open(struct inode *node, struct file *filp)
{
;
}
int my_cdev_release(struct inode *node, struct file *filp)
{
;
}
/*一个环形缓冲区的不覆盖读写实现。
*对于 read函数: 写指针和读指针重合时视为数据为空,等待输入数据。每次读取最多读到缓冲区数组尾部。
*对于write函数: 每次写入最多写入到(读指针-1)位置或缓冲区数组尾部,如果写指针在读指针的前一项(相对环形来说)视为队列已满,等待读取数据。
*/
ssize_t my_cdev_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
if(down_interruptible(&my_driver.sem))
return -ERESTARTSYS;
while(my_driver.rp == my_driver.wp)
{
up(&my_driver.sem);
if(filp->f_flags == O_NONBLOCK)
return -EAGAIN;
printk(KERN_NOTICE "%s :reading, go to sleep\n",current->comm);
if(wait_event_interruptible(my_driver.inq,(my_driver.rp != my_driver.wp)))
return -ERESTARTSYS;
if(down_interruptible(&my_driver.sem))
return -ERESTARTSYS;
printk(KERN_DEBUG "%s :read awoken from waiting,rp:%p, rp:%p\n",current->comm,my_driver.rp,my_driver.wp);
}
if(my_driver.wp > my_driver.rp)
count = min(count,(size_t)(my_driver.wp - my_driver.rp));
else
count = min(count,(size_t)(my_driver.end - my_driver.rp));
if(copy_to_user(buf,my_driver.rp,count))
{
up(&my_driver.sem);
return -EFAULT;
}
my_driver.rp += count;
if(my_driver.rp == my_driver.end)
{
my_driver.rp = my_driver.buffer;
printk(KERN_DEBUG "ioctldemo convert rp");
}
up(&my_driver.sem);
wake_up_interruptible(&my_driver.outq);
printk(KERN_NOTICE "%s did read %ld bytes\n",current->comm,count);
return count;
}
//get max space that is free now
size_t my_cdev_getfree(struct dev_driver *drp)
{
if(drp->rp == drp->wp)
;
)) - ;
}
ssize_t my_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
if(down_interruptible(&my_driver.sem))
return -ERESTARTSYS;
)
{
up(&my_driver.sem);
if(filp->f_flags == O_NONBLOCK)
return -EAGAIN;
printk(KERN_NOTICE "%s :write go to sleep\n",current->comm);
)))
return -ERESTARTSYS;
if(down_interruptible(&my_driver.sem))
return -ERESTARTSYS;
printk(KERN_NOTICE "%s :write awoken from sleep\n",current->comm);
}
count = min(count,my_cdev_getfree(&my_driver));
if(my_driver.wp >= my_driver.rp)
count = min(count,(size_t)(my_driver.end - my_driver.wp));
else// writer pointer has wrapped, fill up to rp-1
count = min(count,(size_t)(my_driver.rp - my_driver.wp -));
if(copy_from_user(my_driver.wp,buf,count))
{
up(&my_driver.sem);
return -EFAULT;
}
my_driver.wp += count;
if(my_driver.wp == my_driver.end)
{
my_driver.wp = my_driver.buffer;
printk(KERN_DEBUG "ioctldemo convert wp");
}
up(&my_driver.sem);
wake_up_interruptible(&my_driver.inq);
printk(KERN_NOTICE "%s did write %ld bytes\n",current->comm,count);
return count;
}
编译,安装,卸载脚本见
测试:
例如我把驱动挂载到了/dev/ioctldemo
可以执行以下命令
cat /dev/ioctldemo
此时缓冲区因为没有数据,所以等待输入。
再打开另外一个终端,输入命令
ls > /dev/ioctldemo
可以看到之前的窗口显示出来了数据。
linux device driver —— 环形缓冲区的实现的更多相关文章
- Linux Device Driver 学习(1)
Linux Device Driver 学习(1) 一.搭建虚拟机开发环境 1.选择虚拟机VirtualBox,官网下载.deb包安装: VirtualBox Linux 5.1.6 下载fedora ...
- how to write your first linux device driver
how to write your first linux device driver 0. environment-ubuntu 1804 64bit 1. apt-get install linu ...
- Linux Device Driver && Device File
catalog . 设备驱动程序简介 . I/O体系结构 . 访问设备 . 与文件系统关联 . 字符设备操作 . 块设备操作 . 资源分配 . 总线系统 1. 设备驱动程序简介 设备驱动程序是内核的关 ...
- How to learn linux device driver
To learn device driver development, like any other new knowledge, the bestapproach for me is to lear ...
- <<linux device driver,third edition>> Chapter 4:Debugging Techniques
Debugging by Printing printk lets you classify messages accoring to their severity by associating di ...
- <<linux device driver,third edition>> Chapter 3:Char Drivers
The Internal Representation of Device Numbers Within the kernel,the dev_t type(defined in linux/type ...
- linux device driver —— ioctl
实现了应用程序和设备驱动通过ioctl通信.还是对设备驱动没什么感觉,贴一下代码吧. 在Ubuntu 16.04 64bit中测试通过 ioctldemo.c #include <linux/m ...
- linux device driver —— 字符设备
现在对linux设备驱动还没有什么认识,跟着书上敲了一个字符驱动,这里把代码贴一下. 测试环境是 Ubuntu 16.04 64bit 驱动程序: #include <linux/fs.h> ...
- <<linux device driver,third edition>> Chapter 2: Building and Running Modules
Kernel Modules Versus Applications Kernel modules programming is similar to event driven programming ...
随机推荐
- 通过阅读ASP.NET MVC5 框架解密 路由的一点心得
路由: 1.在ASP.NET中路由不专属与ASP.NET MVC,因为路由(Route)是在system.web 命名空间下的,所以传统的WebForm也可以使用路由. 2.什么叫做路由 采用某种机制 ...
- Java 高效检查一个数组中是否包含某个值
如何检查一个数组(未排序)中是否包含某个特定的值?在Java中,这是一个非常有用并又很常用的操作.同时,在StackOverflow中,有时一个得票非常高的问题.在得票比较高的几个回答中,时间复杂度差 ...
- select 模型
http://www.cnblogs.com/Anker/p/3258674.html http://www.cnblogs.com/cozy/articles/2088128.html http:/ ...
- bzoj 2733: [HNOI2012]永无乡 离线+主席树
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1167 Solved: 607[Submit][Status ...
- [BZOJ 1115] [POI2009] 石子游戏Kam 【阶梯博弈】
题目链接:BZOJ - 1115 题目分析 首先看一下阶梯博弈: 阶梯博弈是指:初始有 n 堆石子,每次可以从任意的第 i 堆拿若干石子放到第 i - 1 堆.最终不能操作的人失败. 解法:将奇数位的 ...
- ibatis把表名作为一个参数报错问题的解决方案
用ibatis的时候,想把表名也作为一个参数传进去,可是报错了,在ibatis配置文件里面是#resource#的方式,报错信息如下: org.apache.cxf.interceptor.Fault ...
- C/C++ 开源库及示例代码
C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...
- 经典的单例模式c3p0来控制数据库连接池
package com.c3p0.datapools; //数据库连接池 单例模式 import java.sql.Connection; import java.sql.SQLException; ...
- git在myelispse中的安装
1.git在myelispse中的安装 http://blog.csdn.net/chinaonlyqiu/article/details/8830050
- 【HDOJ】1394 Minimum Inversion Number
逆序数的性质.1. 暴力解 #include <stdio.h> #define MAXNUM 5005 int a[MAXNUM]; int main() { int n; int i, ...