还是没有接触到怎么控制硬件,但是在书里看到了一个挺巧妙的环形缓冲区实现。

此环形缓冲区实际为一个大小为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 —— 环形缓冲区的实现的更多相关文章

  1. Linux Device Driver 学习(1)

    Linux Device Driver 学习(1) 一.搭建虚拟机开发环境 1.选择虚拟机VirtualBox,官网下载.deb包安装: VirtualBox Linux 5.1.6 下载fedora ...

  2. 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 ...

  3. Linux Device Driver && Device File

    catalog . 设备驱动程序简介 . I/O体系结构 . 访问设备 . 与文件系统关联 . 字符设备操作 . 块设备操作 . 资源分配 . 总线系统 1. 设备驱动程序简介 设备驱动程序是内核的关 ...

  4. How to learn linux device driver

    To learn device driver development, like any other new knowledge, the bestapproach for me is to lear ...

  5. <<linux device driver,third edition>> Chapter 4:Debugging Techniques

    Debugging by Printing printk lets you classify messages accoring to their severity by associating di ...

  6. <<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 ...

  7. linux device driver —— ioctl

    实现了应用程序和设备驱动通过ioctl通信.还是对设备驱动没什么感觉,贴一下代码吧. 在Ubuntu 16.04 64bit中测试通过 ioctldemo.c #include <linux/m ...

  8. linux device driver —— 字符设备

    现在对linux设备驱动还没有什么认识,跟着书上敲了一个字符驱动,这里把代码贴一下. 测试环境是 Ubuntu 16.04 64bit 驱动程序: #include <linux/fs.h> ...

  9. <<linux device driver,third edition>> Chapter 2: Building and Running Modules

    Kernel Modules Versus Applications Kernel modules programming is similar to event driven programming ...

随机推荐

  1. 通过阅读ASP.NET MVC5 框架解密 路由的一点心得

    路由: 1.在ASP.NET中路由不专属与ASP.NET MVC,因为路由(Route)是在system.web 命名空间下的,所以传统的WebForm也可以使用路由. 2.什么叫做路由 采用某种机制 ...

  2. Java 高效检查一个数组中是否包含某个值

    如何检查一个数组(未排序)中是否包含某个特定的值?在Java中,这是一个非常有用并又很常用的操作.同时,在StackOverflow中,有时一个得票非常高的问题.在得票比较高的几个回答中,时间复杂度差 ...

  3. select 模型

    http://www.cnblogs.com/Anker/p/3258674.html http://www.cnblogs.com/cozy/articles/2088128.html http:/ ...

  4. bzoj 2733: [HNOI2012]永无乡 离线+主席树

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1167  Solved: 607[Submit][Status ...

  5. [BZOJ 1115] [POI2009] 石子游戏Kam 【阶梯博弈】

    题目链接:BZOJ - 1115 题目分析 首先看一下阶梯博弈: 阶梯博弈是指:初始有 n 堆石子,每次可以从任意的第 i 堆拿若干石子放到第 i - 1 堆.最终不能操作的人失败. 解法:将奇数位的 ...

  6. ibatis把表名作为一个参数报错问题的解决方案

    用ibatis的时候,想把表名也作为一个参数传进去,可是报错了,在ibatis配置文件里面是#resource#的方式,报错信息如下: org.apache.cxf.interceptor.Fault ...

  7. C/C++ 开源库及示例代码

    C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...

  8. 经典的单例模式c3p0来控制数据库连接池

    package com.c3p0.datapools; //数据库连接池  单例模式 import java.sql.Connection; import java.sql.SQLException; ...

  9. git在myelispse中的安装

    1.git在myelispse中的安装 http://blog.csdn.net/chinaonlyqiu/article/details/8830050

  10. 【HDOJ】1394 Minimum Inversion Number

    逆序数的性质.1. 暴力解 #include <stdio.h> #define MAXNUM 5005 int a[MAXNUM]; int main() { int n; int i, ...