一. 平台总线
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\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;
}
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_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]); //可以看到它只是多次调用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_resource获取
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;
}