本次实验使用的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) modulescp $(modname).ko /home/lkmao/running_github/runninglinuxkernel_4.0/kmodulesarm-linux-gnueabi-gcc -o app app.c --staticcp app /home/lkmao/running_github/runninglinuxkernel_4.0/kmodulesclean:rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions *.ko
.PHONY: all clean
测试结果: