Linuxドライバー開発研究ノート[11]:プラットフォームデバイスドライバー

目次

1.Linuxドライバーの分離と階層化

1.1。ドライブの分離と分離

1.2、ドリブンレイヤリング

2.ドライバーバスデバイスモデル

2.1バス

2.2ドライブ

2.3機器

3、プラットフォームプラットフォームドライバーモデル

3.1プラットフォームバス

3.2プラットフォームドライバー

3.3プラットフォーム機器

3.4プラットフォームマッチングプロセス

4、プラットフォームプラットフォームドライバーの実験的プログラムの作成

4.1デバイスツリーなし

4.2デバイスツリーあり


1.Linuxドライバーの分離と階層化

ドライバーの作成を容易にし、ソフトウェアの再利用とクロスプラットフォームのパフォーマンスを向上させるために、Linuxはドライバーの階層化と分離を提案しています

1.1。ドライブの分離と分離

ホストドライバーとデバイスドライバーに分かれており、接続用の統合APIが中央にあります。ホストコントローラードライバーは通常、半導体メーカーによって作成され、デバイスドライバーはLinuxドライバーフレームワークの下で作成されます。これは、Linuxのバス、ドライバー、およびデバイスモデルです。

1.2、ドリブンレイヤリング

 

2.ドライバーバスデバイスモデル

ドライバの分離と階層化に従って、バス-ドライバ-デバイスドライバフレームワークが導出されます。バスコードは通常、Linuxカーネルによって提供される私たちが作成する必要はありません。ドライバーとデバイスを書き込むだけです。ドライバーをバスに登録すると、バスは既存のすべてのデバイスを検索して、どのデバイスがこのドライバーに一致するかを確認します。同様に、デバイスをバスに登録すると、バスは既存のドライバー内のドライバーと一致するかどうかを確認します。

ドライバー:特定のデバイスドライバー、読み取り、変更、消去、書き込み

デバイス:デバイスのプロパティ。たとえば、IICデバイスにはIICデバイスのアドレス、速度などがあります。

2.1バス

バスデータ型があるbus_type使用して、bus_registerをカーネルバスまで、主な役割は、駆動装置と完全に一致しています。Linuxには多くの種類のバスがあり、ルートファイルシステムの/ sys / busディレクトリで表示できます。

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;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;
};

2.2ドライブ

バスデータ型があるのdevice_driver、使用driver_registerカーネルとドライバを登録します。ドライバがデバイスと一致した後、ドライバのプローブ機能が実行されます。ルートファイルシステムの/ sys / bus / specific bus / driversディレクトリで表示できます

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

2.3機器

バスのデータタイプはデバイスです。device_register使用してデバイスをカーネルに登録します。ドライバがデバイスと一致した後、ドライバのプローブ機能が実行されます。ルートファイルシステムの/ sys / bus /特定のバス/デバイスディレクトリ表示できます

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 */
    ...
	/* arch specific additions */
	struct dev_archdata	archdata;

	struct device_node	*of_node; /* associated device tree node */
	struct fwnode_handle	*fwnode; /* firmware device node */

	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
};

3、プラットフォームプラットフォームドライバーモデル

ドライバ-バス-デバイスドライバモデルによると、IIC、SPI、USBなどの実際のバスは完全に一致していますが、一部の周辺機器は、SOC内部タイマー、RTCなどの特定のバスに帰することができません。 LCDなど このため、Linuxカーネルは仮想プラットフォームドライバーモデルを作成しました:プラットフォームドライバー-バス-プラットフォームデバイス

3.1プラットフォームバス

プラットフォームプラットフォームの場合、プラットフォームバスもbus_typeタイプです。platform_matchは、プラットフォームドライバーとデバイスのマッチングを担当します。platform_bus_init---> bus_registerプラットフォームバスをカーネル登録します

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

