Development Notes for embedded linux Driver

1, The first driver under Linux

The drive is divided into four parts:
Header file
Inlet and outlet of drive module
Declaration information
Function realization
The first step includes the header file
1 #include<linux/init. h> Header file containing macro definition
2 #include<linux/module. h> Header file containing initialization load module

The second step is to drive the inlet and outlet of the module
module_init();
module_exit();
The third step is to declare that the module has an open source license
MODULE_LICENSE("GPL");

Step 4 realization of function

Print printk("hello world") when the kernel is loaded;

static init hello_init(void)
{
    printk("hello world");
    return 0;
}

Print printk("bye bye") when the kernel is unloaded;

static init hello_exit(void)
{
    printk("bye bye");
    return 0;
}
#include<linux/init.h>
#include<linux/module.h>


static init hello_init(void)
{
    printk("hello world");
    return 0;
}

static init hello_exit(void)
{
    printk("bye bye");
    return 0;
}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE("GPL");

2, Explanation of driver module compilation under Linux

The first method:
Compile the driver into modules, and then use commands to load the driver into the kernel

The second method:
Compile the driver directly into the kernel.

Compile into modules

The first step is to write a makefile

obj-m +=helloworld.o

KDIR:=/home/q123/Desktop/linux/elinux

PWD?=$(shell pwd)

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

Step 2: compile the driver
Issues needing attention before compiling driver:
1. The kernel source code should be compiled first
2. The kernel source code used to compile the driver module must be the same as the running image on the development board.
3. Let's see if the environment of ubuntu is arm.
Setting environment variables
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
Congratulations on the compilation!After successful compilation ko file is our compiled driver file.

Load driver module

insmod helloworld.ko

Unloading the driver module

rmmod helloworld has no suffix name of ko

3, make menuconfig graphical configuration interface

1. Enter the kernel source code path, and then enter make menuconfig to open this interface.
2. make menuconfig graphical interface operation
1) Search function
Enter "/" to pop up the search interface, and then enter the content to search.
2) Configure driver status
(1) Compile the driver into modules, represented by M.
(2) Compile the driver into the kernel, represented by *.
(3) Do not compile
3. Quit
Exit is divided into save exit and do not save exit

4. make menuconfig related files
Makefile
There are Compilation Rules. The practice of cooking.
Kconfig
The menu for the waiter is the same as the menu for the restaurant
.config
Configuration options generated after configuring the kernel. It's equivalent to a finished order.

5. Under which directory will make menuconfig read the Kconfig file
Kconfig in arch/$ARCH / directory
/There are many configuration files under arch / arm / configurations # which are equivalent to the special dishes of rice.

6. Why copy it config instead of copying to other files?
Certainly not, because the kernel reads from the root directory of the Linux kernel by default config as the default configuration option.

7. Copied What if config does not fully meet the requirements?
You need to use make menuconfig to order and call up the menu. After configuration, update to config

8. How to establish a relationship with Makefile files?
When make menuconfig is saved and exited, Linux will save all configuration options in the form of macro definition in Autoconf under include/generated H medium.

4, Three device drivers of Linux

Character device: the transmission process of IO is based on characters without buffer. For example, IIC and SPI are character devices.

Block device: the transmission process of IO is based on blocks. Storage related devices are all block devices, such as tf cards

Network device: different from the previous two, it is accessed by socket.

1. Miscellaneous equipment drive
Miscellaneous device driver is a kind of character device, which can automatically generate device nodes.

There are many miscellaneous equipment in the system.
cat /proc/misc command.

2. Is there any difference between miscellaneous equipment and character equipment except that it is simpler than character equipment code?
The primary device numbers of miscellaneous devices are the same, which are all 10. The secondary device numbers are different. If the primary device numbers are the same, the resources of the kernel can be saved.

3. What are the primary and secondary equipment numbers?
The primary device number includes the secondary device number. The primary device number is unique in linux, and the secondary device number is not necessarily unique.

Equipment number is a way for computer to identify equipment. If the main equipment is the same, it is regarded as the same type of equipment.
The main equipment number can be made into the area code of the telephone number. For example, Anhui is 0551.
The secondary equipment number can be compared to a telephone number.

The main device number can be viewed through the command cat /proc/devices.

4. Miscellaneous device driver description
Defined in the kernel source code path: VI include / Linux / miscdevice h

  struct miscdevice  {
      int minor;//Secondary equipment No
     const char *name;//Name of the device node
      const struct file_operations *fops;//File operation set
      struct list_head list;
      struct device *parent;
      struct device *this_device;
      const struct attribute_group **groups;
      const char *nodename;
      umode_t mode;
  };
  

file_operations *fops;// File operation set
In VI include / Linux / Fs H down.
A structure member must correspond to a call.

Register miscellaneous equipment
extern int misc_register(struct miscdevice *misc);
Write off miscellaneous equipment
extern int misc_deregister(struct miscdevice *misc);

5 process of registering miscellaneous equipment.
(1) Fill in the members of the structure miscdevice.
(2) Fill file_operation is the structure.
(3) Register miscellaneous equipment and generate equipment nodes.
Self assigned equipment number:

5, Practice Course

Objective: register a miscellaneous equipment according to the registration process of miscellaneous equipment and generate equipment nodes.
Create misc Source file of C

