file_operations使用示例(实现read/write/ioctl)

内核态ko完成用户在内核态想完成的任务,而内核态ko加载后,通过用户态open等系统调用间接执行内核态的任务,相关执行任务需要的配置参数,结构体等,通过系统调用传入到内核态,完成任务后,将任务数据写回到用户态,以便下一步操作;

文件目录:

Makefile

obj-m:=test_tools.o
KDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)

default:
    $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
    rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *symvers *Module.markers

test_tools.ko(编译命令:make)

/***************************************************************************//**
*  \file       test_tools.c
*
*  \details    Simple Linux device driver (File Operations)
*
*  \author     EmbeTronicX
*
* *******************************************************************************/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

dev_t dev = 0;
static struct class *dev_class;
static struct cdev test_cdev;

struct task_info {
	char alg[50];
	int res;
};

/*
** Function Prototypes
*/
static int      __init test_tools_init(void);
static void     __exit test_tools_exit(void);
static int      test_open(struct inode *inode, struct file *file);
static int      test_release(struct inode *inode, struct file *file);
static ssize_t  test_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
static ssize_t  test_write(struct file *filp, const char *buf, size_t len, loff_t * off);
static ssize_t  test_unlocked_ioctl(struct file *filp, unsigned int cmd, struct task_info* arg);
static int do_A(struct task_info*);
static int do_B(struct task_info*);

typedef int (*alg_do) (struct task_info*);

struct alg_handle {
	char alg_name[50];
	alg_do alg_func;
};

struct alg_handle alg_handle_tables[] = {
	{"AAA", do_A},
	{"BBB", do_B},
};

static struct file_operations fops =
{
    .owner      = THIS_MODULE,
    .read       = test_read,
    .write      = test_write,
    .open       = test_open,
    .release    = test_release,
	.unlocked_ioctl = test_unlocked_ioctl,
};
/*
** This fuction will be called when we open the Device file
*/
static int test_open(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "Driver Open Function Called...!!!\n");
        return 0;
}
/*
** This fuction will be called when we close the Device file
*/
static int test_release(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "Driver Release Function Called...!!!\n");
        return 0;
}
/*
** This fuction will be called when we read the Device file
*/
static ssize_t test_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
	char *a = NULL;
	int i = 0;
	
	printk(KERN_INFO "Driver Read Function Called...!!!\n");
	a = kmalloc(10,GFP_KERNEL);
	for(;i<9;i++) {
		a[i] = i+'a';
	}
	copy_to_user(buf,a,9);
	return 0;
}
/*
** This fuction will be called when we write the Device file
*/
static ssize_t test_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
	char *a=NULL;
	int i = 0;
	
	printk(KERN_INFO "Driver Write Function Called...!!!\n");
	
	a = kmalloc(len,GFP_KERNEL);
	copy_from_user(a,buf,len);

	for(;i<9;i++) {
		printk("%d ", a[i]);
	}
	printk("\n");
	return len;
}
/*
** This fuction will be called when we ioctl the Device file
*/
static ssize_t test_unlocked_ioctl(struct file *filp, unsigned int cmd, struct task_info* arg)
{
	struct task_info *tf;
	int num_cmds = 0;
	int index;
	alg_do fn;
	int ret = 0;
	
	tf = kzalloc(sizeof(struct task_info), GFP_KERNEL);
	if (!tf) {
		printk("tf alloc failed.\n");
		return -ENOMEM;
	}

	if (copy_from_user(tf, arg, sizeof(*tf))) {
		printk("copy_from_user failed.\n");
		return -EFAULT;
	}
	num_cmds = ARRAY_SIZE(alg_handle_tables);
	for (index = 0; index < num_cmds; index ++) {
		if (!strcmp(tf->alg, alg_handle_tables[index].alg_name)) {
			fn = alg_handle_tables[index].alg_func;
			ret = fn(tf);
			printk("ret:%d res:%d\n", ret, tf->res);
			break;
		}
	}

	ret = copy_to_user(arg, tf, sizeof(struct task_info));
	printk("copy_to_user ret:%d.\n", ret);

	return ret;
}

static int do_A(struct task_info *tf) {
	tf->res = 10;
	
	printk("do somethin in algA\n");

	return 0;
}
static int do_B(struct task_info *tf) {
	tf->res = 0;
	
	printk("do somethin in algB\n");

	return 0;
}

