当前位置:网站首页>[kernel] platform bus model for driving development and learning
[kernel] platform bus model for driving development and learning
2022-07-23 20:34:00 【Cold boiled cabbage】
Platform Platform bus model
One 、 Preface
The platform bus model is also handed over platform Bus model , He is Linux A virtual bus , He is not a real electrical bus ; The platform bus model is the original driver C The file is divided into two files. One is device The file corresponds to our device file , One is driver The file corresponds to our driver file , The advantages of platform bus are :
1) Improve code reuse
2) Reduce repetitive code
3) Distinguish between equipment and drive
4) It is more convenient to manage our equipment
Put the stable drive on driver Inside , The equipment that needs to be changed is placed in device In file ; When we register device perhaps driver Will pass when name Match , In fact, it is the comparison of a string variable in the structure .
Two 、 register Device file
device.c Hardware resources are stored in the file , The hardware resource here refers to the register address 、 Interrupt number 、 Clock and other hardware resources , stay Linux In the kernel, we use a structure to describe ;
#include <linux/platform_device.h> // Header files required by platform devices
struct platform_device {
const char *name; // Name required for platform bus matching
int id; // Number the same equipment , If there is only one equipment here -1 that will do
bool id_auto;
struct device dev; // embedded device Structure
u32 num_resources; // Number of resources ARRAY_SIZE(struct resource)
struct resource *resource; // device Corresponding hardware resources : Register address 、 Interrupt number, etc
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
Device resource structure
struct resource {
resource_size_t start; // Register start address
resource_size_t end; // Register end address
const char *name; // Resource name
unsigned long flags; // The resource type
unsigned long desc;
struct resource *parent, *sibling, *child;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
ANDROID_KABI_RESERVE(4);
};
Resource types include :
#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */ // io Of memory
#define IORESOURCE_MEM 0x00000200 // Physical memory address ( Commonly used )
#define IORESOURCE_REG 0x00000300 /* Register offsets */
#define IORESOURCE_IRQ 0x00000400 // Interrupt number ( Commonly used )
#define IORESOURCE_DMA 0x00000800 // DMA The address of
#define IORESOURCE_BUS 0x00001000 // Bus number :SPI 、 IIC
Example
// Equipment resource information , That is to say BEEP All registers used
struct resource led_res[] = {
[0] = {
.start = 0xfdd60000, // Corresponding start address
.end = 0xfdd60003, // Corresponding end address
.flags = IORESOURCE_MEM, // Express GPIO Memory
.name = "GPIO_DR", // Express DR Register random
}
[1] = {
.start = 0xffffff0, // Corresponding to the starting address used by the second driver
.end = 0xfffffff, // Corresponding to the end address used by the second driver
.flags = IORESOURCE_IO, // Express GPIO Memory
.name = "GPIOA7", // Express DR Register random
}
};
// platform Equipment structure
struct platform_device led_device = {
.name = "led_work",// Drive matching name
.id = -1,
.resource = led_res, // Fill in the device resource structure
.num_resources = ARRAY_SIZE(led_res), // Get the number of resources
.dev = {
.release = led_release
} // device Device interface
};
platform Functions used for bus registration and unloading
platform_device_register(&led_device); // register
platform_device_unregister(&led_device); // uninstall
When we put the above device After registering to the kernel, in the development board /sys/bus/platform/devices Generate our led_work node 

3、 ... and 、 register Driver file
To write driver The idea of , So let's define a platform_driver Variable , Then implement each member variable in the structure , When our driver perhaps device When registering, it will match name When the match is successful, it will execute probe function , So our driver The focus is on writing probe function , In this section, we will write driver Framework ;
struct platform_device_id led_id_table = {
.name = "led_work", // Matching priority is higher , If he fails to match, he will fail directly
};
// platform Drive structure
struct platform_driver led_driver = {
.probe = led_probe, // Call after the device is successfully matched with the driver
.remove = led_remove, // Call after the driver is removed
.driver={
.owner = THIS_MODULE,
.name = "led_work" // Device matching name
},
// adopt platform The equipment ID Match ( Higher priority , Use this matching method to match driver Of name Property will be invalid )
.id_table = &led_idtable
};
Bus driver registration and unloading functions
platform_driver_register(&led_driver);
platform_driver_unregister(&led_driver);
Four 、 To write Probe function
When our device is successfully matched with the driver, our driver can obtain the resource data in the device through functions , Then we can use this data to operate the device , For example, the registration of character devices 、 Registration of miscellaneous equipment 、SPI Use of resources 、IIC Use of equipment 、 Use of interrupts, etc ;
struct resource *led_mem;
int led_probe(struct platform_device *pdev)
{
int ret;
// Get the number of memory address types of this function 0 A resource , If there are multiple resources increasing in turn , If there is a resource of other types in the middle, it will not be counted
// for example
// [0] IORESOURCE_MEM [1]IORESOURCE_IRQ [2]IORESOURCE_MEM
// If we want to get the following [2] resources :platform_get_resource(pdev, IORESOURCE_MEM, 1)
// If we want to get the following [1] resources :platform_get_resource(pdev, IORESOURCE_IRQ, 0)
led_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (led_mem == NULL)
{
printk("platform_get_resource is error\n");
return -EBUSY;
}
// When our resources are successfully obtained, we accept the returned mem Is equal to device As defined in resource, We can use it directly
printk("led_res start is 0x%x \n", led_mem->start);
printk("led_res end is 0x%x \n", led_mem->end);
return 0;
}

5、 ... and 、 Complete code example
Drive part
sdevices.c
#include <linux/init.h> // Initialize header file
#include <linux/module.h> // The most basic file , Support dynamic adding and unloading modules
#include <linux/platform_device.h>// Header files required by platform devices
#include <linux/mod_devicetable.h>
// #include <linux/gpio.h>
void led_release(struct device *dev)
{
printk("led_release \n");
}
// Equipment resource information , That is to say BEEP All registers used
struct resource led_res[] = {
[0] = {
.start = 0xfdd60000,
.end = 0xfdd60003 ,
.flags = IORESOURCE_MEM,
.name = "led_work",
}
};
// platform Equipment structure
struct platform_device led_device = {
.name = "led_work",
.id = -1,
.resource = led_res,
.num_resources = ARRAY_SIZE(led_res),
.dev = {
.release = led_release
}
};
static int device_init(void) {
// Device information is registered to Linux kernel
platform_device_register(&led_device);
return 0;
}
static void device_exit(void) {
// Device information uninstall
platform_device_unregister(&led_device);
}
module_init(device_init);
module_exit(device_exit);
MODULE_LICENSE("GPL");
sdrivers.c
#include <linux/init.h> // Initialize header file
#include <linux/module.h> // The most basic file , Support dynamic adding and unloading modules
#include <linux/platform_device.h>// Header files required by platform devices
#include <linux/mod_devicetable.h>
#include <linux/ioport.h> /* Register miscellaneous device header file */
#include <linux/miscdevice.h> // File system header file , Define file table structure (file,buffer_head,m_inode etc. )
#include <linux/fs.h> // Contains copy_to_user、copy_from_user Wait for the kernel to access the function definition of the memory address of the user process .
#include <linux/uaccess.h> // Contains ioremap、iowrite Wait for kernel access IO Definition of functions such as memory .
#include <linux/io.h> // Register address definition
#include <linux/gpio.h>
// The first address of the mapped virtual address
unsigned int *vir_gpio_dr;
struct resource *led_mem;
long misc_ioctl(struct file *files, unsigned int cmd, unsigned long arg)
{
printk("cmd is %d,arg is %d \n",cmd,(unsigned int)(arg));
switch(cmd)
{
case 0:
{
printk(KERN_INFO "LEDON \n");
*vir_gpio_dr = 0x80008000;
break;
}
case 1:
{
printk(KERN_INFO "LEDOFF\n");
*vir_gpio_dr = 0x80000000;
break;
}
}
return 0; // It must be added or an error will be reported error: control reaches end of non-void function [-Werror=return-type]
}
struct file_operations misc_fops={
// File operation set
.owner = THIS_MODULE,
.unlocked_ioctl = misc_ioctl,
};
struct miscdevice misc_dev = {
// Miscellaneous equipment structure
.minor = MISC_DYNAMIC_MINOR, // Secondary equipment number of dynamic application
.name = "platform_misc", // The name of miscellaneous equipment is hello_misc
.fops = &misc_fops, // File operation set
};
int led_remove(struct platform_device *pdev)
{
iounmap(vir_gpio_dr);
misc_deregister(&misc_dev);
return 0;
}
int led_probe(struct platform_device *pdev)
{
int ret;
led_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (led_mem == NULL)
{
printk("platform_get_resource is error\n");
return -EBUSY;
}
printk("led_res start is 0x%llx \n", led_mem->start);
printk("led_res end is 0x%llx \n", led_mem->end);
ret = misc_register(&misc_dev);
if(ret<0)
{
printk("misc registe is error \n");
}
printk("misc registe is succeed \n");
// Convert physical address to virtual address
vir_gpio_dr = ioremap(led_mem->start,4);
if(vir_gpio_dr == NULL)
{
printk("GPIO_DR ioremap is error \n");
return EBUSY;
}
printk("GPIO_DR ioremap is ok \n");
return 0;
}
struct platform_device_id led_id_table = {
.name = "led_work", // Matching priority is higher , If he fails to match, he will fail directly
};
struct platform_driver led_driver = {
.probe = led_probe,
.remove = led_remove,
.driver={
.owner = THIS_MODULE,
.name = "led"
},
.id_table = &led_id_table,
};
static int led_driver_init(void)
{
int ret = 0; // platform Driver registered to Linux kernel
ret = platform_driver_register(&led_driver);
if(ret<0) {
printk("platform_driver_register error \n");
}
printk("platform_driver_register ok \n");
return 0;
}
static void led_driver_exit(void)
{
// platform Drive unload
platform_driver_unregister(&led_driver);
}
module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");
makefile
obj-m += sdrivers.o // The driver and the device are modified accordingly
KDIR =/home/topeet/Linux/02.sdk/rk356x_linux/kernel
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules modules ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
clean:
rm -rf modules.order *.o workqueue.o Module.symvers *.mod.c *.ko
Usage method : Part sequence
insmod sdrivers.ko
insmod sdevices.ko
Application part
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define LEDON 1 // According to the driven switch To write
#define LEDOFF 0
int main(int argc,char *argv[])
{
int fd;
// Open the device node
fd = open("/dev/platform_misc",O_RDWR);
if(fd < 0)
{
// Failed to open the device node
perror("open error \n");
return fd;
}
while(1)
{
ioctl(fd,LEDON,0);
sleep(1);
ioctl(fd,LEDOFF,0);
sleep(1);
}
close(fd);
}
Experimental results :LED Light flashing 


边栏推荐
- Today's sleep quality record 81 points
- Go to the square for dinner
- ModelBox端云协同AI开发套件(RK3568)试用记录(二)
- ODrive应用 #6 编码器
- 【Kernel】驱动开发学习之Platform平台总线模型
- What if there is no word document in win11? There is no word document solution tutorial in win11
- Parity rearrangement of Bm14 linked list
- The instructions on Microsoft website about opening or closing smartscreen in edge browser are incorrect
- When using polymorphism, two ideas to judge whether it can be transformed downward
- 微服务架构 VS 单体服务架构【华为云服务在微服务模式里可以做什么】
猜你喜欢

选择大于努力!贵阳校区小哥哥0基础成功转行软件测试收获12K!

考研 | 高等数学 Chapter4 不定积分

Lingo 基本使用

一文读懂研发效能洞察的五大流动指标

【C语言】通讯录(静态版本)

如何合理地估算线程池大小

Data warehouse 4.0 notes - data warehouse environment construction - DataGrid preparation and data preparation

NLP领域历史最全必读经典论文分类整理分享(附中文解析)

17.生命周期

After the input error of next numerical data type () occurs, it can still be input normally next time
随机推荐
链表——203. 移除链表元素
JDK installation package and MySQL installation package sorting
20.ref与props
剑指 Offer II 115. 重建序列
Lingo basic use
【C语言】通讯录(静态版本)
海通证券股票开户怎么样安全吗
el-upload实现上传文件预览
【力扣】三数之和
【云享读书会第13期】第五章FFmpeg 查看媒体信息和处理音视频文件的常用方法
Discussion on the usage of scanf () and getchar ()
Meiker Studio - Huawei 14 day Hongmeng equipment development practical notes 5
The latest version of conflict+docker+mysql8 deployment tutorial
EXCEL的密码相关
Cesium knockout怎么用?
数组——977. 有序数组的平方
不用MQTT C库就能实现MQTT连接、订阅和发布
微服务架构 VS 单体服务架构【华为云服务在微服务模式里可以做什么】
利用ENVI对TROPOMI(哨兵5P)数据预处理
Task03 notes 2