linux内核建模,linux内核驱动模型

int device_register(struct device *dev)

{

device_initialize(dev);

return device_add(dev);

}

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);

}

int device_add(struct device *dev)

{

struct device *parent = NULL;

struct class_interface *class_intf;

int error = -EINVAL;

dev = get_device(dev);

if (!dev || !strlen(dev->bus_id))

goto Error;

pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);

parent = get_device(dev->parent);

error = setup_parent(dev, parent);

if (error)

goto Error;

/* first, register with generic layer. */

kobject_set_name(&dev->kobj, "%s", dev->bus_id);

error = kobject_add(&dev->kobj);

if (error)

goto Error;

/* notify platform of device entry */

if (platform_notify)

platform_notify(dev);

/* notify clients of device entry (new way) */

if (dev->bus)

blocking_notifier_call_chain(&dev->bus->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;

}

error = device_add_class_symlinks(dev);

if (error)

goto SymlinkError;

//创建所属class,kobject_type,以及device本身自带的属性文件

error = device_add_attrs(dev);

if (error)

goto AttrsError;

//创建电源管理子目录power

error = dpm_sysfs_add(dev);

if (error)

goto PMError;

//将该设备挂接到电源链表下

device_pm_add(dev);

//将该dev添加到bus

error = bus_add_device(dev);

if (error)

goto BusError;

kobject_uevent(&dev->kobj, KOBJ_ADD); //发送一个uevent事件到用户空间,实现热插拔

bus_attach_device(dev); //自动匹配设备和驱动

if (parent)

klist_add_tail(&dev->knode_parent, &parent->klist_children);

if (dev->class) {

down(&dev->class->sem);

/* tie the class to the device */

list_add_tail(&dev->node, &dev->class->devices);

/* notify any interfaces that the device is here */

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;

BusError:

device_pm_remove(dev);

dpm_sysfs_remove(dev);

PMError:

if (dev->bus)

blocking_notifier_call_chain(&dev->bus->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);

if (dev->class) {

sysfs_remove_link(&dev->kobj, "subsystem");

/* If this is not a "fake" compatible device, remove the

* symlink from the class to the device. */

if (dev->kobj.parent != &dev->class->subsys.kobj)

sysfs_remove_link(&dev->class->subsys.kobj,

dev->bus_id);

if (parent) {

#ifdef CONFIG_SYSFS_DEPRECATED

char *class_name = make_class_name(dev->class->name,

&dev->kobj);

if (class_name)

sysfs_remove_link(&dev->parent->kobj,

class_name);

kfree(class_name);

#endif

sysfs_remove_link(&dev->kobj, "device");

}

}

ueventattrError:

device_remove_file(dev, &uevent_attr);

attrError:

kobject_uevent(&dev->kobj, KOBJ_REMOVE);

kobject_del(&dev->kobj);

Error:

if (parent)

put_device(parent);

goto Done;

}

void bus_attach_device(struct device * dev)

{

struct bus_type *bus = dev->bus;

int ret = 0;

if (bus) {

dev->is_registered = 1;

//如果总线自动探测设备,则进行设备驱动匹配。(可以通过bus下的autoprobe属性文件查看和修改是否支持自动探测)

if (bus->drivers_autoprobe)

ret = device_attach(dev);

WARN_ON(ret < 0);

if (ret >= 0)

klist_add_tail(&dev->knode_bus, &bus->klist_devices);

else

dev->is_registered = 0;

}

}

int device_attach(struct device * dev)

{

int ret = 0;

down(&dev->sem);

if (dev->driver) {

ret = device_bind_driver(dev);

if (ret == 0)

ret = 1;

else {

dev->driver = NULL;

ret = 0;

}

} else {

//将设备和该总线上的所有驱动进行匹配

ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

}

up(&dev->sem);

return ret;

}

static int __device_attach(struct device_driver * drv, void * data)

{

struct device * dev = data;

return driver_probe_device(drv, dev);

}

int driver_probe_device(struct device_driver * drv, struct device * dev)

{

int ret = 0;

if (!device_is_registered(dev))

return -ENODEV;

//首先调用总线的match方法进行匹配

if (drv->bus->match && !drv->bus->match(dev, drv))

goto done;

pr_debug("%s: Matched Device %s with Driver %s\n",

drv->bus->name, dev->bus_id, drv->name);

//调用总线或者驱动的probe方法继续进一步的匹配。

ret = really_probe(dev, drv);

done:

return ret;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值