module_platform_driver(xxx)解析

向苗宣
2023-12-01

参考源码:x3399_nougat_industry

驱动路径:kernel\drivers\leds\leds-gpio.c

​
static struct platform_driver gpio_led_driver = {
	.probe		= gpio_led_probe,
	.remove		= gpio_led_remove,
	.shutdown	= gpio_led_shutdown,
	.driver		= {
		.name	= "leds-gpio",
		.of_match_table = of_gpio_leds_match,
	},
};

module_platform_driver(gpio_led_driver);

​

module_platform_driver(xxx)宏定义在kernel\include\linux\platform_device.h这样定义

/* module_platform_driver() - Helper macro for drivers that don't do
 * anything special in module init/exit.  This eliminates a lot of
 * boilerplate.  Each module may only use this macro once, and
 * calling it replaces module_init() and module_exit()
 */
#define module_platform_driver(__platform_driver) \
	module_driver(__platform_driver, platform_driver_register, \
			platform_driver_unregister)

module_driver 在kernel\include\linux\device.h定义如下:

/**
 * module_driver() - Helper macro for drivers that don't do anything
 * special in module init/exit. This eliminates a lot of boilerplate.
 * Each module may only use this macro once, and calling it replaces
 * module_init() and module_exit().
 *
 * @__driver: driver name
 * @__register: register function for this driver type
 * @__unregister: unregister function for this driver type
 * @...: Additional arguments to be passed to __register and __unregister.
 *
 * Use this macro to construct bus specific macros for registering
 * drivers, and do not use it on its own.
 */
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
	return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
	__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

可以看出这个模块是在platform总线上注册,模块包含有驱动的注册与驱动的卸载。 

非热插拔平台设备可以使用这种方法,以便使用probe()和 它的支持可能存在于__init节中,以保存运行时内存。  

/*
 * use a macro to avoid include chaining to get THIS_MODULE
 */
#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)
extern int __platform_driver_register(struct platform_driver *,
					struct module *);
extern void platform_driver_unregister(struct platform_driver *);

platform device 描述

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;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

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;
};

struct device_driver driver;描述

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 */
	enum probe_type probe_type;

	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;
};

platform_device和platform_driver 里面的驱动名称要一样 才能适配的上,否者probe不执行。

相当于:

static int __init gpio_led_driver_init(void) 
{ 
	printk("welcome_to_gpio_led_driver_init\n");
	return platform_driver_register(&gpio_led_driver); 
} 

static void __exit gpio_led_driver_exit(void) 
{ 
	platform_driver_unregister(&gpio_led_driver); 
} 


module_init(gpio_led_driver_init);
module_exit(gpio_led_driver_exit);

如果驱动注册成功:/sys/bus/platform/drivers 会生成对应的驱动名称,这里的驱动名称是leds-gpio。

查看驱动打印出现:welcome_to_gpio_led_driver_init 说明驱动有编译生效。

[    4.203839] dwmmc_rockchip fe320000.dwmmc: 1 slots initialized
[    4.204389] sdhci-pltfm: SDHCI platform and OF driver helper
[    4.206494] sdhci-arasan fe330000.sdhci: No vmmc regulator found
[    4.206530] sdhci-arasan fe330000.sdhci: No vqmmc regulator found
[    4.232811] mmc1: SDHCI controller on fe330000.sdhci [fe330000.sdhci] using ADMA
[    4.233570] welcome_to_gpio_led_driver_init
[    4.234975] ===========================zdong=====================
[    4.236837] hidraw: raw HID events driver (C) Jiri Kosina
[    4.239521] usbcore: registered new interface driver usbhid
[    4.239539] usbhid: USB HID core driver
[    4.239698] inv_mpu_iio: inv_mpu_init:746
[    4.240320] ashmem: initialized
[    4.243849] ff100000.saradc supply vref not found, using dummy regulator
[    4.245127] rknandbase v1.1 2016-11-08

关于设备名的查看,请查看我另一篇博客:

x3399_nougat_industry led-gpio简析_小猿东哥的博客-CSDN博客

 类似资料: