Linux平台设备驱动(1)

首先来解释下平台设备驱动所涉及的一些结构:

struct resource {
	resource_size_t start;  //该平台设备所占用的资源起始地址
	resource_size_t end;    //结束地址
	const char *name;       //名字
	unsigned long flags;    //资源类型
	struct resource *parent, *sibling, *child;
};

struct platform_device {
	const char	* name;      //该平台设备的名字
	int		id;          //该平台设备的编号
	struct device	dev;
	u32		num_resources; 
	struct resource	* resource;  //占用的资源


	struct platform_device_id	*id_entry;

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

平台设备驱动用platform_device表示平台设备,用platform_add_devices注册平台设备;用platform_driver表示平台驱动,用platform_add_devices注册平台驱动。在Linux设备驱动模型中有三个关键元素:总线-设备-驱动。将设备和驱动挂载在platform这个虚拟的总线上,当挂载在总线的设备和驱动匹配时就会调用probe方法,那设备和驱动根据什么进行匹配呢?回答这个问题前先看看内核中的看门狗设备驱动的代码。

static struct resource s3c_wdt_resource[] = {
	[0] = {
		.start = S3C24XX_PA_WATCHDOG,   //看门狗的启示地址为0x53000000;
		.end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,//结束地址0x53100000-1;
		.flags = IORESOURCE_MEM,              //资源类型为IO内存
	},
	[1] = {
		.start = IRQ_WDT,            //这段没看懂
		.end   = IRQ_WDT,
		.flags = IORESOURCE_IRQ,
	}

};

struct platform_device s3c_device_wdt = {
	.name		  = "s3c2410-wdt",     //这是设备和驱动匹配的依据
	.id		  = -1,               //id为-1表示只有一个这样的设备
	.num_resources	  = ARRAY_SIZE(s3c_wdt_resource),
	.resource	  = s3c_wdt_resource,
};

static struct platform_device *smdk2440_devices[] __initdata = {
	&s3c_device_usb,
	&s3c_device_lcd,
	&s3c_device_wdt,    //这个结构数组将各种platform设备的地址放在数组中;
	&s3c_device_i2c0,   //可以看出lcd,iis,iic等设备都挂载在platform总线上的;
	&s3c_device_iis,
};

static void __init smdk2440_machine_init(void)
{
	s3c24xx_fb_set_platdata(&smdk2440_fb_info);
	s3c_i2c0_set_platdata(NULL);

	platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  //从数组中取出各个平台设备结构的地址,
                                                                //  将平台设备注册进platform总线;
	smdk_machine_init();
}

以上代码注册了看门狗的platform设备,接下来注册驱动;

static struct platform_driver s3c2410wdt_driver = {
	.probe		= s3c2410wdt_probe,//设备和驱动匹配后会调用probe方法;
	.remove		= __devexit_p(s3c2410wdt_remove),
	.shutdown	= s3c2410wdt_shutdown,
	.suspend	= s3c2410wdt_suspend,
	.resume		= s3c2410wdt_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2410-wdt",   //这个name和platform_device的name一致即可将设备和驱动匹配起来
	},
};

static int __init watchdog_init(void)
{
	printk(banner);
	return platform_driver_register(&s3c2410wdt_driver);  //注册platform_driver;
}
 

static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
{
//在probe方法里进行对看门狗的操作。
//在内核中这段代码很长啊,没看懂, 没贴出来。
}


总结:

在平台设备驱动中,总线将设备和驱动绑在一起,系统每注册一个设备的时候,会寻找和它匹配的驱动,相反的,系统每注册一个驱动的时候会寻找和它匹配的设备,匹配的工作是由总线来完成的,匹配的依据多种多样,这里是匹配设备和驱动的name,在其它总线中(usb总线、i2c总线、pci总线等)有其它匹配方法。platform总线是Linux中的一种虚拟的总线,从2.6的内核版本开始引入,这种设备驱动模型思想遍布内核的每个角落。片上系统的资源如lcd、watchdog、rtc等都被当作平台设备来处理,platform机制的优点是将资源注册进内核,由内核统一管理,驱动程序中要使用这些资源时通过platform_device中提供的统一接口进行访问,这样驱动和资源相对独立了,提高了可移植性和安全性。对platform驱动的理解还不是很透彻,我想将led的驱动注册进platform总线中试试,哈哈。

                                                                                                                                                       ----征途开始

                                                                                                                                                          2013.8.5晚



猜你喜欢

转载自blog.csdn.net/xieshangjian/article/details/9771507
今日推荐