Linux character device drivers and some simple Linux knowledge

Source: Internet
Author: User

first, the Linux system divides the device into 3 categories: Character devices, block devices, network equipment

1, character device : Refers to a byte can only one byte read and write devices, can not randomly read the device memory of a certain data, read data need to follow the data. The character device is a stream-oriented device, and the common character devices are mouse, keyboard, serial port, console and led device.
2, block device : Refers to the device can be read from any location of a certain length of data equipment. Block devices include hard disks, disks, USB sticks, and SD cards.

Each character device or block device corresponds to a device file in the/dev directory. The Linux User program uses the driver to manipulate character devices and block devices through device files (or device nodes).

This article is mainly about the character device driver, starting from the driver, involving the file operation, a total of four functions: including the opening of the file, read, write, delete. There are also registration and logoff of files.

Needless to say, the source code, take the code as an example to begin to explain:

1.MYDRIVER.C:

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

#if Config_modversions = = 1
#define Modversions
#include <linux/version.h>
#endif

#define DEVICE_NUM 0//randomly generate a device number

static int device_num = 0; Used to save the device number after a successful creation
static char buffer[1024] = "Mydriver"; Data buffers
static int open_nr = 0; Number of processes that opened the device for mutual exclusion of the kernel

function declaration
Inode;linux the administrative number of the file.
File:linux all documents. The file structure represents an open file, and each open file in the system has an associated struct file in the kernel space. It is created by the kernel when the file is opened and passed to any function that operates on the file. After all instances of the file have been closed, the kernel releases this data structure
static int Mydriver_open (struct inode *inode, struct file *filp);
static int mydriver_release (struct inode *inode, struct file* filp);
Static ssize_t mydriver_read (struct file *file, char __user *buf, size_t count, loff_t *f_pos); Loff-t:long Long Type
Static ssize_t mydriver_write (struct file *file, const char __user *buf, size_t count, loff_t *f_pos); __user indicates that the parameter is a pointer to a user space and cannot be accessed directly in the kernel code.
size_t: A basic unsigned integer for the C + + type
Filling file_operations Structure related entrance
static struct File_operations Mydriver_fops = {
. Read = Mydriver_read,
. write = Mydriver_write,
. open = Mydriver_open,
. Release = Mydriver_release,
};

Open function
static int Mydriver_open (struct inode *inode, struct file *filp)
{
PRINTK ("\nmain device is%d, and the slave device is%d\n", MAJOR (Inode->i_rdev), MINOR (Inode->i_rdev)); Pass in the master/slave device number
if (Open_nr = = 0) {
open_nr++;
Try_module_get (This_module); Try to open the module
return 0;
}
else {
PRINTK (kern_alert "Another process open the Char device.\n");//Process hangs
return-1;
}
}

Read function
Static ssize_t mydriver_read (struct file *file, char __user *buf, size_t count, loff_t *f_pos)
{
if (buf = = NULL) return 0;
if (Copy_to_user (buf, buffer, sizeof))//read buffer, the first parameter is to: the address of the user space, the second parameter is from, the address of the kernel space, the third parameter is the number of bytes to copy from the kernel space
{
return-1;
}
return sizeof (buffer);
}

