Linux device driver model platform device

Linux device driver model platform device

The previous chapter introduced the Linux character device driver, which is relatively basic and allows everyone to understand how to register and use the device driver of the Linux kernel. But at work, I personally think that there are relatively few opportunities to write a character device driver completely by hand. Most of them are based on previous code modifications that have been made for three years. In the kernel driver, you will see more platform-related words. What are they specifically? Let’s take a look.

platform bus

In embedded Linux, you may hear about I2C bus, SPI bus, USB bus, etc., but what is platform bus and what are its specifications? The platform bus is a virtual bus. It does not have communication protocol specifications like the bus introduced above. It is only virtualized to better manage Linux kernel device drivers.

During the project development process, there will be many device drivers that need to be registered, but these devices will all have a lot in common, such as the operations that need to be paid attention to when waking up from sleep. Each device will be different, but they will all have needs, and the same is true when turning on and off. In order to facilitate the management of these device drivers, Linux has added platform devices and drivers to facilitate unified management of the drivers during the development process. Both devices and drivers are mounted on the bus. When new devices or drivers are added, they will be compared. When the device and driver information are consistent, corresponding operations are performed to complete resource application and device registration.

The Linux kernel provides an interface for registering buses. Let’s take a look at what information the platform’s buses provide:

/* 从platform_bus的定义来看,虽然我们说platform总线,实际上它还是一个设备 */
struct device platform_bus = {
    
    
        .init_name      = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);

/* 定义platform设备的默认属性 */
static struct attribute *platform_dev_attrs[] = {
    
    
        &dev_attr_modalias.attr,
        &dev_attr_driver_override.attr,
        NULL,
};
ATTRIBUTE_GROUPS(platform_dev);

/* 提供设备的休眠唤醒接口函数,platform设备的休眠唤醒都通过这个接口完成调用 */
static const struct dev_pm_ops platform_dev_pm_ops = {
    
    
        .runtime_suspend = pm_generic_runtime_suspend,
        .runtime_resume = pm_generic_runtime_resume,
        USE_PLATFORM_PM_SLEEP_OPS
};

/* 定义platform总线的一些总要接口 */
struct bus_type platform_bus_type = {
    
    
        .name           = "platform",
        .dev_groups     = platform_dev_groups,	/* 总线上设备的默认属性 */
        .match          = platform_match,		/* 前面我们说到注册分别注册设备和驱动之后,将会进行设备驱动匹配,platform设备就是通过该函数实现的 */
        .uevent         = platform_uevent,		/* 当添加、删除设备的时候,生成uevent添加到环境变量,实际上可以理解为有设备添加、删除时发送广播  */
        .pm             = &platform_dev_pm_ops,	/* 这个就是上面的休眠唤醒时的调用接口了 */
};
EXPORT_SYMBOL_GPL(platform_bus_type);

int __init platform_bus_init(void)
{
    
    
        int error;

        early_platform_cleanup();

    	/* 注册platform设备 */
        error = device_register(&platform_bus);
        if (error)
                return error;
    	/* 向系统注册platform总线 */
        error =  bus_register(&platform_bus_type);
        if (error)
                device_unregister(&platform_bus);
        of_platform_register_reconfig_notifier();
        return error;
}

The bus_register function mainly performs the following operations:

  1. Set the driver self-detection flag drivers_autoprobe to 1, so that as long as a device or driver joins the bus, the device driver detection will be triggered;
  2. Create the default attribute node of bus;
  3. Create bus probe and other file nodes;

After registering the platform bus with the system, how to use it? Let's take a look at the operation of platform devices and drivers.

platform device

Platform devices are generally added to various SOC interfaces or peripherals in the kernel driver. As an interface to connect to the kernel device, the respective device driver can be more flexible. Let's first look at how the kernel defines this platform device.

struct platform_device {
    
    
        const char      *name;			/* 设备属于什么名字的 */
        int             id;				/* 设备的索引,比如有多个类似的设备 */
        struct device   dev;			/* 内核设备的基础 */
        ...
        u32             num_resources;
        struct resource *resource;		/* 用于这个设备的资源保存了,比如中断和寄存器地址等 */
        ...
};

After basically understanding the type of platform device above, how does it register with the Linux kernel? Mainly through the following two interface functions.

/* 登记注册platform device */
int platform_device_register(struct platform_device *pdev);
/* 登记注册num个platform device */
int platform_add_devices(struct platform_device **devs, int num);