int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);
	if (error)
		return error;
	error =  bus_register(&platform_bus_type);
	if (error)
		device_unregister(&platform_bus);
	of_platform_register_reconfig_notifier();
	return error;
}

3.2プラットフォームドライバー

プラットフォームドライバを使用して、いくつかのプラットフォーム固有の属性を追加し、構造体のdevice_driverに基づいて導出されplatform_driver_registerを、カーネルとプラットフォームドライバを登録するためのプラットフォームドライバが正常にプラットフォームのデバイスに一致した場合、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 of_device_id *of_match_table;
    // ---> const char *name;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};

3.3プラットフォーム機器

プラットフォームドライバは、struct deviceに基づいて派生し、いくつかのプラットフォームプロパティが追加されています。デバイスツリーがない場合は、platform_device_registerを使用してプラットフォームデバイスをカーネルに登録する必要があります。デバイスツリーがある場合は、デバイスツリーを変更するだけで済みます。プラットフォームドライバがプラットフォームデバイスと正常に一致すると、platform_driverのプローブが実行されます。

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

3.4プラットフォームマッチングプロセス

ドライバーとデバイスのマッチングはbus-> match関数を介して実行され、プラットフォームバスの下のmatch関数はplatform_matchです。

/**
 * platform_match - bind platform device to platform driver.
 * @dev: device.
 * @drv: driver.
 *
 * Platform device IDs are assumed to be encoded like this:
 * "<name><instance>", where <name> is a short description of the type of
 * device, like "pci" or "floppy", and <instance> is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "<name>".  So, extract the <name> from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
        return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first(首先尝试通过设备树来匹配) */
	if (of_driver_match_device(dev, drv))
        return 1;

	/* Then try ACPI style match(再尝试通过acpi来匹配) */
	if (acpi_driver_match_device(dev, drv))
        return 1;

	/* Then try to match against the id table(根据driver下的id_table来匹配dev) */
	if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */ 
   /*最终的就是比较字符串,也就是比较 platform_device->name 和 platform_driver->driver->name
    *这是大多数无设备树情况下的匹配使用方式*/
	return (strcmp(pdev->name, drv->name) == 0);
}

デバイスツリーがある場合、照合プロセスは次のとおりです。

of_driver_match_device(dev, drv)
    ---> of_match_device //of_match_table 为 platform驱动下的 device_driver ---> of_match_table

static inline int of_driver_match_device(struct device *dev,const struct device_driver *drv)
{
	return of_match_device(drv->of_match_table, dev) != NULL;
}

/*
 * Struct used for matching a device
 */
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

4、プラットフォームプラットフォームドライバーの実験的プログラムの作成

4.1デバイスツリーなし

実験ルーチンでは、LED照明を例として取り上げます。これは、ledデバイスとledドライバーの2つの部分で記述する必要があります。ledデバイスには、ledのすべてのリソース、つまり使用されるIOのアドレス情報が含まれます。これらのアドレス情報は、ledドライバーに提供されます。 。つまり、ledドライバーでは、関数platform_get_resourceを使用して、ledデバイスからこれらのリソース(アドレス情報)を取得します。

struct resource *platform_get_resource(struct platform_device *dev, 
                                        unsigned int type, //资源类型 
                                        unsigned int num)//资源索引

プログラムのソースコード:

https://github.com/denghengli/linux_driver/tree/master/18_led_platform

使用例:

4.2デバイスツリーあり

デバイスツリーがある場合、デバイスはデバイスツリーによって記述されるため、デバイスをバスに登録する必要はありませんが、デバイスツリーを直接変更してから、ドライバを記述します。ドライバとデバイスが正常に一致した後、デバイス情報はデバイスツリーノードからplatform_device構造に変換されます。実験ルーチンでは、例としてLED照明を使用します。

プログラムのソースコード:

https://github.com/denghengli/linux_driver/tree/master/19_led_dtsplatform

使用例:

 

おすすめ

転載: blog.csdn.net/m0_37845735/article/details/107307579