美文网首页
丰富杂项设备驱动的read和write

丰富杂项设备驱动的read和write

作者: 付凯强 | 来源:发表于2023-01-04 23:41 被阅读0次

引言

通过丰富杂项设备驱动的write和read方法来丰富杂项设备驱动。

char_misc_device.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>

#define DEMO_NAME "char_misc_device"
static struct device *my_char_misc_device;

static char device_buffer[64];
#define MAX_DEVICE_BUFFER_SIZE 64

static int char_device_open(struct inode *inode, struct file *file) {
    int major = MAJOR(inode->i_rdev);
    int minor = MINOR(inode->i_rdev);
    printk("%s: major=%d, minor=%d\n", __func__, major, minor);
    return 0;
}

static ssize_t char_device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
    int actual_readed;
    int max_free;
    int need_read;
    int ret;
    max_free = MAX_DEVICE_BUFFER_SIZE - *ppos;
    need_read = max_free > count ? count : max_free;
    if (need_read == 0) {
        dev_warn(my_char_misc_device, "no space for write");
    }
    ret = copy_to_user(buf, device_buffer + *ppos, need_read);
    if (ret == need_read) {
        return -EFAULT;
    }
    actual_readed = need_read - ret;
    *ppos += actual_readed;
    printk("%s,actual_readed = %d,pos=%lld\n", __func__, actual_readed, *ppos);
    return actual_readed;
}

static int char_device_release(struct inode *inode, struct file *file) {
    return 0;
}

static ssize_t char_device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
    int actual_write;
    int free;
    int need_write;
    int ret;
    free = MAX_DEVICE_BUFFER_SIZE - *ppos;
    need_write = free > count ? count : free;
    if (need_write == 0) {
        dev_warn(my_char_misc_device, "no space for write");
    }
    ret = copy_from_user(device_buffer + *ppos, buf, need_write);
    if (ret == need_write) {
        return -EFAULT;
    }
    actual_write = need_write - ret;
    *ppos += actual_write;
    printk("%s actual_write = %d,ppos=%lld\n", __func__, actual_write, *ppos);
    return actual_write;
}

static const struct file_operations char_device_fops = {
        .owner = THIS_MODULE,
        .open = char_device_open,
        .release = char_device_release,
        .read = char_device_read,
        .write = char_device_write
};

static struct miscdevice char_misc_device = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEMO_NAME,
        .fops = &char_device_fops,
};

static int __init simple_char_device_init(void) {
    int ret;
    ret = misc_register(&char_misc_device);
    if (ret) {
        printk("failed register misc device\n");
        return ret;
    }
    my_char_misc_device = char_misc_device.this_device;
    printk("successed regitster char device: %s\n", DEMO_NAME);
    return 0;
}

static void __exit simple_char_device_exit(void) {
    printk("removing device\n");
    misc_deregister(&char_misc_device);
}

module_init(simple_char_device_init);
module_exit(simple_char_device_exit);

MODULE_AUTHOR("fkq");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("simple character device");
  1. char_device_read有4个参数。file表示打开的虚拟设备文件;buf表示用户空间的内存起始地址,__user用来提醒开发者这个地址空间属于用户空间的;count表示用户想读取多少字节的数据;ppos表示文件的位置指针。
    char_device_read借助copy_to_user来复制杂项设备中的内容到用户空间buf缓冲区。
#include <linux/uaccess.h>
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);

第一个参数to是用户空间的指针,第二个参数from是内核空间指针,第三个参数n表示从内核空间向用户空间拷贝数据的字节数。
如果数据拷贝成功,则返回零;否则,返回没有拷贝成功的数据字节数。

  1. char_device_write参数与char_device_read一致,不再赘述。
    char_device_write借助copy_from_user来复制用户空间缓冲区内容到杂项设备中。
unsigned long copy_from_user(void * to, const void __user * from, unsigned long n)

第一个参数to是内核空间的数据目标地址指针,第二个参数from是用户空间的数据源地址指针,第三个参数n是数据的长度。
如果数据拷贝成功,则返回零;否则,返回没有拷贝成功的数据字节数。
此函数将from指针指向的用户空间地址开始的连续n个字节的数据传送到to指针指向的内核空间地址。

Makefile

KVERS = $(shell uname -r)

obj-m := char_misc_device.o