#include<linux/init.h>
#include<linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>

struct file_operations  misc_fops =
{
    .owner = THIS_MODULE
};

struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "hello_misc",
    .fops = &misc_fops
};

static int misc_init(void)
{
    int ret;
    ret = misc_register(&misc_dev);//register
    if (ret<0)
    {
        printk("misc_register is error\n");
        return -1;
    }
    printk("misc_register is successful\n");
    return 0;
}
static int misc_exit(void)
{
    misc_deregister(&misc_dev);//uninstall
    printk("bye bye");
    return 0;
}
module_init(misc_init);

module_exit(misc_exit);

MODULE_LICENSE("GPL");

After making, mount the ko file to nfs and use insmod to mount the device driver.

Data transmission between application layer and kernel layer

Linux everything is a file!!!
The corresponding operations of the file include opening, closing, reading and writing.
The corresponding operations of the device node include opening, closing, reading and writing.
1. What happens if you use system IO to open, close, read and write device nodes in the application layer?

When the read device node is in the application layer, the read function in the driver will be triggered.
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

When the device node is written in the application layer, the write function in the driver will be triggered.
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

When a poll/select device node is in the application layer, the poll function in the driver will be triggered.
unsigned int (*poll) (struct file *, struct poll_table_struct *);

When the ioctl device node is in the application layer, the ioctl function in the driver will be triggered.
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

When the device node is opened in the application layer, the open function in the driver will be triggered.
int (*open) (struct inode *, struct file *);

When the device node is closed in the application layer, the close function in the driver will be triggered.
int (*release) (struct inode *, struct file *);

open, release, read and write driver code test

In file_ Add the following code to the operation structure and make it.

#include<linux/init.h>
#include<linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>

int misc_open(struct inode *inode,struct file *file)
{
    printk("hello misc_open\n"); 
    return 0;
}
int misc_close(struct inode *inode,struct file *file)
{
    printk("bye bye\n"); 
    return 0;
}
int misc_read(struct inode *inode,struct file *file)
{
     printk("read\n");   
    return 0;
}

int misc_write(struct inode *inode,struct file *file)
{
     printk("write\n");   
    return 0;
}
struct file_operations  misc_fops =
{
    .owner = THIS_MODULE,
    .open = misc_open,
    .release = misc_close,
    .read = misc_read,
    .write = misc_write
};

struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "hello_misc",
    .fops = &misc_fops
};

static int misc_init(void)
{
    int ret;
    ret = misc_register(&misc_dev);//register
    if (ret<0)
    {
        printk("misc_register is error\n");
        return -1;
    }
    printk("misc_register is successful\n");
    return 0;
}

static int misc_exit(void)
{
    misc_deregister(&misc_dev);//uninstall
    printk("bye bye");
    return 0;
}

module_init(misc_init);

module_exit(misc_exit);

MODULE_LICENSE("GPL");

open, close, read and write application code test

The application layer code is as follows

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

int main(int argc, char **argv)
{
    int fd;

    char buf[64];


    fd = open("dev/hello_misc",O_RDWR);
    if (fd < 0) 
    {
        printf("open error\n");
        return fd;
    }

    read(fd, buf, sizeof(buf));

    write(fd, buf, sizeof(buf));

    close(fd);
    
    return 0;
}

Compiling application layer code using cross compiler

arm-linux-gnueabihf-gcc app.c -o app -static

Copy to nfs directory and call/ app calls the driver code ~ ~!!!

6, Summary

1. Call relation
Upper application device node and lower driver

The device node is the bridge connecting the upper application and the bottom application.

2. Add file_ There is no read in operations. What happens to the read device node in the application layer?

Nothing will happen and no error will be reported.

3. The application layer and kernel layer cannot transmit data directly.

Open include / ASM generic
copy_ from_ The user layer transfers data to the kernel layer.

static inline long copy_from_user(void *to,const void __user * from, unsigned long n)
 {
     might_fault();
     if (access_ok(VERIFY_READ, from, n))
         return __copy_from_user(to, from, n);
     else
         return n;
 }

copy_ to_ The user kernel layer transfers data to the application layer.

 static inline long copy_to_user(void __user *to,
         const void *from, unsigned long n)
 {
     might_fault();
     if (access_ok(VERIFY_WRITE, to, n))
         return __copy_to_user(to, from, n);
     else
         return n;
 }

copy_to_user test
Include header file

#include <linux/uaccess.h>

code

int misc_read(struct file *file,char __user *ubuf,size_t size,loff_t *loff_t)
{
    char kbuf[64] = "hello";

    if(copy_to_user(ubuf,kbuf,sizeof(kbuf))!=0)
    {
        printk("copy to user error\n");
        return -1;
    }  
    return 0;

}

copy_from_user test

int misc_write(struct file *file,char __user *ubuf,size_t size,loff_t *loff_t)
{
   char kbuf[64] = {0};

    if(copy_from_user(kbuf,ubuf,size)!=0)
    {
        printk("copy_from_user\n");
        return -1;
    }  
    printk("kbuf is %s\n",kbuf);
    return 0;

}

Keywords: C Linux network Embedded system

Added by Craig79 on Wed, 02 Mar 2022 12:25:02 +0200