本次实验使用的kfifo相关宏

struct __kfifo {
	unsigned int	in;
	unsigned int	out;
	unsigned int	mask;
	unsigned int	esize;
	void		*data;

	
};
/*
 * define compatibility "struct kfifo" for dynamic allocated fifos
 */
struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);

判空:kfifo_is_empty

/**
 * kfifo_is_empty - returns true if the fifo is empty
 * @fifo: address of the fifo to be used
 */
#define	kfifo_is_empty(fifo) \
({ \
	typeof((fifo) + 1) __tmpq = (fifo); \
	__tmpq->kfifo.in == __tmpq->kfifo.out; \
})

 判满:kfifo_is_full

/**
 * kfifo_is_full - returns true if the fifo is full
 * @fifo: address of the fifo to be used
 */
#define	kfifo_is_full(fifo) \
({ \
	typeof((fifo) + 1) __tmpq = (fifo); \
	kfifo_len(__tmpq) > __tmpq->kfifo.mask; \
})

判断fifo可用空间大小 kfifo_avail

/**
 * kfifo_avail - returns the number of unused elements in the fifo
 * @fifo: address of the fifo to be used
 */
#define	kfifo_avail(fifo) \
__kfifo_uint_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmpq = (fifo); \
	const size_t __recsize = sizeof(*__tmpq->rectype); \
	unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \
	(__recsize) ? ((__avail <= __recsize) ? 0 : \
	__kfifo_max_r(__avail - __recsize, __recsize)) : \
	__avail; \
}) \
)

 为kfifo分配空间kfifo_alloc 

和kfifo_free成对使用。

/**
 * kfifo_alloc - dynamically allocates a new fifo buffer
 * @fifo: pointer to the fifo
 * @size: the number of elements in the fifo, this must be a power of 2
 * @gfp_mask: get_free_pages mask, passed to kmalloc()
 *
 * This macro dynamically allocates a new fifo buffer.
 *
 * The numer of elements will be rounded-up to a power of 2.
 * The fifo will be release with kfifo_free().
 * Return 0 if no error, otherwise an error code.
 */
#define kfifo_alloc(fifo, size, gfp_mask) \
__kfifo_int_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	__is_kfifo_ptr(__tmp) ? \
	__kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \
	-EINVAL; \
}) \
)

释放为kfifo分配的空间kfifo_free

/**
 * kfifo_free - frees the fifo
 * @fifo: the fifo to be freed
 */
#define kfifo_free(fifo) \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	if (__is_kfifo_ptr(__tmp)) \
		__kfifo_free(__kfifo); \
})

 kfifo_from_user:复制用户空间的数据到kfifo

kfifo_from_user()宏用来将用户空间的数据写入环形缓冲区中,其中参数fifo表示使用哪个环形缓冲区;from 表示用户空间缓冲区的起始地址;len 表示要复制多少个元素;copied保存了成功复制元素的数量,通常用作返回值。

