How to make an embedded Linux device driver (7)

7th: Interface for procfs

About this series

This is a HowTo article for developing embedded Linux device drivers as kernel modules. All the content of this article can be run on a Raspberry Pi.

-1st time: Build environment preparation and simple kernel module creation -Second time: System call handler and driver registration (static method) -Third time: System call handler and driver registration (dynamic method) -4th: Read / write implementation and memory story -5th time: Implementation of GPIO driver for Raspberry Pi -6th time: Implementation of ioctl --__ 7th time: Interface for procfs <--------------------- This time Contents __ -8th time: Interface for debugfs -9th time: Call a function of another kernel module / Use GPIO control function -10th time: Create a device driver using I2C -11th time: Add I2C device to device tree -12th time: Load the created device driver at startup

The entire source code that appears in this article

https://github.com/take-iwiw/DeviceDriverLesson/tree/master/07_01

Contents of this time

Until last time, we implemented ioctl in addition to the basic system calls (open, close, read, write). This almost covers the minimum required interfaces for a device driver (skip select / poll).

In fact, if you are developing to control a device (eg a sensor or actuator), you may want to change or get the parameters for debugging. It would be very convenient to be able to do this from the shell. This can be achieved by reading / writing to files in the proc file system (procfs). For example, suppose you create the following file.

