`
20386053
  • 浏览: 461897 次
文章分类
社区版块
存档分类
最新评论

platform device和platform driver

 
阅读更多

从Linux 2.6起引入了一套新的驱动管理和注册机制:Platform_device和Platform_driver。

Linux中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device表示,驱动用Platform_driver进行注册。


Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。


Platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。

通过Platform机制开发发底层驱动的大致流程为: 定义 platform_add_devices注册 platform_device,定义 platform_add_driver注册 platform_driver。

1、platform_device注册过程:


首先要确认的就是设备的资源信息,例如设备的地址,中断号等。

在2.6内核中platform设备用结构体platform_device来描述,该结构体定义在kernel\include\linux\platform_device.h中,

struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
struct platform_device_id *id_entry;
};

该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel\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;
};

下面举s3c6410平台的i2c驱动作为例子来说明:

static struct platform_device *smdk6410_devices[] __initdata = {
#ifdef CONFIG_SMDK6410_SD_CH0
&s3c_device_hsmmc0,
#endif
#ifdef CONFIG_SMDK6410_SD_CH1
&s3c_device_hsmmc1,
#endif
&s3c_device_i2c0,
&s3c_device_i2c1,
&s3c_device_fb,
&s3c_device_usb,
&s3c_device_usb_hsotg,
&smdk6410_lcd_powerdev,

&smdk6410_smsc911x,
};
把一个或几个设备资源放在一起,便于集中管理,其中IIC设备
platform_device如下:
struct platform_device s3c_device_i2c0 = {
.name = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
.id = 0,
#else
.id = -1,
#endif
.num_resources = ARRAY_SIZE(s3c_i2c_resource),
.resource = s3c_i2c_resource,
};
具体resource如下:
static struct resource s3c_i2c_resource[] = {
[0] = {
.start = S3C_PA_IIC,
.end = S3C_PA_IIC + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_IIC,
.end = IRQ_IIC,
.flags = IORESOURCE_IRQ,
},
};

这里定义了两组resource,它描述了一个I2C设备的资源,第1组描述了这个I2C设备所占用的总线地址范围,IORESOURCE_MEM表示第1组描述的是内存类型的资源信息,第2组描述了这个I2C设备的中断号,IORESOURCE_IRQ表示第2组描述的是中断资源信息。设备驱动会根据flags来获取相应的资源信息。


定义好了platform_device结构体后就可以调用函数platform_add_devices向系统中添加该设备了,之后可以调用platform_driver_register()进行设备注册。

s3c6410-i2c的platform_device是在系统启动时,在mach-smdk6410.c里的smdk6410_machine_init()函数里进行注册的,这个函数申明为arch_initcall的函数调用,arch_initcall的优先级高于module_init。所以会在Platform驱动注册之前调用。(详细参考imach-smdk6410.c)


static void __init smdk6410_machine_init(void)
{
s3c_i2c0_set_platdata(NULL);
s3c_i2c1_set_platdata(NULL);
s3c_fb_set_platdata(&smdk6410_lcd_pdata);

gpio_request(S3C64XX_GPN(5), "LCD power");
gpio_request(S3C64XX_GPF(13), "LCD power");
gpio_request(S3C64XX_GPF(15), "LCD power");

i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
//添加多设备

}
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]);
if (ret) {
while (--i >= 0)
platform_device_unregister(devs[i]);
break;
}
}

return ret;
}
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
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);//如果有id 表示有多个同类设备用
pdev->name和pdev->id标识该设备
else
dev_set_name(&pdev->dev, "%s", pdev->name);
//否则,只用
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;
// 作为IOMEM资源分配
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
// 作为IOPORT资源分配
}

if (p && insert_resource(p, r)) {
//将新的resource插入内核resource tree
printk(KERN_ERR
"%s: failed to claim resource %d\n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}

pr_debug("Registering platform device '%s'. Parent at %s\n",
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;
}

PS:smdk6410_machine_init-->platform_add_devices-->platform_device_register-->platform_device_add

1、platform_driver注册过程:


在platform_device注册完成后,就可以进行platform_driver注册了,在驱动初始化函数中调用函数platform_driver_register()注册platform_driver,需要注意的是s3c_device_i2c结构中name元素和s3c6410_i2c_driver结构中driver.name必须是相同的,这样在platform_driver_register()注册时会对所有已注册的所有platform_device中的name和当前注册的platform_driver的driver.name进行比较,只有找到相同的名称的platfomr_device才能注册成功。

static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.suspend_late = s3c24xx_i2c_suspend_late,
.resume = s3c24xx_i2c_resume,
.id_table = s3c24xx_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
},
};

static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);//注册IIC驱动
}

nt platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;

return driver_register(&drv->driver);
}

int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;

BUG_ON(!drv->bus->p);

if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);

other = driver_find(drv->name, drv->bus);//检查Driver是否已经存在
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
//若不存在,则添加驱动到驱动树。
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;

bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;

pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;

if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);

error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}

kobject_uevent(&priv->kobj, KOBJ_ADD);
return 0;
out_unregister:
kfree(drv->p);
drv->p = NULL;
kobject_put(&priv->kobj);
out_put_bus:
bus_put(bus);
return error;
}



分享到:
评论

相关推荐

    Linux Platform Device and Driver

    ### Linux Platform Device 和 Driver #### 一、概述 在Linux内核中,为了更好地管理和注册设备及其对应的驱动程序,从2.6版本开始引入了一种新的机制——Platform Device和Platform Driver。这种机制不仅简化了...

    Linux设备管理机制PlatForm

    在Linux内核中,为了更好地管理和组织设备与对应的驱动程序,从2.6版本开始引入了一种新的管理机制——Platform Device和Platform Driver模型。这一机制极大地提高了系统的灵活性、可移植性和可扩展性。本文将通过...

    Linux 设备模型

    此外,还有`struct platform_device_id`用于匹配设备ID,以及一系列的注册、注销、资源管理和设备操作函数,如`platform_register_device()`、`platform_unregister_device()`、`platform_driver_register()`和`...

    Platform driver&device.pptx

    以下将详细阐述平台驱动(Platform Driver)和平台设备(Platform Device)的概念、结构以及它们在Linux内核中的工作原理。 平台驱动(Platform Driver): 平台驱动是针对特定硬件平台设计的,它负责初始化、配置...

    Linux嵌入式platform设备模块modules_platform_device

    标题"Linux嵌入式platform设备模块modules_platform_device"所指的,就是与Linux内核中的平台设备和与其相关的模块打交道的方法。平台设备驱动(Platform Driver)则是实现这一模型的软件组件,它负责与平台设备进行...

    详解Linux2.6内核中基于platform机制的驱动模型

    首先介绍了Platform总线的基本概念,接着介绍了platform device和platform driver的定义和加载过程,分析了其与基类device 和driver的派生关系及在此过程中面向对象的设计思想。最后以ARM S3C2440中I2C控制器为例...

    Linux 设备模型浅析之驱动篇.pdf

    - **Platform Bus Type**:定义了Platform Device和Platform Driver之间如何进行关联和通信的规则。 #### 三、S3C2410 RTC 驱动分析 以S3C2410 RTC(实时时钟)为例,我们来看看平台驱动的注册过程。在`drivers/...

    linux device driver platform

    platform linux 嵌入式 ARM, S2C2440, driver

    基于platform总线的驱动模型

    - **Bus**:是连接Device和Driver的桥梁,它定义了Device和Driver之间的交互规则。 - **Device**:代表具体的硬件实体或一组硬件资源,通过Bus连接到Driver。 - **Driver**:负责控制Device的行为,通过Bus与Device...

    Linux内核中Platform平台设备注册流程

    通过定义和注册`platform_device`与`platform_driver`,内核能够自动发现和管理硬件设备,大大简化了设备驱动的开发过程。这一机制不仅提高了设备驱动的可移植性和可维护性,也增强了内核的灵活性和扩展性。

    platform机制的驱动模型

    3. **Device Driver和Platform Driver** `device_driver`是驱动程序的抽象,它定义了驱动程序的行为。`platform_driver`是针对Platform Bus的设备驱动,提供了驱动程序的初始化、匹配、操作等接口。驱动注册通常...

    linux 设备驱动模型platform driver与driver

    根据源码分析整理的linux platfom driver与device driver的关系,对初学者有较大的帮助

    SD驱动分析研究

    `platform_driver` 是与`platform_device`相对应的驱动程序结构,它包含了与特定设备交互所需的函数指针和其他相关信息。`platform_driver`用于注册和注销设备驱动,并通过回调函数与对应的`platform_device`实例...

    platform-driver-analysis.rar_platform总线

    1. 设备描述:在platform总线中,每个设备都有一个platform_device结构体,它包含了设备的唯一标识符(如名称和ID)、资源描述(如内存映射和中断号)以及设备属性(用于传递固件信息)。 2. 驱动注册:对应的驱动...

    Linux嵌入式platform驱动模块modules_platform_dirver

    在嵌入式系统中,`modules_platform_driver`尤其重要,因为它允许开发人员快速适配各种不同的硬件平台,减少了代码复用和移植的工作量。配合博客文章《Linux嵌入式platform驱动模块modules_platform_dirver》...

    linux platform机制详解

    该机制由 Platform_device 和 Platform_driver 两部分组成,提供了一种标准的接口用于驱动程序和资源管理。 Platform 机制的优势 相比传统的 Device_driver 机制,Platform 机制有以下几个优势: 1. 资源注册:...

    linux platform总线驱动开发实例

    平台驱动通常包含设备描述结构体(platform_device)和驱动描述结构体(platform_driver)。前者用于描述硬件设备,后者包含匹配设备的函数和操作集。 4. **驱动注册与注销** - `platform_driver_register()`函数...

    plat_device.rar_platform 驱动_platform设备

    在Linux中,平台设备驱动注册到名为`platform_driver`的结构体,并通过`platform_add_devices()`函数添加到系统中。驱动通常包括以下关键部分: 1. **探测函数**(probe):当内核发现匹配的平台设备时,会调用该...

    OpenCL开发流程,platform/devices/context概念澄清

    - **Platform**:OpenCL平台是硬件和软件的抽象,它包含了OpenCL实现的所有组件,如设备驱动、OpenCL ICD(Installable Client Driver)和运行时库。开发者可以通过平台来访问不同的硬件设备。 - **Devices**:设备...

    Linux 驱动PlatForm平台总线详解

    platform_driver 结构体定义在文件 include/linux/platform_device.h 中。 Platform 驱动的注册使用 platform_driver_register 函数来实现,而卸载则使用 platform_driver_unregister 函数。编写 Platform 驱动的...

Global site tag (gtag.js) - Google Analytics