Write a function to write the user's input string
Static ssize_t mydriver_write (struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
if (buf = = NULL) return 0;
if (copy_from_user (buffer, buf, sizeof (buffer))//write buffer
{
return-1;
}
return sizeof (buffer);
}

Releasing device functions
static int mydriver_release (struct inode *inode, struct file* filp)
{
open_nr--; Number of processes minus 1
PRINTK ("The device is released!\n");
Module_put (This_module); Release module
return 0;
}

Registering device functions
static int __init mydriver_init (void)
{
int result;

PRINTK (Kern_alert "Begin to init Char device!"); Registering your device
Register a character device with the system's character registration form
result = Register_chrdev (Device_num, "Mydriver", &mydriver_fops); The first parameter equals 0, which indicates that the system is dynamically assigned the main device number, and not 0, which indicates a static registration. The second parameter is named, and the third parameter is its address

if (Result < 0) {
PRINTK (kern_warning "Mydriver:register failure\n");
return-1;
}
else {
PRINTK ("Mydriver:register success!\n");
Device_num = result;
return 0;
}
}

Unregister device functions
static void __exit mydriver_exit (void)
{
PRINTK (Kern_alert "unloading...\n");
Unregister_chrdev (Device_num, "mydriver"); Logout device
PRINTK ("Unregister success!\n");
}

Module macro Definition
Module_init (Mydriver_init); Module load function
Module_exit (Mydriver_exit); Device unload function

Module_license ("GPL"); "GPL" indicates that this is any version of the GNU General Public License

Because the comment content is limited, some comments on the source code are posted later:

Inode;linux the administrative number of the file. (Static)
File:linux all documents. The file structure represents an open file, and each open file in the system has an associated struct file in the kernel space. It is created by the kernel when the file is opened and passed to any function that operates on the file. After all instances of the file have been closed, the kernel releases this data structure. (dynamic)
__user:the use of char __user *buf was typically found in the Linux kernel...denoting that this address is in the user Spac E. For example when writing to disk The kernel copies the contents of *BUF into a kernel space buffer before writing it OU T to disk. Similarly when a process requests a read Operation...the device driver at the behest of the kernel reads the desired disk Blocks into a kernel space buffer...and then copies them into the user space buffer pointed to by *BUF.
__user indicates that the parameter is a pointer to a user space and cannot be accessed directly in the kernel code. It is also convenient for other tools to check the code.
File-operations:
A pointer to a function that stores the functions provided by the kernel module to perform various operations. Each domain of the struct corresponds to the address of a function that drives the kernel module to process a requested transaction.
MAJOR (Inode->i_rdev), MINOR (Inode->i_rdev):
If the inode represents a device, the value of I_rdev is the device number. For better portability of code, get Inode major and minor should use the Imajor and Iminor functions
#include <linux/module.h>:
This header file must be loaded when the kernel driver is written, and the function is to load the module into the kernel dynamically.
#include <linux/version.h>:
When a device driver needs to support different versions of the kernel at the same time, during the compile phase, the kernel module needs to know the version of the kernel source currently in use, thereby using the appropriate kernel API
Try_module_get (&module), Module_put (&module):
Flexible Module Count Management interface
#include <linux/kernel.h>:
The kernel.h contains the kernel print function PRINTK function, etc.
#include <linux/uaccess.h>:
A function definition that contains kernel access to user process memory addresses such as Copy_to_user, Copy_from_user, and so on. (Copy_to_user () completes the user-space-to-kernel-space replication, and the function Copy_from_user () completes the kernel-space-to-user-space replication)
Copy_to_user (buf, buffer, sizeof (buffer)//
#include <linux/fs.h>:
Contains definitions of the associated struct for file operations, such as the famous struct file_operations

#include <linux/init.h>:
The initialization and logoff functions of the kernel modules are in this file

2. Makefile:

# if Kernelrelease is defined, we ' ve been invoked from the

# Kernel build system and can use the its language.

Ifeq ($ (kernelrelease),)

# Assume the source tree is where the running kernel was built

# should set Kerneldir in the environment if it ' s elsewhere

Kerneldir =/lib/modules/$ (Shell uname-r)/build

# The current directory was passed to Sub-makes as argument

PWD: = $ (shell pwd)

Modules

$ (make)-C $ (Kerneldir) m=$ (PWD) modules

Modules_install:

$ (make)-C $ (Kerneldir) m=$ (PWD) Modules_install

Clean

RM-RF *.o *~ core depend. *.cmd *.ko *.mod.c. tmp_versions

. Phony:modules Modules_install Clean

Else

# called from kernel build system:just declare what we modules are

Obj-m: = MYDRIVER.O

endif

3.

    1. TEST.c

#include <sys/types.h>

#include <sys/stat.h>

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#define MAX_SIZE 1024

int main (void)

{

int FD;

Char Buf[max_size];

Char Get[max_size];

Char devname[20], dir[49] = "/dev/";

System ("ls/dev/");

printf ("Please input the device ' s name of You wanna to use:");

Gets (Devname);

Strcat (dir, devname);

FD = open (dir, O_rdwr | O_nonblock);

if (FD! =-1)

{

Read (FD, buf, sizeof (BUF));

printf ("The device was inited with a string:%s\n", buf);

Test Write

printf ("Please input a string: \ n");

Gets (get);

Write (fd, get, sizeof (get));

Test Read

Read (FD, buf, sizeof (BUF));

System ("DMESG");

printf ("\nthe string in the device now is:%s\n", buf);

Close (FD);

return 0;

}

Else

{

printf ("Device open failed\n");

return-1;

}

}

The above source code can be used directly, the following is my basic knowledge of some humble opinion, if you have any ideas please be sure to point out, thank you big guy!

I. What is makefile
(1) kernelrelease is defined in the top-level makefile in the Linux kernel source code
(2) Shell PWD Gets the current working path
(3) Shell uname- R gets the version number of the current kernel
(4) because there is no target behind make, the make will be executed as the default target in the first target in makefile.
So modules becomes the target of Make
(5) First-c means to the directory where the kernel is stored (KERNELDIR) to perform its makefile, where the top-level makefile,m= option to save the kernel is the function of
When the user needs to build an external module based on a kernel, you need to add m=$ (PWD) to the Make Modules command, and the
program will automatically find the module source code in the dir directory you specify, compile it, and generate the Ko file.
(6) Obj-m means that the file is compiled as a module, but compiles GLOBALMEM.O without linking to the kernel
(7) Each makefile should write a rule that empties the target file (. O and Execute file), which is not only easy to recompile
, It's also good for keeping files clean--clean
(8) Make Modules_install is to copy the compiled module to the system directory (generally/lib/modules/),
Copy to the system directory for the purpose of easy to use, The load driver uses the Modprobe GLOBALMEM command, which looks for a module named Globalmem from the system directory

Two. What is modular programming? Why modular programming?
(1) Kernel modules are code that allows the operating system kernel to load and execute when needed, and can be uninstalled when it is not needed.
This is a good feature that extends the kernel functionality of the operating system without restarting the system and is a dynamically loaded technology.
(2) kernel module code runs in kernel space while the application is in user space. The operation of the application creates a new process, and the kernel module generally does not
。 Whenever an application executes a system call, the Linux execution mode switches from user space to kernel space.
A: The overall structure of the Linux kernel is very large and contains many components. How do we include the necessary parts in the kernel?
One way is to compile all the required functions into the Linux kernel.
This can lead to two problems, one is that the generated kernel will be large, and the second is that if we want to add or remove functionality from the existing kernel, we will have to recompile the kernel.
Is there a mechanism that the compiled kernel itself does not need to contain all the functionality, and when these functions need to be used,
The corresponding code can be loaded into the kernel dynamically?
Linux provides such a mechanism, known as a module, to achieve the above effects. Modules have the following characteristics.
1. The module itself is not compiled into the kernel image, which controls the size of the kernel.
2. Once the module is loaded, it is exactly the same as the rest of the kernel.

Three. How to understand the device number, what is the main device number, what is the secondary device number?

A character device or a block device has a master device number and a secondary device number. The main device number identifies the driver that is connected to the device file and is used to reflect the device type. The secondary device number is used by the driver to identify which device is operating and to distinguish between devices of the same type.
In the Linux kernel, the device number is described by dev_t, as defined in 2.6.28:
typedef u_long DEV_T;
In a 32-bit machine is 4 bytes, the high 12 bits represent the main device number, and the lower 12 bits represent the secondary device number.

Four. The entire drive from the compilation to the test program to test the whole process, need to master the various operational commands
1. In globalmen this directory, make a first, GLOBALMEM.C compiled into modules Globalmem.ko
2. Lsmod See if this Linux has globalmem module
3.insmod globalmem.ko load globalmem module
4.lsmod See if load succeeded
5.cat/proc/ Devices view the device that is generated when the driver is loaded (the proc directory is a virtual file system, and the
can provide interaction between Linux user space and kernel space, which only exists in memory and not the actual flash or hard disk space)
6.mknod/dev/ Globalmem C 200 0 Create the device node for the GLOBALMEM device, the main device number is 200, the secondary device number is 0
7.cd/dev enter the dev directory
8.ls See if there is a Globalmem device
9.echo in the dev directory Teacher, you are really handsome! ' >/dev/globalmem write a word to the GLOBALMEM device
10.cat/dev/globalmem See what's Inside the Globalmem device
11.gcc-o test.c test Use GCC to compile the test program
12../test run the test program

Five. Three important data structures (structs): File_operations, Innode, file, especially the File_operations
file structure:
struct file, defined in <linux/ Fs.h>. The file structure represents an open file. (It is not specific to the device driver;
Each open file in the system has an associated struct file in kernel space.
It is created by the kernel at open and passed to any function that operates on the file until the last close.
After all instances of the file have been closed, the kernel releases the data structure
. The pointer to struct file is often called FILP ("file pointer"), and there is no struct in the source code,
But it is often used in functions, such as
Int Globalmem_open (struct inode *inode, struct file *filp);
int globalmem_release (struct inode *inode, struct file *filp);
Static ssize_t globalmem_read (struct file *filp, char __user *buf, size_t size, loff_t *ppos);
Static ssize_t globalmem_write (struct file *filp, const char __user *buf, size_t size, loff_t *ppos);
Static loff_t globalmem_llseek (struct file *filp, loff_t offset, int orig);
Static long globalmem_ioctl (struct file *filp, unsigned int cmd, unsigned long arg);

Inode structure:
The INODE structure is used internally by the kernel to represent files. Therefore, it differs from the file structure that represents the open file descriptor.
There may be many file structures that represent multiple open descriptors for a single file, but they all point to a single inode structure.
The inode structure contains a large amount of information about the file. As a general rule, only 2 members of this structure are useful for writing driver code:
Dev_ti_rdev;
For a node that represents a device file, this member contains the actual device number.
Structcdev *i_cdev;
Structcdev is the internal structure of the kernel, representing the character device; This member contains a pointer to this structure when the node refers to a character device file.

File_operations structure:
The struct file_operations is defined in the header file Linux/fs.h to store pointers to functions that drive kernel modules to perform various operations on the device.
Each domain of the struct corresponds to the address of a function that drives the kernel module to process a requested transaction.
The following is a method of using the struct with the C99 syntax, and the struct member that does not show the declaration is initialized to null by GCC
static const struct File_operations Globalmem_fops = {
. Owner = This_module,
. Llseek = Globalmem_llseek,
. Read = Globalmem_read,
. write = Globalmem_write,
. Unlocked_ioctl = globalmem_ioctl,/* in the kernel version of 2.6.x, in the file operation structure,
Will have the IOCTL field, use Unlocked_ioctl in the higher version */
. open = Globalmem_open,
. Release = Globalmem_release,
};

Linux character device drivers and some simple Linux knowledge

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.