一. 平台总线
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; }