/*
** Module Init function
*/
static int __init test_tools_init(void)
{
        /*Allocating Major number*/
        if((alloc_chrdev_region(&dev, 0, 1, "test_tools")) <0){
                printk(KERN_INFO "Cannot allocate major number\n");
                return -1;
        }
        printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
        /*Creating cdev structure*/
        cdev_init(&test_cdev,&fops);
        /*Adding character device to the system*/
        if((cdev_add(&test_cdev,dev,1)) < 0){
            printk(KERN_INFO "Cannot add the device to the system\n");
            goto r_class;
        }
        /*Creating struct class*/
        if((dev_class = class_create(THIS_MODULE,"test_class")) == NULL){
            printk(KERN_INFO "Cannot create the struct class\n");
            goto r_class;
        }
        /*Creating device*/
        if((device_create(dev_class,NULL,dev,NULL,"test_tools")) == NULL){
            printk(KERN_INFO "Cannot create the Device 1\n");
            goto r_device;
        }
        printk(KERN_INFO "Device Driver Insert...Done!!!\n");
        return 0;
r_device:
        class_destroy(dev_class);
r_class:
        unregister_chrdev_region(dev,1);
        return -1;
}
/*
** Module exit function
*/
static void __exit test_tools_exit(void)
{
        device_destroy(dev_class,dev);
        class_destroy(dev_class);
        cdev_del(&test_cdev);
        unregister_chrdev_region(dev, 1);
        printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(test_tools_init);
module_exit(test_tools_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lanzhihui@huawei.com");
MODULE_DESCRIPTION("test_tools");
MODULE_VERSION("1.0");

main.c(编译命令:gcc main.c -o main)

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define CHR_DEV_NAME "/dev/test_tools"

struct task_info {
	char alg[50];
	int res;
};

int main()
{
    int ret;
    char buf[32];
    int fd = open(CHR_DEV_NAME, O_RDWR);
    if(fd < 0)
    {
        printf("open file %s failed!\n", CHR_DEV_NAME);
        return -1;
    }
	
	//read
    read(fd, buf, 32);
	int i=0;
	for(;i<10;i++) {
		printf("%d ", buf[i]);
	}
	printf("\n");

	//write
	ret = write(fd,buf,10);
	printf("ret:%d\n", ret);
	
	//ioctl
	struct task_info tf = {
		.alg = "AAA",
		.res = -1,
	};
	ret = ioctl(fd, 0, &tf);
	printf("ret:%d res:%d\n", ret, tf.res);
	
    close(fd);
    return 0;
}

 

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我已经理解了您的问题。以下是一个简单的字符设备驱动程序的示例代码,包括设备打开、读、写、I/O控制和关闭等基本操作。请注意,这只是一个示例,您需要根据自己的需求进行适当的修改。 chardev.c: #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #define DEVICE_NAME "chardev" //设备名称 #define BUF_LEN 80 //缓冲区大小 static int major; //主设备号 static char msg[BUF_LEN]; //缓冲区 static char *msg_ptr; //缓冲区指针 //打开设备 static int device_open(struct inode *inode, struct file *file) { static int counter = 0; if (counter) return -EBUSY; counter++; msg_ptr = msg; try_module_get(THIS_MODULE); return 0; } //释放设备 static int device_release(struct inode *inode, struct file *file) { counter--; module_put(THIS_MODULE); return 0; } //读设备 static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset) { int bytes_read = 0; if (*msg_ptr == 0) return 0; while (length && *msg_ptr) { put_user(*(msg_ptr++), buffer++); length--; bytes_read++; } return bytes_read; } //写设备 static ssize_t device_write(struct file *filp, const char *buff, size_t length, loff_t *off) { int i; for (i = 0; i < length && i < BUF_LEN; i++) get_user(msg[i], buff + i); msg_ptr = msg; return i; } //I/O控制 static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { case 1: printk(KERN_INFO "IOCTL command 1\n"); break; case 2: printk(KERN_INFO "IOCTL command 2\n"); break; default: return -EINVAL; } return 0; } //设备文件操作结构体 static struct file_operations fops = { .owner = THIS_MODULE, .read = device_read, .write = device_write, .unlocked_ioctl = device_ioctl, .open = device_open, .release = device_release }; //初始化字符设备 int init_chardev_module(void) { major = register_chrdev(0, DEVICE_NAME, &fops); if (major < 0) { printk(KERN_ALERT "Registering char device failed with %d\n", major); return major; } printk(KERN_INFO "Chardev module loaded with major number %d\n", major); return 0; } //关闭字符设备 void exit_chardev_module(void) { unregister_chrdev(major, DEVICE_NAME); printk(KERN_INFO "Chardev module unloaded\n"); } module_init(init_chardev_module); module_exit(exit_chardev_module); Makefile: obj-m := chardev.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 在使用前,请确定您的系统已经安装了适当的编译工具链和内核头文件。可以使用以下命令来编译和加载模块: make sudo insmod chardev.ko 您可以使用以下命令来测试设备驱动程序: echo "Hello, world!" > /dev/chardev cat /dev/chardev sudo ioctl /dev/chardev 1 希望这能帮助您了解如何编写一个简单的字符设备驱动程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值