device_register()和platform_device_register()的区别
首先看device和
platform_device区别
由struct platform_device {
const char * name;
//NOTE:此处设备的命名应和相应驱动程序命名一致
u32 id; //以实现driver
binding
struct device dev;
u32 num_resources;
struct
resource * resource;
};
可知:platform_device由device派生而来
内核中关于
Platform devices的注释
Platform devices
~~~~~~~~~~~~~~~~
Platform
devices are devices that typically appear as autonomous
entities in
the system. This includes legacy port-based devices and
host bridges
to peripheral buses, and most controllers integrated
into
system-on-chip platforms. What they usually have in common
is direct
addressing from a CPU bus. Rarely, a platform_device will
be
connected through a segment of some other kind of bus; but its
registers
will still be directly addressable.
Platform devices are given a
name, used in driver binding, and a
list of resources such as
addresses and IRQs.
个人理解:Platform devices是相对独立的设备,拥有各自独自的资源(addresses
and IRQs)
一个Platform devices实例:
static struct
platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb, //片上的各个设备
&s3c_device_lcd,
//下面以s3c_device_lcd为例
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};
/* LCD Controller */
static
struct resource s3c_lcd_resource[] = { //LCD的两个资源
[0] = {
.start = S3C2410_PA_LCD,
.end = S3C2410_PA_LCD +
S3C2410_SZ_LCD,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device s3c_device_lcd =
{//s3c_device_lcd设备
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev
= { //device实例
.dma_mask =
&s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
s3c_device_lcd
的resource中硬件地址:
#define S3C2410_LCDREG(x) ((x) + S3C2410_VA_LCD)
/*
LCD control registers */
#define S3C2410_LCDCON1
S3C2410_LCDREG(0x00)
#define S3C2410_LCDCON2 S3C2410_LCDREG(0x04)
#define
S3C2410_LCDCON3 S3C2410_LCDREG(0x08)
#define S3C2410_LCDCON4
S3C2410_LCDREG(0x0C)
#define S3C2410_LCDCON5
S3C2410_LCDREG(0x10)
#define S3C2410_LCDCON1_CLKVAL(x) ((x)
<< 8)
#define S3C2410_LCDCON1_MMODE (1<<7)
#define
S3C2410_LCDCON1_DSCAN4 (0<<5)
#define S3C2410_LCDCON1_STN4
(1<<5)
#define S3C2410_LCDCON1_STN8 (2<<5)
#define
S3C2410_LCDCON1_TFT (3<<5)
--------------------------
#define
S3C2410_ADDR(x) (0xF0000000 + (x))
/* LCD controller */
#define
S3C2410_VA_LCD S3C2410_ADDR(0x00600000)
#define S3C2410_PA_LCD
(0x4D000000)
#define S3C2410_SZ_LCD SZ_1M
再分析
device_register()和platform_device_register()的实现代码:
device_register()------------------------
/**
* device_register - register a device with the system.
* @dev:
pointer to the device structure
*
* This happens in two clean
steps - initialize the device
* and add it to the system. The two
steps can be called
* separately, but this is the easiest and most
common.
* I.e. you should only call the two helpers separately if
* have a clearly defined need to use and refcount the device
*
before it is added to the hierarchy.
*/
int
device_register(struct device *dev)
{
device_initialize(dev);
//初始化设备结构
return device_add(dev); //添加设备到设备层
}
platform_device_register()--------------------
/**
* platform_device_register - add a platform-level device
* @pdev:
platform device we're adding
*
*/
int
platform_device_register(struct platform_device * pdev)
{
device_initialize(&pdev->dev); //初始化设备结构
return
platform_device_add(pdev); //添加一个片上的设备到设备层
}
由以上函数可
知:device_register()和platform_device_register()都会首先初始化设备
区别在于第二步:其实
platform_device_add()包括device_add(),只不过要先注册resources
platform_device_add()----------------------
/**
* platform_device_add - add a platform device to device hierarchy
*
@pdev: platform device we're adding
*
* This is part 2 of
platform_device_register(), though may be called
* separately _iff_
pdev was allocated by platform_device_alloc().
*/
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;
/*++++++++++++++
The
platform_device.dev.bus_id is the canonical name for the devices.
It's built from two components:
* platform_device.name
... which is also used to for driver matching.
*
platform_device.id ... the device instance number, or else "-1"
to indicate there's only one.
These are concatenated,
so name/id "serial"/0 indicates bus_id "serial.0", and
"serial/3" indicates bus_id "serial.3"; both would use the
platform_driver
named "serial". While "my_rtc"/-1 would be
bus_id "my_rtc" (no instance id)
and use the platform_driver
called "my_rtc".
++++++++++++++*/
if (pdev->id !=
-1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u",
pdev->name, pdev->id);
else //"-1" indicate there's only one
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
for (i =
0; i < pdev->num_resources; i++) { //遍历设备资源个数,如LCD的两个资源:控制器和IRQ
struct resource *p, *r = &pdev->resource[i];
if
(r->name == NULL)
r->name = pdev->dev.bus_id;
p =
r->parent;
if (!p) { //resources分为两种
IORESOURCE_MEM和IORESOURCE_IO
//CPU对外设IO端口物理地址的编址方式有两种:I/O映射方式和内存映射方式
if
(r->flags & IORESOURCE_MEM)
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO)
p =
&ioport_resource;
}
if (p &&
insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed
to claim resource %d\n",
pdev->dev.bus_id, i);
ret
= -EBUSY;
goto failed;
}
}
pr_debug("Registering
platform device '%s'. Parent at %s\n",
pdev->dev.bus_id,
pdev->dev.parent->bus_id);
ret =
device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0)
if (pdev->resource[i].flags
& (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}
相
关参考+++++++++++++++++++++++
device_initialize()------------------
/**
<\drivers\base\core.c>
* device_initialize - init device
structure.
* @dev: device.
*
* This prepares the device for
use by other layers,
* including adding it to the device hierarchy.
* It is the first half of device_register(), if called by
* that,
though it can also be called separately, so one
* may use @dev's
fields (e.g. the refcount).
*/
void device_initialize(struct
device *dev)
{
kobj_set_kset_s(dev, devices_subsys);
kobject_init(&dev->kobj);
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev,
0);
set_dev_node(dev, -1);
}
device_add(struct device
*dev)-------------
/**
* device_add - add device to device
hierarchy.
* @dev: device.
*
* This is part 2 of
device_register(), though may be called
* separately _iff_
device_initialize() has been called separately.
*
* This adds it
to the kobject hierarchy via kobject_add(), adds it
* to the global
and sibling lists for the device, then
* adds it to the other
relevant subsystems of the driver model.
*/
结构体
resource----------------------
/* <
\include\linux\ioport.h>
* Resources are tree-like, allowing
*
nesting etc..
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
-----------------------------
阅读(1214) | 评论(0) | 转发(0) |