在platform模型设备的建立中,需要2个部分的注册,驱动的注册和设备的注册
platform_device_register(&test_device);
platform_driver_register(&test_driver);
首先看platform_device_register
注册参数为test_device,结构如下
static struct platform_device test_device = {
.name = "test_ts",
.id = -1,
//. resource
//.dev
};
这个结构主要描述了设备的名字,ID和资源和私有数据,其中资源和私有数据我们在这里不使用,将在别的文章中进行讲解
int platform_device_register(struct platform_device *pdev)
{
//设备属性的初始化
device_initialize(&pdev->dev);
//将设备添加进platform里
return platform_device_add(pdev);
}
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset; //设置kset为devices_kset,则将设备挂接上了devices目录
kobject_init(&dev->kobj, &device_ktype); //初始化kobeject,置ktype为device_ktype
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);
}
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
//检测是否设置了dev中的parent,无则赋为platform_bus
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
//设置dev中的bus为platform_bus_type
pdev->dev.bus = &platform_bus_type;
//检测id,id为-1表明该设备只有一个,用设备名为bus_id
//不为1则表明该设备有数个,需要用序号标明bus_id
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
//增加资源到资源树中
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource;
if (r->name == NULL)
r->name = pdev->dev.bus_id;
p = r->parent;
if (!p) {
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.flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource);
return ret;
}
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error;
dev = get_device(dev);
if (!dev || !strlen(dev->bus_id)) {
error = -EINVAL;
goto Done;
}
pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
//取得上层device,而dev->parent的赋值是在platform_device_add中的pdev->dev.parent = &platform_bus完成的
parent = get_device(dev->parent);
//以上层devices为准重设dev->kobj.parent
setup_parent(dev, parent);
if (parent)
set_dev_node(dev, dev_to_node(parent));
//设置dev->kobj的名字和父对象,并建立相应目录
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
if (error)
goto Error;
if (platform_notify)
platform_notify(dev);
//一种新型的通知机制,但是platform中没有设置相应的结构,所以在这里跳过
/* notify clients of device entry (new way) */
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
//建立uevent文件
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
//设备有设备号则建立dev文件
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
}
//建立subsystem连接文件连接到所属class
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
//添加dev的描述文件
error = device_add_attrs(dev);
if (error)
goto AttrsError;
//添加链接文件至所属bus
error = bus_add_device(dev);
if (error)
goto BusError;
//添加power文件
error = device_pm_add(dev);
if (error)
goto PMError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
//检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,所以不会进行匹配
bus_attach_device(dev);
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
down(&dev->class->sem);
list_add_tail(&dev->node, &dev->class->devices);
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
Done:
put_device(dev);
return error;
PMError:
bus_remove_device(dev);
BusError:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
ueventattrError:
device_remove_file(dev, &uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
if (parent)
put_device(parent);
goto Done;
}
static void setup_parent(struct device *dev, struct device *parent)
{
struct kobject *kobj;
//取得上层device的kobj
kobj = get_device_parent(dev, parent);
//kobj不为空则重设dev->kobj.parent
if (kobj)
dev->kobj.parent = kobj;
}
static struct kobject *get_device_parent(struct device *dev,
struct device *parent)
{
int retval;
//因为dev->class为空,所以跳过这段代码
if (dev->class) {
struct kobject *kobj = NULL;
struct kobject *parent_kobj;
struct kobject *k;
if (parent == NULL)
parent_kobj = virtual_device_parent(dev);
else if (parent->class)
return &parent->kobj;
else
parent_kobj = &parent->kobj;
spin_lock(&dev->class->class_dirs.list_lock);
list_for_each_entry(k, &dev->class->class_dirs.list, entry)
if (k->parent == parent_kobj) {
kobj = kobject_get(k);
break;
}
spin_unlock(&dev->class->class_dirs.list_lock);
if (kobj)
return kobj;
k = kobject_create();
if (!k)
return NULL;
k->kset = &dev->class->class_dirs;
retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
if (retval < 0) {
kobject_put(k);
return NULL;
}
return k;
}
if (parent)
//返回上层device的kobj
return &parent->kobj;
return NULL;
}
在bus_attach_device中虽然没有成功进行匹配,但是有很重要的一步为之后正确的匹配打下基础
void bus_attach_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
int ret = 0;
if (bus) {
if (bus->p->drivers_autoprobe)
ret = device_attach(dev);
WARN_ON(ret < 0);
if (ret >= 0)
klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
}
}
klist_add_tail(&dev->knode_bus, &bus->p->klist_devices)就是这一行
在这一行代码中将设备挂载到了bus下的devices链表下,这样,当驱动请求匹配的时候,platform总线就会历遍devices链表为驱动寻找合适的设备
现在来看一下test_device的模型