platform Bus is learning linux A knowledge point that drivers must master .

This article refers to published :Linux 3.14 kernel

One 、 Concept

There are many physical buses in embedded systems :I2c、SPI、USB、uart、PCIE、APB、AHB

linux from 2.6 Since then, a new driver management and registration mechanism has been added platform Platform bus , It's a virtual bus , It's not a physical bus .

comparison PCI、USB, It's mainly used to describe SOC Resources on chip .platform The resources described have one thing in common : stay CPU Direct address on the bus .

Platform devices are assigned a name ( Used in driver binding ) And a series of things like addresses and interrupt request numbers (IRQ) Resources like that .

For equipment platform_device Express , For driving platform_driver To register .

In the traditional way bus/device/driver Mechanism compared to ,platform Unified management by the kernel , Using resources in the driver , Improve the security and portability of the code .

Two 、platform

1. platform The two most important structures of the bus

platform All drivers maintained must be defined with this structure :

platform_driver

struct platform_driver {int (*probe)(struct platform_device *);  //int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;
bool prevent_deferred_probe;};

The structure , Used to register drivers to platform Bus ,

member meaning
probe When the driver and hardware information match successfully , Will call probe function , The registration and initialization of all drive resources are placed in probe Function
remove Hardware information has been removed , Or the driver is unloaded , Release all of them , The operation of releasing resources is placed in this function
struct device_driver driver All drivers maintained by the kernel must contain this member , Usually driver->name Used to match devices
const struct platform_device_id *id_table Often, a driver can support multiple hardware at the same time , The names of the hardware are placed in the structure array

When we write drivers, we often need to fill in the above members

platform_device

platform A bus is a structure used to describe the hardware information of a device , Including all the resources of the hardware (io,memory、 interrupt 、DMA wait ).

struct platform_device {const char*name;int id;
bool id_auto;struct device dev;
u32 num_resources;struct resource *resource;const struct platform_device_id *id_entry;/* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata archdata;};

member meaning
const char *name Name of equipment , Used to match the driver
struct device dev All devices maintained in the kernel must contain this member ,
u32 num_resources Number of resources
struct resource *resource Descriptive resources

struct device dev->release() Must be realized ,

The member that describes the hardware information struct resource

0x139d0000

struct resource {
resource_size_t start;  // Represents the starting value of the resource ,           
resource_size_t end;    // Represents the address of the last byte of the resource ,  If it's an interruption ,end and satrt identical const char *name;   //  Don't write   unsigned long flags; // The type of resources struct resource *parent, *sibling, *child;};flags Type description of #define IORESOURCE_MEM 0x00000200    // Memory #define IORESOURCE_IRQ 0x00000400    // interrupt 

All the drivers in the kernel , All of them have to contain a name called struct device_driver member , // men
Describe the hardware , Must contain struct device Structural members . // women

struct device_driver {const char*name;      
struct bus_type *bus;struct module *owner;const char*mod_name;/* used for built-in modules */
bool suppress_bind_attrs;/* disables bind/unbind via sysfs */const struct of_device_id *of_match_table;const struct acpi_device_id *acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;};

among :

const char*name;

Used to match hardware .

The kernel describes the hardware , Must contain struct device Structural members :

struct device {struct device *parent;struct device_private *p;struct kobject kobj;const char*init_name; /* initial name of the device */const struct device_type *type;struct mutex mutex;/* mutex to synchronize calls to
 * its driver.
 */struct bus_type *bus;/* type of bus device is on */struct device_driver *driver;/* which driver has allocated this
   device */void*platform_data;/* Platform specific data, device
   core doesn't touch it */struct dev_pm_info power;struct dev_pm_domain *pm_domain;#ifdef CONFIG_PINCTRLstruct dev_pin_info *pins;#endif#ifdef CONFIG_NUMAint numa_node;/* NUMA node this device is close to */#endif
u64 *dma_mask;/* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
     alloc_coherent mappings as
     not all hardware supports
     64 bit addresses for consistent
     allocations such descriptors. */struct device_dma_parameters *dma_parms;struct list_head dma_pools;/* dma pools (if dma'ble) */struct dma_coherent_mem *dma_mem; /* internal for coherent mem
     override */#ifdef CONFIG_DMA_CMAstruct cma *cma_area;/* contiguous memory area for dma
   allocations */#endif/* arch specific additions */struct dev_archdata archdata;struct device_node *of_node; /* associated device tree node */struct acpi_dev_node acpi_node; /* associated ACPI device node */
dev_t devt;/* dev_t, creates the sysfs "dev" */
u32 id;/* device instance */
spinlock_t devres_lock;struct list_head devres_head;struct klist_node knode_class;struct class *class;const struct attribute_group **groups;/* optional groups */void(*release)(struct device *dev);struct iommu_group *iommu_group;
bool offline_disabled:1;
bool offline:1;};