So what are the main operations of the platform_device_register() function?

  1. Initialize pdev->dev through device_initialize, which is to initialize the above struct device;
  2. Set the DMA mask of the platform device;
  3. Initialize the parent of pdev->dev to platform_bus and bus to platform_bus_type;
  4. Update platform device resources;
  5. Add pdev->dev device to the kernel through device_add();

It seems that the registration is completed. Now there is only the device and no driver. Let's see what the driver is.

platform driver

The kernel separates devices and drivers. Devices can be visible and tangible entities, or they can be some virtual, remote devices, while drivers are the code that enables the device to work normally. The platform driver is defined as follows:

struct platform_device_id {
    
    
        char name[PLATFORM_NAME_SIZE];
        kernel_ulong_t driver_data;
};

struct platform_driver {
    
    
    	/* probe函数用于探测是否存在和该驱动一致的platform device,由各自driver实现,驱动加载时调用 */
        int (*probe)(struct platform_device *);
    	/* remove函数则是在卸载模块时调用,释放相关资源 */
        int (*remove)(struct platform_device *);
    	/* 系统关机时将会调用shutdown */
        void (*shutdown)(struct platform_device *);
    	/* suspend和resume则是系统进入休眠和唤醒时调用 */
        int (*suspend)(struct platform_device *, pm_message_t state);
        int (*resume)(struct platform_device *);
    	/* 内核驱动的基础 */
        struct device_driver driver;
    	/* platform device和driver匹配信息 */
        const struct platform_device_id *id_table;
};

The basic members of the platform driver are listed above. Each driver will be implemented. The basic needs are to complete the filling of probe, remove and id_table information. To register a driver with the kernel, driver registration is completed through platform_driver_register, which mainly performs several operations:

  1. Set the driver's bus to platform_bus_type;
  2. The driver is a platform driver, so the probe, remove, and shutdown functions of device_driver are set to the platform driver's functions;
  3. Register the driver with the kernel through the driver_register function;

The meaning of probe

A machine with only hardware without software may be just a pile of scrap metal; and with only software drivers, it is useless and cannot play its role without a carrier. Although we have registered device and driver, if there is no match, it will not work, just like using an ARM64 firmware on a mips architecture chip and failing to run, so the meaning of probe is to confirm whether the current device is consistent with itself through the driver. If they are consistent, the registration of system nodes can be carried out.

When introducing the platform device above, there is a name member, and there is an id_table in the platform driver. When will the device and driver be triggered to match?

Looking back, when registering the driver through the platform_driver_register() function, driver_register() will call bus_add_driver() to register the driver with the bus. In bus_add_driver(), because the bus has already set drivers_autoprobe, driver_attach() will be used to match device and driver. , the process is as follows:

platform_driver_register
	driver_register
		bus_add_driver
			driver_attach
				__driver_attach
					driver_match_device
						bus->match

In driver_attach, the klist_devices of the bus (all device information on the bus is on this linked list) will be matched with the driver one by one. The matching is completed through the __driver_attach() function. In __driver_attach, the bus is called through driver_match_device() The match function of platform bus is platform_match(). platform_match will perform the following comparisons in sequence:

  1. If the driver_override of the platform device is set, compare the driver_override of pdev and the name of drv to see if they are consistent;
  2. To match the device tree, compare the of_match_table of drv and the of_node information of dev to see if they are consistent;
  3. Comparing acpi information, this point is not very clear and is not used normally;
  4. Compare pdrv->id_table and pdev->name. This is usually used more often;
  5. Finally, directly compare pdev->name and drv->name;

If none of the above comparisons are consistent, there is no match, otherwise the match is successful. If the device driver is successfully matched, it will be matched through the device_driver_attach() function.

device_driver_attach will perform the following operations:

  1. Get the pin configuration information of the device;
  2. Establish a link between the driver and device in the /sys directory;
  3. The probe function of the bus where the device is located is called first, if not, the probe function of the driver is called;
  4. Configure all pins of the device to default state;

For example, the platform bus does not implement the probe function, so the platform_drv_probe() function assigned when registering the driver will be called. Here, the probe function of the platform driver is actually called, which is the probe function implemented by the driver itself.

When the probe function is called, it proves that the device driver model of the entire Linux kernel has been run through. However, whether the device actually exists requires the probe function to be implemented. After the probe function confirms that the device exists, it will be possible to apply for resources and related device nodes. registration operation.

device driver model

platform device driver model

Guess you like

Origin blog.csdn.net/weixin_41944449/article/details/132963909