all:
    $(MAKE) -C /lib/modules/$(KVERS)/build M=$(PWD) modules

clean:
    $(MAKE) -C /lib/modules/$(KVERS)/build M=$(PWD) clean
    rm -rf *.ko;

makefile的文件内容被拷贝到本地之后,格式可能发生变化,这个需要调整格式,不然编译会报错。

编译驱动

make

加载驱动

sudo insmod char_misc_device.ko

添加权限

sudo chmod 777 /dev/char_misc_device

char_device_test.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define DEMO_DEV_NAME "/dev/char_misc_device"

int main() {
    char buffer[64];
    int fd;
    int ret;
    size_t len;
    char message[] = "Testing the virtual FIFO device";
    char *read_buffer;

    len = sizeof(message);

    fd = open(DEMO_DEV_NAME, O_RDWR);
    if (fd < 0) {
        printf("open device %s failed\n", DEMO_DEV_NAME);
        return -1;
    }

    /*1. write the message to device*/
    ret = write(fd, message, len);
    if (ret != len) {
        printf("can not write on device %d,ret=%d",fd,ret);
        return -1;
    }

    read_buffer = malloc(2*len);
    memset(read_buffer,0,2*len);

    /*close the fd, and reopen it*/
    close(fd);

    fd = open(DEMO_DEV_NAME,O_RDWR);
    if (fd < 0) {
        printf("open device %s failded\n",DEMO_DEV_NAME);
        return -1;
    }
    ret = read(fd, read_buffer, 2*len);
    printf("read %d bytes\n",ret);
    printf("read buffer=%s\n",read_buffer);

    close(fd);
    return 0;
}
$./char_device_test 
read 64 bytes
read buffer=Testing the virtual FIFO device

kernel日志

$dmesg
[4241440.269793] successed regitster char device: char_misc_device
[4241457.314147] char_device_open: major=10, minor=56
[4241457.314163] char_device_write actual_write = 32,ppos=32
[4241457.314305] char_device_open: major=10, minor=56
[4241457.314314] char_device_read,actual_readed = 64,pos=64

ppos

ppos不管在char_device_read还是char_device_write,方法初始时都是0。
为什么开始的时候都是0,这个作为一个TODO.

close

char_device_test.c中wrtie之后close fd之后,又重新open fd。为什么这样操作,这个作为一个TODO.

内核版本

Linux version 4.15.0-142-generic

参考

奔跑吧Linux内核入门篇第二版(这一节书中内容有错误,参考以上内容进行修复)

相关文章

  • 丰富杂项设备驱动的read和write

    引言 通过丰富杂项设备驱动的write和read方法来丰富杂项设备驱动。 char_misc_device.c c...

  • Linux驱动编程——misc设备驱动框架

    Linux驱动编程——misc设备驱动框架 主要概念: misc:杂项设备杂项设备是字符设备的一种,杂项设备可以自...

  • Linux驱动之平台设备(张栖银详谈)

    一、设备驱动的分层与分离 相信经过前面对字符设备驱动、杂项设备驱动和输入子系统的介绍,大家对Linux系统中的驱动...

  • Linux驱动开发入门

    设备驱动分类字符设备:可一个一个字节读取的设备,一般要实现open close read write ioctl等...

  • 字符驱动

    //////////////前边主要是说的是杂项设备驱动的注册,下边是字符驱动///////////////// ...

  • 杂项设备

    杂项设备可以说是对一部分字符设备的封装,还有一部分不好归类驱动也归到杂项设备。 •1为什么会引入杂项设备? ...

  • Linux驱动程序

    驱动程序包含以下类型的功能函数:drv_open(打开设备),drv_read(读),drv_write(写),d...

  • iOS蓝牙开发记录

    1、通过lightblue软件 可以得到蓝牙设备的属性,例如:write、read、write withoutRe...

  • 基于内存映射的设备驱动程序

    基于内存映射的设备驱动程序 通过添加内核模块实现一个基于内存映射的杂项设备驱动程序。

  • 设备 IO

    IO有两个特性:阻塞/非阻塞 与 同步/异步,组合一下就是四种情况。 同步设备驱动中,read/write方法属于...

网友评论

      本文标题:丰富杂项设备驱动的read和write

      本文链接:https://www.haomeiwen.com/subject/crtrcdtx.html