1.platform_device结构体
struct platform_device {
const char * name;/* 设备名 */
u32 id;
struct device dev;
u32 num_resources;/* 设备所使用各类资源数量 */
struct resource * resource;/* 资源 */
};
设备的分配:
struct platform_device *platform_device_alloc(const char *name, int id); //name:设备名,id:设备
id,一般为-1
设备的注册:
int platform_device_add(struct platform_device *pdev);
对platform_device的定义通常在BSP的板文件中实现,在板文件中,将platform_device归纳
为一个数组:
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
};
最终通过 platform_add_devices()函数统一注册:
static void __init smdk2410_init(void)
{
s3c_i2c0_set_platdata(NULL);
platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
smdk_machine_init();
}
platform_add_devices()函数可以将平台设备添加到系统中,这个函数的 原型为:
int platform_add_devices(struct platform_device **devs, int num);
该函数的第一个参数为平台设备数组的指针,第二个参数为平台设备的数量,它内部调用了
platform_device_register()函 数用于注册单个的平台设备。
2.platform_driver包含具体的操作函数,通常需要由驱动实现:
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;
};
看看驱动是怎么注册进去的:
int platform_driver_register(struct platform_driver *drv)
{
。。。
return driver_register(&drv->driver);
}
int driver_register(struct device_driver *drv)
{
。。。。
ret = bus_add_driver(drv);
。。。
}
int bus_add_driver(struct device_driver *drv)
{
。。。
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
。。。
}
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
来看__driver_attach这个函数,其中分别调用了driver_match_device,driver_probe_device函数。
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
if (!driver_match_device(drv, dev))
return 0;
if (dev->parent)
down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev)
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
return 0;
}
匹配的时候调用的bus的match函数。匹配成功后调用驱动的probe函数。
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
。。。
ret = really_probe(dev, drv);
。。。
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
。。。
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
。。。
ret = really_probe(dev, drv);
。。。
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
。。。
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
。。。
}
由relly_probe函数可以看出,如果bus定义了probe函数,则调用bus的probe
函数;如果bus,没有定义而driver定义了probe函数,则调用driver的probe
函数。
3.bus_type类型的platform_bus_type
(1)基本结构
struct bus_type platform_bus_type = {
name = “platform”,
dev_attrs = platform_dev_attrs,
match = platform_match,
uevent = platform_uevent,
pm = PLATFORM_PM_OPS_PTR,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
(2)match()表明了platform_device和platform_driver之间如何匹配
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
匹配platform_device和platform_driver主要看二者的name字段是否相同
(3)总线初始化
platform_bus_type是在系统初始化的时候初始化的,不用我们做什么工作:
.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;
}
4.设备中的资源
flags可以为IORESOURCE_IO、 IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA等
static struct resource ldd6410_dm9000_resource[] = {
[0] = {
.start = 0×18000000,
.end = 0×18000000 + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = IRQ_EINT(7),
.end = IRQ_EINT(7),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}
};
获取资源:
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5.plat_data
对设备的硬件描述除了中断、内存、DMA通道以外,可能还会有一些配置信
息,而 这些配置信息也依赖于板,不适宜直接放置在设备驱动本身,因此,
platform也提供了platform_data的支持。例如:
static struct dm9000_plat_data ldd6410_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
.dev_addr = { 0×0, 0×16, 0xd4, 0×9f, 0xed, 0xa4 },
};
static struct platform_device ldd6410_dm9000 = {
.name = “dm9000″,
.id = 0,
.num_resources = ARRAY_SIZE(ldd6410_dm9000_resource),
.resource = ldd6410_dm9000_resource,
.dev = {
.platform_data = &ldd6410_dm9000_platdata,
}
};
获取plat_data:
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
其中,pdev为platform_device的指针。