Linux プラットフォーム デバイス フレームワーク ドライバー

Linux プラットフォーム デバイス フレームワーク ドライバー

  プラットフォーム デバイス フレームワーク (プラットフォーム) は、ドライバーをデバイス層ドライバー層の2 つの部分に分割し、バス モデルを通じてデバイスとドライバーをバインドします。デバイスがシステムに登録されるたびに、そのデバイスはドライバーと照合され、同様に、登録されているすべてのドライバーもデバイスと照合されます。
   通常、Linux デバイスとドライバーはバスに接続する必要があります。PCI、USB、I2C、SPI などに接続されているデバイスの場合、これは当然問題になりませんが、組み込みシステムでは、SOC システムが独立したペリフェラル コントローラーを統合します。 、SOC メモリ空間に接続されたペリフェラルなどは、このタイプのバスには接続されません。
   バス フレームワークのモデル構造に基づいて、Linux 上でプラットフォーム デバイス フレームワーク モデル (プラットフォーム) が導出されます。プラットフォーム デバイス バスは、プラットフォーム バス と呼ばれる仮想バスです対応するデバイス層はplatform_deviceと呼ばれ、ドライバー層はplatform_driverと呼ばれます。デバイス層とドライバー層はプラットフォームデバイスバスを通じてマッチング管理を行います。

1. プラットフォームデバイスフレームワークの機能

  1. プラットフォーム モデルは階層構造を採用しており、デバイス ドライバーを
      プラットフォーム デバイス (platform_device)プラットフォーム ドライバー (platform_driver)の 2 つの部分に分割します。
  2. プラットフォームデバイスは、デバイス自身のリソースをカーネルに登録し、カーネルによって均一に管理できます。
  3. ハードウェア リソースとドライバー インターフェイスの分離、コンパイルされたコードの保守と移植。
    ここに画像の説明を挿入

2. プラットフォームデバイスバス関連のインターフェース機能

2.1 デバイス層インターフェース機能

  各デバイスのシステムは、デバイス構造体struct platform_deviceを通じて保存されます。構造プロトタイプはinclude/linux/platform_devcie.hで定義されます。

struct platform_device {
    
    
	const char	* name; //设备名字,驱动层和设备层匹配标志
	int		id;//通常填-1
	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;
};
  • struct device dev 構造体情報

      struct device dev構造体は、デバイス モデルを実装するために使用されます。この構造体には多くのメンバーがあり、構造体のプロトタイプはinclude/linux/devcie.hで定義されています。
      プラットフォーム データ ポインター: void *platform_data;
      リソース解放関数: void (*release)(struct device *dev);
      プラットフォーム データ ポインターplatform_dataは、ドライバー層に送信できる void * 型のポインターです。任意のデータを渡すには、リソース解放関数インターフェースをデバイス層で実装する必要があります。そうしないと、デバイス層でリソースを解放するときにエラーが報告されます。

  これらのメンバー構造のいくつかを以下に示します。

struct device {
    
    
	const char *init_name; /*逻辑设备的名字*/
	struct device_type *type; /* 设备类型 */
	struct bus_type *bus; /* 设备所属的总线类型 */
	struct device_driver *driver;/* 指向开辟 struct device 结构 driver 指针*/
	void		*platform_data;	/* 平台设备指针 */
	dev_t devt;  /* 存放设备号 dev_t,creates the sysfs"dev" */
	struct class *class;  /* 设备所属类*/
	void	(*release)(struct device *dev);/*设备资源释放函数*/
};
  • struct resource * リソース構造情報

      struct resource * リソース構造は、デバイス リソースのコンテンツ情報を格納するために使用されます。構造定義の場所: include/linux/ioport.h
struct resource {
    
    
	resource_size_t start; //资源起始地址
	resource_size_t end; //资源结构地址
	const char *name;//资源名字
	unsigned long flags;//资源类型
	struct resource *parent, *sibling, *child;
};

  リソース構造内のリソース タイプフラグ、リソース タイプの関連マクロ定義の場所: include/linux/ioport.h、一般的に使用されるリソース タイプは次のとおりです。

#define IORESOURCE_TYPE_BITS	0x00001f00	/* Resource type */
#define IORESOURCE_IO		0x00000100 //IO 空间, 一般在 X86 框架中存在, ARM 一般没有
#define IORESOURCE_MEM		0x00000200 //内存空间,占用的是 CPU 4G 统一编址空间
#define IORESOURCE_IRQ		0x00000400 //中断号
#define IORESOURCE_DMA		0x00000800 //DMA
  • デバイス層登録機能

int platform_device_register(struct platform_device *pdev)
関数:プラットフォーム デバイスの登録;
仮パラメータ: pdev --device 構造体;
戻り値:成功した場合は 0 を返し、失敗した場合は他の値を返します。

  • デバイス層ログアウト機能

void platform_device_unregister(struct platform_device *pdev)
関数:プラットフォーム デバイスを登録;
パラメーター: pdev --device 構造体;

  • 複数のデバイスをカーネルに追加する

int platform_add_devices(struct platform_device **devs, int num)
関数:複数のデバイスをカーネルに登録;
仮パラメータ: pdev --device 構造体;
   num - 登録されたデバイスの数
戻り値:成功した場合は 0 を返し、他の値を返します失敗した場合;

2.2 ドライバー層インターフェース機能

  ドライバー層は、struct platform_driver構造体および構造体定義の場所 ( include/linux/devcie.h)
