Getting Started with Linux drivers (a) character device driver foundation

copy from :https://blog.csdn.net/weixin_42462202/article/details/99887783

Linux driver entry (a) character device driver basis of
article directories
Linux driver entry (a) device driver base characters
a drive Introduction
II character device driver concept
Third, the registered character device
four or compile the module
five load modules
Sixth, create a device node
seven test
a drive Introduction
Linux driver into character device driver, a block device drivers, network device driver

Character device driver

A devices must character in serial order of access, such as led, a touch screen, a mouse, etc.

Call accessible through open, close, read, write and other systems

Block device driver

Block access device may be in any order, in units of blocks to operate, such as a hard disk, and so the EMMC

There are great differences drive the design block and character devices, but can also be accessed via open, close, read, write and other system calls, but these are generally using the file system to manage

Network device driver

Network device is designed for receiving and sending data packets, in the file system, and there is no corresponding device node, accessed through socket interface

This paper mainly on the character device

Second, the concept of character device drivers
under Linux everything is a file, such as a led device performance in the file system as a device node / dev / led, application layer through open, read, write and other system calls can be control led

For example, want led light, open the device file write 1

int fd;
int val = 1;

Open = FD ( "/ dev / led", XXX);
Write (FD, & Val, the sizeof (Val));

such that it can be led lit

Now think about a question, why so that you can make the led light up?

To get led lights, you must operate the hardware, operating hardware that is part of the work led drive completed

The easiest way is, for the application layer led to the open operation, then the corresponding one of led_open led driver. Led to the application layer for write operations, the operation led to a corresponding one of the driver led_write then led_write operation to control the hardware, then control led

Then on led device nodes open, write system call, how to call to the driver's led_open, led_write it?

When the application layer calls open, read, write and other operations, will cause an exception, causing the system to become kernel mode, and then to execute the corresponding system call sys_open, sys_read, sys_write etc.

Will go to find the appropriate driver sys_open, sys_read, sys_write, and then calls the driver's open, read, write hardware to operate

As shown below

 

Sys_open then call in a virtual file system, how did you find led driver instead of the other drivers do?

First, tell us about the device number

Each device has a device number, 32-bit, where 12 indicates a high number of master device, 20 represents a lower minor number

Use ls / dev / led -l viewing device, the following information can be obtained

the root-RW. 1 ---- CRW 0 10, 131. 1 12:00 Jan / dev / LED
. 1
wherein 10, 131 denotes a device number, device number 10 indicates the master, minor number 131 denotes

To facilitate understanding, we can consider that there is a character in the kernel array device to the master device index number, the device itself is a character array element, there is a character device file set of operations, a series of operations set function (e.g. led_open, led_write, led_read)

sys_open system calls to find a good array of equipment by the master file, a set of calls to the driver's led_open led by a character device file operations and other functions

 

Character device driver is to improve the fops (file operation set), and then specify the device number, up to the kernel character device

Third, the character device registered
first look at the character device object

struct file_operations {
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
int (*open) (struct inode *, struct file *);
...
};

struct the cdev {
struct the kobject Kobj;
struct Module1 * owner; / * View Module * /
const struct the file_operations * OPS; / * file operations set * /
struct the list_head List;
the dev_t dev; / * device number * /
unsigned int COUNT;
};

wherein the dev_t members define a device number, 32-bit, high resolution master device 12, 20 for the lower sub-device number

Kernel following two major and minor number macro obtain

MAJOR (dev_t dev) // major number
MINOR (dev_t dev) // minor number

using the following macro acquisition device number

MKDEV (int major, int minor)

each device has its own character corresponding device number range, here's how to apply the device number

No application equipment

Dynamic allocation

This function specifies the number of times a device number and device number can be dynamically assigned major number

/ *
* Dev: application to the device number returned
* baseminor: starting minor number
* count: the number of the application device number
* /
int alloc_chrdev_region (the dev_t * dev, unsigned baseminor, unsigned COUNT,
const char * name)

static allocation

This function must be the number of major and minor number and device number

/ *
* From: Actually device number
* count: the number of device number
* /
int register_chrdev_region (from the dev_t, unsigned COUNT, const char * name)

after the completion of the application device number, you can use this device number to register a character device

Register character device

Function and character-related equipment

void cdev_init (struct the cdev *, struct the file_operations *);
struct the cdev * cdev_alloc (void);
void cdev_put (struct the cdev * P);
int cdev_add (struct the cdev *, the dev_t, unsigned);
void cdev_del (struct the cdev *);

cdev_init : FOPS and equipment associated with the character used, which is a file operation file_operations set, there is provided a series of manipulation functions (e.g. open, read, write)

cdev_alloc: assign a character device object

cdev_add: Registration character device

cdev_del: cancellation of a character device

A step of registering character device

struct cdev * cdev_alloc (void); // assign character device

void cdev_init (struct cdev *, struct file_operations *); // Bind a fops

int cdev_add (struct cdev *, dev_t , unsigned); // character and to apply to the device the device number registered into the kernel

following is a simple character device driver

mydev.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>

static dev_t dev_id;
static struct cdev *mydev;

ssize_t mydev_read(struct file *file, char __user *data, size_t size, loff_t * loff)
{
printk("mydev_read\n");

return 0;
}

ssize_t mydev_write(struct file *file, const char __user *data, size_t size, loff_t *loff)
{
printk("mydev_write\n");

return 0;
}

int mydev_open(struct inode *inode, struct file *file)
{
printk("mydev_open\n");

return 0;
}

/* 文件操作集合 */
static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
.read = mydev_read,
.open = mydev_open,
.write = mydev_write,
};