/**
 * kfifo_from_user - puts some data from user space into the fifo
 * @fifo: address of the fifo to be used
 * @from: pointer to the data to be added
 * @len: the length of the data to be added
 * @copied: pointer to output variable to store the number of copied bytes
 *
 * This macro copies at most @len bytes from the @from into the
 * fifo, depending of the available space and returns -EFAULT/0.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
#define	kfifo_from_user(fifo, from, len, copied) \
__kfifo_uint_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	const void __user *__from = (from); \
	unsigned int __len = (len); \
	unsigned int *__copied = (copied); \
	const size_t __recsize = sizeof(*__tmp->rectype); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	(__recsize) ? \
	__kfifo_from_user_r(__kfifo, __from, __len,  __copied, __recsize) : \
	__kfifo_from_user(__kfifo, __from, __len, __copied); \
}) \
)

 kfifo_to_user:复制kfifo中的数据到用户空间

kfifo_to_user()宏用来读出环形缓冲区的数据并且复制到用户空间中,其中参数fifo表示使用哪个环形缓冲区;to表示用户空间缓冲区的起始地址;len 表示要复制多少个元素;copied保存了成功复制元素的数量,通常用作返回值。

/**
 * kfifo_to_user - copies data from the fifo into user space
 * @fifo: address of the fifo to be used
 * @to: where the data must be copied
 * @len: the size of the destination buffer
 * @copied: pointer to output variable to store the number of copied bytes
 *
 * This macro copies at most @len bytes from the fifo into the
 * @to buffer and returns -EFAULT/0.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
#define	kfifo_to_user(fifo, to, len, copied) \
__kfifo_uint_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	void __user *__to = (to); \
	unsigned int __len = (len); \
	unsigned int *__copied = (copied); \
	const size_t __recsize = sizeof(*__tmp->rectype); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	(__recsize) ? \
	__kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \
	__kfifo_to_user(__kfifo, __to, __len, __copied); \
}) \
)

 实验代码:

驱动代码:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/kfifo.h>

#define DEBUG_INFO(format, ...) printk("%s:%d -- "format"\n",\
__func__,__LINE__,##__VA_ARGS__)

struct ch5_kfifo_struct{
    struct miscdevice misc;
    struct file_operations fops;
    // struct __kfifo fifo;
    // DECLARE_KFIFO(fifo, char, 64);
    struct kfifo fifo;
    char buf[64];
};

static int ch5_open (struct inode *inode, struct file *file){
    struct ch5_kfifo_struct *p = (struct ch5_kfifo_struct *)container_of(file->f_op,struct ch5_kfifo_struct,fops);
    file->private_data = p;
    DEBUG_INFO("major = %d, minor = %d\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
    DEBUG_INFO("name = %s",p->misc.name);
    return 0;
}
static int ch5_release (struct inode *inode, struct file *file){
    DEBUG_INFO("close");
    return 0;
}

static ssize_t ch5_read (struct file *file, char __user *buf, size_t size, loff_t *pos){
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    int ret;
    int actual_readed = 0;
    if(kfifo_is_empty(&p->fifo)){
        DEBUG_INFO("kfifo is null");
        return 0;
    }
    ret = kfifo_to_user(&p->fifo, buf, size, &actual_readed);
    if (ret){
        DEBUG_INFO("kfifo_to_user error");
		return -EIO;
    }
    
    DEBUG_INFO("size = %d,actual_readed = %d\n",size,actual_readed);

    memset(p->buf,0,sizeof(p->buf));
    ret = copy_from_user(p->buf, buf, actual_readed);
    
    if(ret != 0){
        DEBUG_INFO("copy_from_user error ret = %d\n",ret);
    }else{
        DEBUG_INFO("p->buf = %s\n",p->buf);
    }
    return 0;
}
static ssize_t ch5_write (struct file *file, const char __user *buf, size_t size, loff_t* pos){
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    int actual_writed = 0;
    int ret;
    ret = kfifo_from_user(&p->fifo, buf, size, &actual_writed);
    if (ret){
        DEBUG_INFO("kfifo_from_user error");
		return -EIO;
    }
    DEBUG_INFO("actual_writed = %d\n",actual_writed);

    if(*pos == 0){
        *pos = size;
        return size;
    }
    *pos = *pos + size;
    return size;
}

struct ch5_kfifo_struct ch5_kfifo = {
    .misc = { 
        .name = "ch5-03-kfifo",
        .minor = MISC_DYNAMIC_MINOR,
    },
    .fops = {
        .owner = THIS_MODULE,
        .read = ch5_read,
        .write = ch5_write,
        .open = ch5_open,
        .release = ch5_release,
    },
};

static int __init ch5_init(void){
    int ret = 0;
    DEBUG_INFO("start init\n");
    ch5_kfifo.misc.fops = &ch5_kfifo.fops;
    ret = kfifo_alloc(&ch5_kfifo.fifo,
				64,
				GFP_KERNEL);
    if (ret) {
        DEBUG_INFO("kfifo_alloc error: %d\n", ret);
        ret = -ENOMEM;
        return ret;
    }
    DEBUG_INFO("kfifo_alloc ok");

    ret = misc_register(&ch5_kfifo.misc);
    if(ret < 0){
        DEBUG_INFO("misc_register error: %d\n", ret);
        return ret;
    }
    DEBUG_INFO("misc_register ok");
    return 0;
}

static void __exit ch5_exit(void){
    DEBUG_INFO("exit\n");
    misc_deregister(&ch5_kfifo.misc);
    kfifo_free(&ch5_kfifo.fifo);
}

module_init(ch5_init);
module_exit(ch5_exit);

MODULE_LICENSE("GPL");

应用代码

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>

#define DEBUG_INFO(format, ...) printf("%s:%d -- "format"\n",\
__func__,__LINE__,##__VA_ARGS__)

int main(int argc, char**argv){
    int fd;
    char buf[1024];
    char *filename = NULL;
    if(argc < 2){
        filename = "/dev/ch5-03-kfifo";
    }else{
        filename = argv[1];
    }

    fd = open(argv[1], O_WRONLY);
    if(fd < 0){
        perror("open");
        return -1;
    }
    write(fd, filename, strlen(filename));
    memset(buf, 0, sizeof(buf));
    close(fd);

    fd = open(argv[1], O_RDONLY);
    if(fd < 0){
        perror("open");
        return -1;
    }
    memset(buf, 0, sizeof(buf));
    read(fd, buf, sizeof(buf));
    DEBUG_INFO("buf = %s",buf);
    close(fd);

    return 0;
}

makefile

modname:=ch5-03-kfifo
obj-m:=$(modname).o
PWD :=$(shell pwd)
MAKE :=make
KERNELDIR = /home/lkmao/running_github/runninglinuxkernel_4.0
CROSS_COMPILE=arm-linux-gnueabi-
ARCH=arm
all:
	$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
	cp $(modname).ko /home/lkmao/running_github/runninglinuxkernel_4.0/kmodules
	arm-linux-gnueabi-gcc -o app app.c --static
	cp app /home/lkmao/running_github/runninglinuxkernel_4.0/kmodules

clean:
	rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions *.ko
.PHONY: all clean

测试结果:

 小结

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