本次实验使用的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
测试结果: