您的位置:首页 > 其它

字符设备驱动(三)

2017-04-29 08:41 127 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: