[IMX6ULL driver development and learning] 06. APP and driver transfer data + automatically create device nodes (hello driver)

1. Transfer data between APP and driver

/*驱动从APP获取数据*/
unsigned long copy_from_user(void *to, const void *from, unsigned long n)

/*驱动传输数据到APP*/
unsigned long copy_to_user(void *to, const void *from, unsigned long n)

2. Use copy_to_user and copy_from_user to transfer data between APP and hello driver

test method:

./hello_test /dev/hello 1234abc    APP向驱动程序写入数据
./hello_test /dev/hello            APP从驱动程序读出刚才写入的数据

APP and driver transfer data principle:

  1. The APP calls the open function to open the device, and uses the system IO function write to write data to the device
  2. The system calls the write operation function of the driver (specified by the file_operations structure) , and passes the parameters passed in the APP to the write operation function
  3. The write operation function of the driver program calls the copy_from_user function to copy data from the user program to the driver program
  4. APP calls the system IO function read to read the drive data
  5. The system calls the read operation function of the driver (specified by the file_operations structure) , and copies the data in the driver to the APP

Let's represent it with a picture
insert image description here

3. The driver automatically creates device nodes

The first step: class_create function to create a device class

/*
 * @description		: 创建一个class类型的对象
 * @param - owner	: THIS_MODULE
 * @param - name	: 类名字
 * @return 			: 成功,返回struct class的指针;其他 失败
 */
struct class *class_create(struct module *owner, const char *name)

/*举例*/
static struct class *hello_class;
hello_class = class_create(THIS_MODULE, "hello_class");

Step 2: The device_create function creates a device node under /dev (there is no need to execute the mknod command on the development board side)

/*
 * @description		: 生成设备节点并导出到用户空间(在/dev下创建设备节点)
 * @param - class	: 指向该设备应注册到的struct class的指针(上一个class_create函数返回值)
 * @param - parent	: 指向此新设备的父struct设备的指针(如果有),没有填NULL
 * @param - devt	: 要添加的char设备的dev_t(设备号)
 * @param - drvdata	: 要添加到设备中以进行回调的数据(如果有),没有填NULL
 * @param - fmt		: 设备名称的字符串
 * @return 			: 成功,返回struct device指针;其他 失败
 */
struct device *device_create(struct class *class, struct device *parent, 
								dev_t devt, void *drvdata, const char *fmt, ...)
/*举例*/
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");

The above code
hello driver code:

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/capability.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <asm/therm.h>
#include <linux/string.h>


static int major;
static unsigned char buff[100];
static struct class *hello_class;

static int hello_open (struct inode *node, struct file *filp)
{
    
    
	printk("hello_open\n");
	printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);

	return 0;
}

static ssize_t hello_read (struct file *filp, char *buf, size_t size, loff_t *offset)
{
    
    
	size_t len = size > 100 ? 100 : size;
	printk("hello_read\n");
	copy_to_user(buf, buff, len);
	return len;
}

static ssize_t hello_write (struct file *filp, const char *buf, size_t size, loff_t *offset)
{
    
    
	size_t len = size > 100 ? 100 : size;
	memset(buff, 0 ,sizeof(buff));
	printk("hello_write\n");
	copy_from_user(buff, buf, len);
	return len;
}

static int hello_release (struct inode *node, struct file *filp)
{
    
    
	printk("hello_release\n");
	return 0;
}

/*1.定义 file_operations 结构体*/
static const struct file_operations hello_drv = {
    
    
    .owner 		= THIS_MODULE,
	.read		= hello_read,
	.write		= hello_write,
	.open		= hello_open,
	.release    = hello_release,
};

/*3.入口函数*/
static int hello_init(void)
{
    
    
	//返回主设备号
	major = register_chrdev(0,"hello_drv",&hello_drv);
	
	printk("hello_open\n");
	printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);

	/*在内核中创建设备*/
	hello_class = class_create(THIS_MODULE, "hello_class");
	if (IS_ERR(hello_class)) {
    
    
		printk("hello class create failed!\n");
	}

	/*在设备类下面创建设备*/
	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");
	if (IS_ERR(dev)) {
    
    
		printk("hello device_create  failed!\n");
	}
	return 0;
}

/*4.退出函数*/
static int hello_exit(void)
{
    
    
	//卸载设备
	unregister_chrdev(major,"hello_drv");

	//销毁设备
	device_destroy(hello_class, MKDEV(major, 0));
	//删除设备类
	class_destroy(hello_class);

	//删除注册的设备号
	// unregister_chrdev_region(major, 1);

	return 0;
}	

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

hello application code:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
    
    
    int len;
    char read_buf[10];

    if(argc < 2){
    
    
        printf("please input  at least 2 args\n");
        printf("%s <dev> [string]\n", argv[0]);
        return -1;
    }

    /*open*/
    int fd;
    fd = open(argv[1], O_RDWR);
    if(fd < 0){
    
    
        printf("open failed\n");
        return -2;
    }

    /*read*/
    if(argc == 2){
    
      
        read(fd, read_buf, 10);    //调用read函数,只为了触发系统调用hello驱动的read函数
        printf("read operation : %s\n", read_buf);
    }

    /*write*/
    if(argc == 3){
    
    
        len = write(fd, argv[2], strlen(argv[2]));   //调用write函数,只为了触发系统调用hello驱动的write函数
        printf("write length = %d \n", len);
    }

    close(fd);

    return 0;
}

Test Results:

[root@100ask:/mnt]# insmod hello_drv.ko  (向内核注册hello驱动)
[root@100ask:/mnt]# cat /proc/devices    (查看驱动设备号)
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 29 fb
 81 video4linux
 89 i2c
 90 mtd
108 ppp
116 alsa
128 ptm
136 pts
166 ttyACM
180 usb
188 ttyUSB
189 usb_device
207 ttymxc
216 rfcomm
226 drm
238 hello_drv
[root@100ask:/mnt]# ls -l /dev/hello       (查看/dev下是否有hello设备节点)
crw------- 1 root root 238, 0 Jan  1 01:37 /dev/hello

#测试hello驱动读写操作
[root@100ask:/mnt]# ./hello_test /dev/hello 1234abc    (向驱动写)
write length = 7 
[root@100ask:/mnt]# ./hello_test /dev/hello            (读驱动)
read operation : 1234abc

Guess you like

Origin blog.csdn.net/HuangChen666/article/details/131134366