You can check the sensor value by reading the value of / proc / mydevice_sensor0 (for example, cat), or you can control the motor by writing the value to / proc / mydevice_motor0 (for example, ʻecho). ). Basically, it is the same as read / write of the device driver that I have made so far. But until now it was read / write to the device file (/ dev / mydevice`). This time we will do it for the procfs file. You can make as many as you like. This is useful when you have just one device and many parameters you want to check.

Note (additional note)

In the comments, @rarul pointed out. It seems that procfs is only used to place process information, and debugfs is recommended for debugging purposes as described above. I will describe debugfs next time. It shouldn't be used for debugging, but I think it's a good way to create procfs, so I'll leave this article as it is.

Implementation of interface for procfs

To create an interface for procfs, simply register the file name and the function you want to call during read / write with the function proc_create where the driver is loaded (insmod). When registering, set the read / write handler function in the struct file_operations table. In fact, this is exactly the same procedure as registering a handler for a normal device driver. The only difference is the function used. Use the remove_proc_entry function to remove it.

myDeviceDriver.c


#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

/***Information about this device***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice"				/* /proc/Device name displayed on devices etc.*/
#define PROC_NAME "MyDevice_test"			/* /The name of procfs to create in proc*/

/*procfs test variables*/
static char proc_test_string[16];
static int  flag_read = 0;

/* /proc/MyDevice_Function called when accessing test*/
static int mydevice_proc_open(struct inode *inode, struct file *file)
{
	printk("mydevice_proc_open\n");
	flag_read = 0;
	return 0;
}

/* /proc/MyDevice_Function called when reading test*/
static ssize_t mydevice_proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	printk("mydevice_proc_read\n");

	if (flag_read == 0) {
		int len;
		len = sprintf(buf, "%s\n", proc_test_string);
		flag_read = 1;
		return len;
	} else {
		return 0;
	}
}

/* /proc/MyDevice_Function called when writing test*/
static ssize_t mydevice_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	printk("mydevice_proc_write\n");

	if (count > sizeof(proc_test_string)) count = sizeof(proc_test_string) - 1;
	if (copy_from_user(proc_test_string, buf, count)) {
		return -EFAULT;
	}
	proc_test_string[count] = '\0';
	return count;	
}

/*Handler table for procfs*/
static struct file_operations mydevice_proc_fops = {
	.owner = THIS_MODULE,
	.open  = mydevice_proc_open,
	.read  = mydevice_proc_read,
	.write = mydevice_proc_write,
};

/*Road(insmod)Functions sometimes called*/
static int mydevice_init(void)
{
	printk("mydevice_init\n");

	struct proc_dir_entry *entry;
	/*Create procfs*/
	entry = proc_create(PROC_NAME, S_IRUGO | S_IWUGO, NULL, &mydevice_proc_fops);
	if (entry == NULL) {
		printk(KERN_ERR "proc_create\n");
		return -ENOMEM;
	}

	return 0;
}

/*Unload(rmmod)Functions sometimes called*/
static void mydevice_exit(void)
{
	printk("mydevice_exit\n");

	/*Get rid of procfs*/
	remove_proc_entry(PROC_NAME, NULL);
}

module_init(mydevice_init);
module_exit(mydevice_exit);

Let's create a file called / proc / MyDevice_test. The processing when this file is read (mydevice_proc_read), the processing when writing (mydevice_proc_write), and the processing when opening (mydevice_proc_open) are implemented. The process at open is always called every time you read or write from the shell. I think it's okay without it. In fact, close is omitted.

mydevice_proc_write keeps the user-set string in an internal static variable (proc_test_string). Returns the contents held by mydevice_proc_read. I want you to call it only once per reading (cat), so I manage the flag and clear it at the time of open. I think there is a better way to do this.

When loading the module, use the proc_create function to create a / proc / MyDevice_test file. S_IRUGO | S_IWUGO is the same as 0666, giving all users RW access.

Try reading and writing parameters via procfs

Build and load with the following command.

make 
sudo insmod  MyDeviceModule.ko
ls /proc/MyDevice_test
/proc/MyDevice_test

echo "abc" > /proc/MyDevice_test
cat /proc/MyDevice_test
abc

After loading, / proc / MyDevice_test will be created. On the other hand, write the value with echo. After that, when you read it with cat, the value you wrote earlier is output.

Note

The content of this article is in line with the content of "Linux Device Driver Programming (Yutaka Hirata)". The book used create_proc_entry to register with the proc filesystem. However, it is now obsolete. This article uses proc_create instead.

Note 2: sysfs

As you pointed out in the comments, procfs essentially exchanges information about processes. As mentioned in the next article, debugfs exchanges information for debugging.

Apart from these, there is a mechanism for exchanging parameters with modules. You can check the module information and parameters as sysfs that can be placed under the / sys directory. It looks the same as procfs, but procfs is the old way, and as I wrote in this article, it's free to be added by developer developers. As a result, it has become chaotic. sysfs must be registered in the correct manner. And each file is organized and managed by directory.

There are various methods, but if you just want to show the parameters, you can do it with a helper macro called module_param (). This allows you to set parameters and read the values of parameters (variables) when loading a module. However, it seems that the parameters cannot be changed after loading the kernel.

I will actually use it. All you have to do is declare the variable and read module_param (). An example of using the variable param1 as a parameter is shown below.

static int param1 = 10;
module_param(param1, int, S_IRUGO);

You can check the value of param1 by reading / sys / module / MyDeviceModule / parameters / param1. You can also specify a value during insmod.

sudo insmod MyDeviceModule.ko
cat /sys/module/MyDeviceModule/parameters/param1
  10

sudo rmmod MyDeviceModule
sudo insmod MyDeviceModule.ko param1=20
cat /sys/module/MyDeviceModule/parameters/param1
  20

Recommended Posts

How to make an embedded Linux device driver (11)
How to make an embedded Linux device driver (8)
How to make an embedded Linux device driver (4)
How to make an embedded Linux device driver (7)
How to make an embedded Linux device driver (2)
How to make an embedded Linux device driver (3)
How to make an embedded Linux device driver (6)
How to make an embedded Linux device driver (5)
How to make an embedded Linux device driver (10)
How to make an embedded Linux device driver (9)
How to make an embedded Linux device driver (12) (Complete)
[Blender x Python] How to make an animation
How to make Linux compatible with Japanese keyboard
How to make Yubico Yubikey recognized in Manjaro Linux
How to make an interactive CLI tool in Golang
How to make an HTTPS server with Go / Gin
How to make a hacking lab-Kali Linux (2020.1) VirtualBox 64-bit Part 2-
How to make a hacking lab-Kali Linux (2020.1) VirtualBox 64-bit edition-
How to make a Python package (written for an intern)
How to create an ISO file (CD image) on Linux
How to make a Japanese-English translation
How to make a slack bot
How to install wkhtmltopdf (Amazon Linux2)
How to create an email user
How to install VMware-Tools on Linux
How to make a crawler --Advanced
How to make a recursive function
How to install MBDyn (Linux Ubuntu)
How to make a deadman's switch
[Blender] How to make a Blender plugin
[Blender] How to make Blender scripts multilingual
How to make a crawler --Basic
How to build MongoDB C driver
How to check Linux OS version
How to make a string into an array or an array into a string in Python
How to get the printer driver for Oki Mac into Linux
How to make Word Cloud characters monochromatic
How to make Selenium as light as possible
[Linux] How to subdivide files and folders
How to make an artificial intelligence LINE bot with Flask + LINE Messaging API
How to install aws-session-manager-plugin on Manajro Linux
[Python] How to make a class iterable
python3 How to install an external module
How to create an NVIDIA Docker environment
How to convert Python to an exe file
[Linux] How to use the echo command
How to use the Linux grep command
How to update php on Amazon linux 2
How to display emoji on Manjaro Linux
How to install packages on Alpine Linux
[Cocos2d-x] How to make Script Binding (Part 2)
How to install Anisble on Amazon Linux 2
How to operate Linux from the console
How to install Windows Subsystem For Linux
How to power off Linux with Ultra96-V2
How to update security on CentOS Linux 8
I want to make an automation program!
How to install php7.4 on Linux (Ubuntu)
How to make multi-boot USB (Windows 10 compatible)
How to make a Backtrader custom indicator
How to make a Pelican site map