を通じて関連情報を保存します。   この構造体では、インターフェイス関数を実装する必要があります。

  • リソースマッチング関数: int (*probe)(struct platform_device *)
  • リソース解放関数: int (*remove)(struct platform_device *);
  • ドライバーリソース構造体: struct device_driver driver;

  ドライバー層は複数のデバイス層を照合できます。複数のデバイス層を同時に照合したい場合は、id_tableポインターを使用して照合を完了できます。

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;//匹配多多设备时需要填写
};
  • struct device_driver ドライバー構造体情報

  struct device_driverドライバー構造体には、入力する必要があるメンバー名があります。 id_tableポインターが実装されていない場合、デバイス層とドライバー層は、このメンバーを通じてリソースの照合を完了します。

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;

	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;
};
  • const struct platform_device_id *id_table 構造体情報

  この構造はデバイス リソースの照合にも使用され、1 つのドライバー層が同時に複数のデバイス層と照合できます。

struct platform_device_id {
    
    
	char name[PLATFORM_NAME_SIZE]; //资源匹配参数
	kernel_ulong_t driver_data
			__attribute__((aligned(sizeof(kernel_ulong_t)))); //匹配设备层的 void *platform_data数据
};
  • ドライバー層の登録および登録解除機能

//ドライバー登録関数
int platform_driver_register(struct platform_driver *drv)
//ドライバーキャンセル関数
void platform_driver_unregister(struct platform_driver *drv)

3. プラットフォームデバイスフレームワークの適用例

3.1 デバイス層の登録例

  デバイス層の登録手順:

  1. struct デバイス構造体を入力し、デバイス リソース情報を入力します。 struct resource * resource;
  2. デバイス層登録関数 platform_device_register() を呼び出します。
  3. 登録を解除する場合は、登録解除関数 platform_device_unregister を呼び出します。
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/platform_device.h>

#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>

static void platform_release(struct device *dev)
{
    
    
	printk("资源释放完成\n");
}
static struct resource	resource[]=
{
    
    
	[0]={
    
    
			.start=EXYNOS4X12_GPM4(0),
			.end=EXYNOS4X12_GPM4(0),
			.name="led1",
			.flags=IORESOURCE_MEM
		},
	[1]={
    
    
			.start=EXYNOS4X12_GPM4(1),
			.end=EXYNOS4X12_GPM4(1),
			.name="led2",
			.flags=IORESOURCE_MEM
		},		
		
};

struct platform_device pdev=
{
    
    
	.name="led_dev",
	.id=-1,
	.dev=
	{
    
    
		.release=platform_release,//资源释放函数
	},
	.num_resources=sizeof(resource)/sizeof(resource[0]),
	.resource=resource,	
};

static int __init wbyq_platform_dev_init(void)
{
    
    
	platform_device_register(&pdev);
    return 0;
}
/*驱动释放*/
static void __exit wbyq_platform_dev_cleanup(void)
{
    
    
	/*注销设备层*/
	platform_device_unregister(&pdev);

}
module_init(wbyq_platform_dev_init);//驱动入口函数
module_exit(wbyq_platform_dev_cleanup);//驱动出口函数

MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 platform_dev Driver");

3.2 ドライバー層の登録例

  ドライバー層の登録手順:

  1. struct platform_driver 構造体に記入して、リソース照合機能とリソース解放機能を実装します。
  2. デバイス層登録関数 platform_driver_register() を呼び出します。
  3. ログアウトするときは、ログアウト関数 platform_driver_unregister を呼び出します。
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/platform_device.h>

#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>

static int platform_probe(struct platform_device *dev)
{
    
    
	printk("资源匹配成功\n");
	printk("资源个数:%d\n",dev->num_resources);
	struct resource * resource=platform_get_resource(dev,IORESOURCE_MEM,0);
	if(resource)
	{
    
    
		printk("资源名:%s\tstart=%x\tend=%x\n",resource->name,resource->start,resource->end);
	}
	return 0;
	
}
static int platform_remove(struct platform_device *dev)
{
    
    
	printk("资源释放成功\n");
	return 0;
}
static struct platform_device_id id_table[]=
{
    
    
	[0]=
	{
    
    
		.name="led_dev"
	},
	[1]=
	{
    
    
		.name="tiny4412_dev"
	},
	
};
static struct platform_driver drv=
{
    
    
	.probe=platform_probe,
	.remove=platform_remove,
	.driver=
	{
    
    
		.name="platform_drv",
	},
	.id_table=id_table,
};
static int __init wbyq_platform_drv_init(void)
{
    
    
	platform_driver_register(&drv);
	printk("驱动层平台设备注册成功\n");
    return 0;
}
/*驱动释放*/
static void __exit wbyq_platform_drv_cleanup(void)
{
    
    
	/*注销设备层*/
	platform_driver_unregister(&drv);
	printk("驱动层平台设备注销成功\n");

}
module_init(wbyq_platform_drv_init);//驱动入口函数
module_exit(wbyq_platform_drv_cleanup);//驱动出口函数

MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 platform_drv Driver");

3.3 メイクファイル

KER_ADD=/home/wbyq/src_pack/linux-3.5
all:
	make -C $(KER_ADD) M=`pwd` modules
	#arm-linux-gcc main.c -o app 
	cp ./*.ko  /home/wbyq/src_pack/rootfs/code 
	make -C $(KER_ADD) M=`pwd` modules clean
	rm app -f
obj-m +=platform_drv.o platform_dev.o platform_dev2.o

4 ランニング効果

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_44453694/article/details/126868999