among :

void(*release)(struct device *dev);

Can't be empty .

2. How to sign up

To register a platform Driving steps

1) Registration drive platform_device_register

/**
 * platform_device_register - add a platform-level device
 * @pdev: platform device we're adding
 */int platform_device_register(struct platform_device *pdev){device_initialize(&pdev->dev);arch_setup_pdev_archdata(pdev);return platform_device_add(pdev);}

2) Register device platform_driver_register

#define platform_driver_register(drv) \
__platform_driver_register(drv, THIS_MODULE)

3、 ... and 、 give an example

1. Development steps

platform The development steps of bus driver are :

equipment

The structure to be implemented is :platform_device .

1) initialization resource Structural variables

2) initialization platform_device Structural variables

3) Register the device with the system :platform_device_register.

Three steps above , It must be done before the device driver is loaded , The perform platform_driver_register() Before , The reason is that driver registration needs to match all registered device names in the kernel .

platform_driver_register() Add device In the end, it's called by the kernel device_add function .

Platform_device_add and device_add The main difference is one more step insert_resource(p, r), the platform resources (resource) Add to the kernel , Managed by the kernel .

drive

Driver registration , The structure to be implemented is :platform_driver .

In the initialization function of the driver , Called platform_driver_register() register platform_driver .

It should be noted that :platform_driver and platform_device Medium name The value of the variable must be the same 【 Without considering the device tree , About the device tree , I'll write a new article about it later 】 .

In this way platform_driver_register() Registration time , The current registered platform_driver Medium name The value of the variable and all registered platform_device Medium name Compare the values of variables , Only those with the same name can be found platform_device To register successfully .

When the registration is successful , Would call platform_driver Structural elements probe A function pointer .

example 1

This example is simple , Only for testing platform_driver and platform_device Whether it can be matched successfully .
On the left is platform_device Structure registration code , On the right is platform_driver Structure registration code .

platform_driver Define and register :

 1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/platform_device.h>
  4 #include <linux/ioport.h>
  5 
  6 static int hello_probe(struct platform_device *pdev)
  7 {
  8     printk("match ok \n");
  9     return 0;
 10 }
 11 static  int hello_remove(struct platform_device *pdev)
 12 {
 13     printk("hello_remove \n");
 14     return 0;
 15 }
 16 static struct platform_driver hello_driver =
 17 {
 18     .probe = hello_probe,
 19     .driver.name = "duang",
 20     .remove = hello_remove,     
 21 };
 22 static int hello_init(void)
 23 {
 24     printk("hello_init \n");
 25     return platform_driver_register(&hello_driver);
 26 }
 27 static void hello_exit(void)
 28 {
 29     printk("hello_exit \n");
 30     platform_driver_unregister(&hello_driver);
 31     return;
 32 }
 33 MODULE_LICENSE("GPL");
 34 module_init(hello_init);
 35 module_exit(hello_exit);

platform_device Define and register :

  1 #include <linux/init.h>                                                                                                                                                        
  2 #include <linux/module.h>
  3 #include <linux/platform_device.h>
  4 #include <linux/ioport.h>
  5 
  6 static void hello_release(struct device *dev)
  7 {
  8      return;
  9 }
 10 static struct platform_device hello_device =
 11 {
 12     .name = "duang",
 13     .id = -1,
 14     .dev.release = hello_release,
 15 };
 16 
 17 
 18 static int hello_init(void)
 19 {
 20     printk("hello_init \n");
 21     return platform_device_register(&hello_device);
 22 
 23 }
 24 static void hello_exit(void)
 25 {
 26     printk("hello_exit \n");
 27     platform_device_unregister(&hello_device);
 28     return;
 29 }
 30 MODULE_LICENSE("GPL");
 31 module_init(hello_init);
 32 module_exit(hello_exit);

