linux platformプラットフォームデバイス駆動

11099 ワード

一.プラットフォームバス
    1. バス構造体
struct bus_type platform_bus_type = {
	.name		= "platform",		//   
	.dev_attrs	= platform_dev_attrs,	//    
	.match		= platform_match,		//    
	.uevent		= platform_uevent,		//    
	.pm		= &platform_dev_pm_ops,	//       
};

 
    2.バスの初期化
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);
	return error;
}

 
    3.paltform_matchメソッド
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);	//               

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))		//    ?
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)				//id   ?
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);		//    
}

 
二.プラットフォームデバイス
   1.プラットフォームデバイス構造体
struct platform_device {
	const char	* name;	//   
	int		id;	//  id
	struct device	dev;	//    
	u32		num_resources;	//     
	struct resource	* resource;	//    

	const struct platform_device_id	*id_entry;

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

    2.プラットフォームデバイス登録
int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	return platform_device_add(pdev);
}

2.1プラットフォーム追加設備
int platform_device_add(struct platform_device *pdev)
{
	int i, ret = 0;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;	//     

	pdev->dev.bus = &platform_bus_type;		//        

	if (pdev->id != -1)			//       
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
	else
		dev_set_name(&pdev->dev, "%s", pdev->name);

	for (i = 0; i < pdev->num_resources; i++) {	//      
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);

		p = r->parent;
		if (!p) {
			if (resource_type(r) == IORESOURCE_MEM)
				p = &iomem_resource;
			else if (resource_type(r) == IORESOURCE_IO)
				p = &ioport_resource;
		}

		if (p && insert_resource(p, r)) {
			printk(KERN_ERR
			       "%s: failed to claim resource %d
", dev_name(&pdev->dev), i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s
", dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); // if (ret == 0) return ret; failed: while (--i >= 0) { struct resource *r = &pdev->resource[i]; unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO) release_resource(r); } return ret; }

2.2プラットフォーム設備の登録は一般的にBoard-xxxに置く.cプレートレベル駆動中
複数のプラットフォーム・デバイスの登録が必要な場合は、次のように配列を定義できます.
static struct platform_device platform_device_1 = {
	.name	= "paltform_1",
	.id	= -1,				//  id      -1
	.num_resources = 0,
    .dev = {
		.platform_data = &paltform_1_pdata,
    }
}; 

static struct platform_device platform_device_2 = {
	.name	= "paltform_2",
	.id	= -1,
	.resource = &paltform_2_resource,		//    
	.num_resources = 1,			//     
};
	....
static struct platform_device *test_devices[] __initdata = {
	&platform_device_1,
	&platform_device_2,
	&platform_device_3,
};

そしてそのプレートレベルで駆動する.init_machineが指定した初期化関数には、次のように登録されています.
//    
platform_device_register(&platform_device_1);
platform_device_register(&platform_device_2);
platform_device_register(&platform_device_3);
//       
platform_add_devices(test_devices,ARRAY_SIZE(test_devices))

2.3 platform_の使用add_デバイスは複数のプラットフォームデバイスを同時に登録する
int platform_add_devices(struct platform_device **devs, int num)
{
	int i, ret = 0;

	for (i = 0; i < num; i++) {
		ret = platform_device_register(devs[i]);	//           platform_device_register  
		if (ret) {
			while (--i >= 0)
				platform_device_unregister(devs[i]);
			break;
		}
	}

	return ret;
}

 
2.4プラットフォームデバイス動的作成platform_device_alloc
struct platform_device *platform_device_alloc(const char *name, int id)
{
	struct platform_object *pa;

	pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
	if (pa) {
		strcpy(pa->name, name);
		pa->pdev.name = pa->name;				//       .name 
		pa->pdev.id = id;					//       .id 
		device_initialize(&pa->pdev.dev);
		pa->pdev.dev.release = platform_device_release;
	}

	return pa ? &pa->pdev : NULL;
}

 
    3.プラットフォームデバイスのログアウト
void platform_device_unregister(struct platform_device *pdev)
{
	platform_device_del(pdev);
	platform_device_put(pdev);
}

 
三.プラットフォーム駆動
   1.プラットフォーム駆動構造体
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;	//     id 
};

 
    2.プラットフォームドライバ登録
int platform_driver_register(struct platform_driver *drv)
{
	drv->driver.bus = &platform_bus_type;	//          
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;	//  probe  
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;	//  remove  
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;	//  shutdown  

	return driver_register(&drv->driver);	//      
}

    2.1 platform_drv_probe
static int platform_drv_probe(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);	//            
	struct platform_device *dev = to_platform_device(_dev);	//            

	return drv->probe(dev);	//       probe  
}

    2.2 platform_drv_remove
static int platform_drv_remove(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);	//            
	struct platform_device *dev = to_platform_device(_dev);	//            

	return drv->remove(dev);	//       remove  
}

 
    2.3 platform_drv_shutdown
static void platform_drv_shutdown(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);	//            
	struct platform_device *dev = to_platform_device(_dev);	//            

	drv->shutdown(dev);	//       shutdown  
}

 
2.4プラットフォーム駆動は対応する駆動ディレクトリの下に置く
プラットフォーム駆動とプラットフォーム設備のnameドメインは、プラットフォームバスにmatchをマッチングするために同じであるべきであり、プラットフォーム駆動のprobeメソッドを呼び出す.
プラットフォームリソースの取得は一般的にprobeメソッドに置かれ、platform_を使用する.get_义齿
 
2.5上記プラットフォーム駆動登録方式は、ホットスワップ対応機器用platform_driver_probe登録
int __init_or_module platform_driver_probe(struct platform_driver *drv,int (*probe)(struct platform_device *))
{
	int retval, code;

	/* make sure driver won't have bind/unbind attributes */
	drv->driver.suppress_bind_attrs = true;

	/* temporary section violation during probe() */
	drv->probe = probe;	//   probe          probe  ,                     probe 
	retval = code = platform_driver_register(drv);

	/*
	 * Fixup that section violation, being paranoid about code scanning
	 * the list of drivers in order to probe new devices.  Check to see
	 * if the probe was successful, and make sure any forced probes of
	 * new devices fail.
	 */
	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
	drv->probe = NULL;
	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
		retval = -ENODEV;
	drv->driver.probe = platform_drv_probe_fail;
	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);

	if (code != retval)
		platform_driver_unregister(drv);
	return retval;
}

 
    3. プラットフォーム駆動ログアウト
void platform_driver_unregister(struct platform_driver *drv)
{
	driver_unregister(&drv->driver);
}

四.プラットフォームリソース
   1.しげんこうぞうたい
struct resource {
	resource_size_t start;	//        
	resource_size_t end;	//        
	const char *name;		//   
	unsigned long flags;	//    
	struct resource *parent, *sibling, *child;
};

1.1一般的なリソースのタイプは次のとおりです.
#define IORESOURCE_IO		0x00000100		//io  
#define IORESOURCE_MEM		0x00000200		//    
#define IORESOURCE_IRQ		0x00000400		//    

1.2プラットフォーム資源の取得パラメータは:資源が所属するプラットフォーム設備、資源を取得するタイプ、取得した資源個数
struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num)
{
	int i;

	for (i = 0; i < dev->num_resources; i++) {
		struct resource *r = &dev->resource[i];

		if (type == resource_type(r) && num-- == 0)
			return r;
	}
	return NULL;
}