int mydev_init the __init static (void)
{
/ * Application device number * /
alloc_chrdev_region (the dev_id &,. 1,. 1, "that mydev");

/ * Assign character device * /
that mydev cdev_alloc = ();

/ * Set character device * /
cdev_init (that mydev, & mydev_fops);

/ * Register character device * /
cdev_add (mydev, dev_id, 1);

/ * Print request to the major and minor number * /
the printk ( "Major: D%; Minor:% D \ n-", MAJOR (the dev_id), MINOR (the dev_id));

return 0;
}

static __exit void mydev_exit(void)
{
cdev_del(mydev);
kfree(mydev);
unregister_chrdev_region(dev_id, 1);
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE ( "GPL");

Fourth, the compiler module
written in after the driver, how do we compile the driver, there are two ways, one is compiled into the kernel and drivers together, one is written into the driver alone module

The second presentation here

The drivers are compiled as modules need to write Makefile

Makefile as follows

KERN_DIR = / work / linux / kernel /

all:
make -C $(KERN_DIR) M=`pwd` modules

clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order

obj-m + = mydev.o
where KERN_DIR = / work / linux / kernel / kernel tree represents, according to the need to modify the path where your kernel

obj-m + = mydev.o show file to be compiled mydev.c

make -C $ (KERN_DIR) M = pwd modules show a jump to the kernel source tree, compiling module

The Makefile and mydev.c put together, perform make, mydev.ko drive module can be obtained

Fifth, the load module
using the driving module can be loaded insmod xxx.ko

Use lsmod can view the currently loaded module

You can uninstall the driver using rmmod xxx loaded modules

The above mydev.ko copied to generate experimental platform, execute insmod mydev.ko

Once loaded module, the kernel will run module_init (mydev_init) specified module entry, mydev_init function, we apply the device number, registered the character device, and print the major and minor device numbers

You can see the print information

Major: 250; Minor: 1
1
represents the major number 250, minor number 1 (what you see may vary)

At this point the module has been loaded, we can see through the cat / proc / devices that we have registered the character device

But did not generate device nodes, we are still unable to operate the equipment in the / dev directory, here's how to create a device node

Six, create device nodes
create a device node is created automatically and manually created is divided into the following were introduced

Manually create

In the top drivers to print out major: 250; minor: 1, we can use this information to create device nodes

By the following command to create a device node

mknod device name device type (character: c, block: b) major number from the device number

performed

mknod / dev / mydev c 250 1

run after the generation of the device node / dev / mydev

Created automatically

It is automatically created using mdev udev mechanism or mechanisms, when the device driver creates related information / sys, udev mdev or device nodes are created according to the information

The following describes how to create device nodes

static struct class *mydev_class;

mydev_class = class_create (THIS_MODULE, "mydev "); // Create a class
device_create (mydev_class, NULL, dev_id, NULL, "mydev"); // Create a node device according to the device number

destruction device node

device_destroy (mydev_class, dev_id); // device node is destroyed
class_destroy (mydev_class); // class destruction

driving modified

mydev.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>

static dev_t dev_id;
static struct cdev *mydev;
static struct class *mydev_class;

ssize_t mydev_read(struct file *file, char __user *data, size_t size, loff_t * loff)
{
printk("mydev_read\n");

return 0;
}

ssize_t mydev_write(struct file *file, const char __user *data, size_t size, loff_t *loff)
{
printk("mydev_write\n");

return 0;
}

int mydev_open(struct inode *inode, struct file *file)
{
printk("mydev_open\n");

return 0;
}

static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
.read = mydev_read,
.open = mydev_open,
.write = mydev_write,
};

int mydev_init the __init static (void)
{
/ * Application device number * /
alloc_chrdev_region (the dev_id &,. 1,. 1, "that mydev");

/ * Assign character device * /
that mydev cdev_alloc = ();

/ * Set character device * /
cdev_init (that mydev, & mydev_fops);

/ * Register character device * /
cdev_add (mydev, dev_id, 1);

/ * Print request to the major and minor number * /
the printk ( "Major: D%; Minor:% D \ n-", MAJOR (the dev_id), MINOR (the dev_id));

mydev_class = class_create(THIS_MODULE, "mydev");
device_create(mydev_class, NULL, dev_id, NULL, "mydev");

return 0;
}

static __exit void mydev_exit(void)
{
device_destroy(mydev_class, dev_id);
class_destroy(mydev_class);

cdev_del(mydev);
kfree(mydev);
unregister_chrdev_region(dev_id, 1);
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE ( "GPL");

recompile module loaded

View / sys / dev / char directory, you will find some more information 250: 1

At this point see ls / dev / mydev, you will find the / dev directory already have a mydev

Seven test
after each driver is finished, you need to write application testing

Here is our test program

mydev_test.c

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

int main(int argc, char* argv[])
{
int val = 1;

int fd = open("/dev/mydev", O_RDWR);

write(fd, &val, sizeof(val));

read(fd, &val, sizeof(val));

0 return;
}

compiled

arm-linux-gcc mydev_test.c

load module

insmod mydev.ko

execute the test program

./a.out

can see the console print

[2639.832633] mydev_open
[2639.833528] mydev_write
[2639.836014] mydev_read

demonstrated normal driver

This article to end here
----------------
Disclaimer: This article is CSDN blogger original article "JT students", following the CC 4.0 BY-SA copyright agreement, reprint Please include links to the original source and this statement.
Original link: https: //blog.csdn.net/weixin_42462202/article/details/99887783

Guess you like

Origin www.cnblogs.com/Oude/p/12455626.html