This program is only for testing platform Whether the framework can be successfully matched ,struct platform_device hello_device No hardware information is set .

Makfile

  1 ifneq ($(KERNELRELEASE),)                                                                                                                                                      
  2 obj-m:=device.o driver.o  3 else
  4 KDIR :=/lib/modules/$(shell uname -r)/build  5 PWD  :=$(shell pwd)
  6 all:
  7     make -C $(KDIR) M=$(PWD) modules  8 clean:
  9     rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order 10 endif

The makefile You can put two at the same time C File compiled into ko file .

compile :

 compile
Compile the generated file :

 Insert picture description here

Load module

 Empty log Information
sudo dmesg -c

 The match is successful

example 2

To structure platform_device Add hardware information , And can be read out in the kernel .
In this case, the structure hello_device Add the following information :

  1. Base register address 0x139d0000, The space of the address is 0x4
  2. Interrupt number 199
    【 Be careful 】
    In the actual kernel, the interrupt number of the peripheral will be based on HW id( Usually soc Manufacturer's equipment soc Each interrupt source will be defined as a unique ID) Calculate a new interrupt number , The interrupt number will be cpu Identified .

device.c

struct resource res[]={[0] ={.start = 0x139d0000,.end  = 0x139d0000 + 0x3,.flags = IORESOURCE_MEM,},[1] ={.start = 199,.end  = 199,.flags = IORESOURCE_IRQ,},};static struct platform_device hello_device = {.name = "duang",.id = -1,.dev.release = hello_release,.num_resources = ARRAY_SIZE(res),.resource = res,};

driver.c

static int hello_probe(struct platform_device *pdev){printk("match ok \n");printk("mem = %x \n",pdev->resource[0].start);printk("irq = %d \n",pdev->resource[1].start);// Registration interrupted 、 Application memory return 0;}

recompile , Uninstall the module of the first example , And get rid of log:

make
sudo rmmod device 
sudo rmmod driver
sudo dmesg -c

perform

From the results ,probe Function correctly read the hardware information .

Four 、platform_device How is it managed ?

1. There is no device tree

When there is no device tree , Samsung Cortex-A8 s5pc100 For example , The hardware information is placed in the following places

arch\arm\mach-s5pc100\Mach-smdkc100.c
arch\arm\plat-samsung\

 register platform_device
platform_device Definition
This array holds , Information about the hardware that needs to be initialized for kernel startup .

2. If there is a device tree

The kernel will have complete code for device initialization , It will parse and initialize the device tree information when the kernel starts , Initialize the hardware information to the corresponding linked list .
After successful bus matching , Will pass the hardware information to probe() function .

Four 、 Other knowledge points related to bus

1. Kernel bus related structure variables

All the buses maintained by the kernel need to register a variable with the following structure .

struct bus_type {const char*name;const char*dev_name;struct device *dev_root;struct device_attribute *dev_attrs;/* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);   
int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;};

platform Definition of bus variables struct bus_type platform_bus_type
The definition is as follows :

struct bus_type platform_bus_type = {.name = "platform",.dev_groups = platform_dev_groups,.match = platform_match,.uevent = platform_uevent,.pm = &platform_dev_pm_ops,};

The most important members are **.match**.

When the hardware information of the device is registered to platform_bus_type When I'm on the bus , Will traverse all platform The driver of bus maintenance ,
Match by name , If the same , It shows that the hardware information matches the driver , Will call the driver platform_driver ->probe function , Initialize all resources of the driver , Make the drive work .

When a device driver is registered with platform_bus_type When I'm on the bus , Will traverse all platform Hardware information for bus maintenance ,
Match by name , If the same , It shows that the hardware information matches the driver , Will call the driver platform_driver ->probe function , Initialize all resources of the driver , Make the drive work .

Registered location

drivers\base\Platform.c

platform_bus_type Registration of

5、 ... and 、 Registration code process details

The benefits of Architecture , It can help us locate the problem

1. match When the function is called to ?

2. probe When the function is called to

The following is the calling process of the above two problem codes :
 Code call flow

We'll talk more about the device tree later .