dev_fifo.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/export.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
#include <asm/current.h>
MODULE_LICENSE("Dual BSD/GPL");
extern char *saved_command_line;
//指定的主设备号
#define MAJOR_NUM 232
//自己的字符设备
struct mycdev
{
int len;
unsigned char buffer[256]; //全局内存
struct cdev cdev; //记录描述字符设备的结构体
};
//设备号 dev_t记录设备类型,字符,块,网络
static dev_t dev_num = {0};
//全局gcd
struct mycdev *gcd;
//设备类
struct class *cls;
void dev_fifo_info(void)
{
printk(KERN_INFO "The process is \"%s\" (pid %i) (state %ld)\n", current->comm,current->pid,current->state);
//printk(KERN_INFO "Kernel command line: %s\n", saved_command_line);
}
//打开设备
static int dev_fifo_open(struct inode *inode, struct file *file)
{
printk("dev_fifo_open success!\n");
dev_fifo_info();
return 0;
}
//读设备
static ssize_t dev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos)
{
int n;
int ret;
char *kbuf;
printk("read *ppos : %lld\n",*ppos);
if(*ppos == gcd->len) //都为0返回0
return 0;
//请求大大小 > buffer剩余的字节数 :读取实际记得字节数
if(size > gcd->len - *ppos)
n = gcd->len - *ppos; //写进去的长度
else
n = size;
printk("n = %d\n",n);
//从上一次文件位置指针的位置开始读取数据
kbuf = gcd->buffer + *ppos;
//拷贝数据到用户空间
ret = copy_to_user(ubuf,kbuf, n);
if(ret != 0)
return -EFAULT;
//更新文件位置指针的值
*ppos += n;
printk("dev_fifo_read success!\n");
dev_fifo_info();
return n;
}
//写设备
static ssize_t dev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos)
{
int n;
int ret;
char *kbuf;
printk("write *ppos : %lld\n",*ppos);
//已经到达buffer尾部了
if(*ppos == sizeof(gcd->buffer))
return -1;
//请求大大小 > buffer剩余的字节数(有多少空间就写多少数据)
if(size > sizeof(gcd->buffer) - *ppos)
n = sizeof(gcd->buffer) - *ppos;
else
n = size;
//从上一次文件位置指针的位置开始写入数据
kbuf = gcd->buffer + *ppos;
//拷贝数据到内核空间
ret = copy_from_user(kbuf, ubuf, n);
if(ret != 0)
return -EFAULT;
//更新文件位置指针的值
*ppos += n;
//更新dev_fifo.len
gcd->len += n;
printk("dev_fifo_write success!\n");
dev_fifo_info();
return n;
}
//设备操作函数接口
static const struct file_operations fifo_operations = {
.owner = THIS_MODULE,
.open = dev_fifo_open,
.read = dev_fifo_read,
.write = dev_fifo_write,
};
//模块入口
int __init dev_fifo_init(void)
{
int ret;
struct device *device;
gcd = kzalloc(sizeof(struct mycdev), GFP_KERNEL);
if(!gcd){
return -ENOMEM;
}
//设备号 : 主设备号(12bit) | 次设备号(20bit)
dev_num = MKDEV(MAJOR_NUM, 0);
//静态注册设备号
ret = register_chrdev_region(dev_num,1,"dev_fifo");
if(ret < 0){
//静态注册失败,进行动态注册设备号
ret = alloc_chrdev_region(&dev_num,0,1,"dev_fifo");
if(ret < 0){
printk("Fail to register_chrdev_region\n");
goto err_register_chrdev_region;
}
}
//创建设备类
cls = class_create(THIS_MODULE, "dev_fifo");
if(IS_ERR(cls)){
ret = PTR_ERR(cls);
goto err_class_create;
}
//初始化字符设备
cdev_init(&gcd->cdev,&fifo_operations);
//添加设备到操作系统
ret = cdev_add(&gcd->cdev,dev_num,1);
if (ret < 0)
{
goto err_cdev_add;
}
//导出设备信息到用户空间(/sys/class/类名/设备名)
device = device_create(cls,NULL,dev_num,NULL,"dev_fifo%d",0);
if(IS_ERR(device)){
ret = PTR_ERR(device);
printk("Fail to device_create\n");
goto err_device_create;
}
printk("Register dev_fifo to system,ok!\n");
dev_fifo_info();
return 0;
err_device_create:
cdev_del(&gcd->cdev);
err_cdev_add:
class_destroy(cls);
err_class_create:
unregister_chrdev_region(dev_num, 1);
err_register_chrdev_region:
return ret;
}
void __exit dev_fifo_exit(void)
{
//删除sysfs文件系统中的设备
device_destroy(cls,dev_num );
//删除系统中的设备类
class_destroy(cls);
//从系统中删除添加的字符设备
cdev_del(&gcd->cdev);
//释放申请的设备号
unregister_chrdev_region(dev_num, 1);
dev_fifo_info();
return;
}
module_init(dev_fifo_init);
module_exit(dev_fifo_exit);
Makefile
ifeq ($(KERNELRELEASE),)
KERNEL_DIR ?=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
.PHONY:modules clean
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
else
obj-m := -DEXPORT_SYMTAB
obj-m := dev_fifo.o
endif
instatll.sh
sudo rmmod dev_fifo
sudo insmod dev_fifo.ko
sudo chmod 666 /dev/dev_fifo0
sudo dmesg -c
test.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
int fd ;
int n;
char buf[256];
fd = open("/dev/dev_fifo0",O_RDWR);
if(fd < 0){
perror("Fail to open");
return -1;
}
else
{
printf("open successful ,fd = %d\n",fd);
read(fd, buf, 256);
printf("读取内部值:%s\n",buf);
printf("输入一个值: ");
scanf("%s",buf);
n = write(fd,buf,strlen(buf));
read(fd, buf, strlen(buf));
printf("读取当前值:%s\n",buf);
printf("write %d bytes!\n",n);
if(n < 0){
perror("Fail to write");
return -1;
}
}
return 0;
}