Linux设备驱动模型探究--3(device)



三.设备(device)

/***系统中的每个设备都是一个struct device对象,内核为容纳所有这些设备定义了一个kset-->devices_kset,
****作为系统中所有struct device类型内核对象的容器,内核将系统中的设备分为两大类:block和char
****每一个类对应内核对象,分别为sysfs_dev_block_kobj和sysfs_dev_char_kobj,
****block和char内核对象的上级内核对象为dev_kobj,
*/

/*设备结构*/
struct device {
 struct device  *parent; /*当前设备的父设备*/

 struct device_private *p;  /*structure to hold the private to the driver core portions of the device structure*/
         /*指向设备驱动相关的数据*/

 struct kobject kobj;   /*内核对象*/
 const char  *init_name; /* initial name of the device,内核会把init_name设置成kobj成员的名称,表项为一个目录 */
 struct device_type *type;

 struct bus_type *bus;  /* type of bus device is on */
 struct device_driver *driver; /* which driver has allocated this
        device */
 void  *platform_data; /* Platform specific data, device
            core doesn't touch it */

 dev_t   devt; /* dev_t, creates the sysfs "dev" */

 struct class  *class;

};

/*设备初始化--*/
void device_initialize(struct device *dev)

 dev->kobj.kset = devices_kset;    ////devices_kset 在devices_init 中初始化
 kobject_init(&dev->kobj, &device_ktype); //kobj_type定义了一组sysfs文件系统相关的操作函数和属性
 mutex_init(&dev->mutex);
}

/*注册设备*/
int device_register(struct device *dev)
{
 device_initialize(dev); 
 return device_add(dev);
}

/*注册核心函数*/
int device_add(struct device *dev)
{
 struct device *parent = NULL;
 struct class_interface *class_intf;
 int error = -EINVAL;

 dev = get_device(dev);
 if (!dev)
  goto done;

 if (dev->init_name) {
  dev_set_name(dev, "%s", dev->init_name);
  dev->init_name = NULL;      ////
 }

 if (!dev_name(dev)) {
  error = -EINVAL;
  goto name_error;
 }

 pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

 parent = get_device(dev->parent);
 setup_parent(dev, parent);

 /* first, register with generic layer. */
 /* we require the name to be set before, and pass NULL */
 error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//-->1.建立kobject对象间层次关系,2.在sysfs文件系统中建立一个目录
 if (error)
  goto Error;

 error = device_create_file(dev, &uevent_attr);  //为dev->kobject建立属性文件uevent_attr
 if (error)
  goto attrError;

 if (MAJOR(dev->devt)) {       //如果设备号不为空,就创建设备文件dev
  error = device_create_file(dev, &devt_attr);//为dev->kobject建立属性文件devt_attr
  if (error)
   goto ueventattrError;

  error = device_create_sys_dev_entry(dev);//create symlink between two objects(dev->koobj && dev->class->dev_kobj or sysfs_dev_char_kobj;)
  if (error)
   goto devtattrError;

  devtmpfs_create_node(dev);    //在dev 目录文件下生成设备节点
 }
/*建立符号链接
 * sysfs_create_link - create symlink between two objects.
 * @kobj: object whose directory we're creating the link in.
 * @target: object we're pointing to.
 * @name:  name of the symlink.
 *int sysfs_create_link(struct kobject *kobj, struct kobject *target, const char *name)
 *{
******return sysfs_do_create_link(kobj, target, name, 1);
 *}
**/
 error = device_add_class_symlinks(dev);  //建立符号链接,主要是class中的内核对象和dev中的内核对象
 if (error)
  goto SymlinkError;
  
 error = device_add_attrs(dev);  /*创建设备属性文件*/
 
 if (error)
  goto AttrsError;
/**
 * bus_add_device - add device to bus
 * @dev: device being added
 *
 * - Add device's bus attributes.
 * - Create links to device's bus.
 * - Add the device to its bus's list of devices.
 *----struct device_private(重点操作对象)
**/
 error = bus_add_device(dev);
 

 error = dpm_sysfs_add(dev);
 
/**
 * device_pm_add - Add a device to the PM core's list of active devices.
 * @dev: Device to add to the list.
**/
 device_pm_add(dev);

/* Notify clients of device addition.  This call must come
 * after dpm_sysf_add() and before kobject_uevent().
**/
 if (dev->bus)
  blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
          BUS_NOTIFY_ADD_DEVICE, dev);

/**
 * kobject_uevent - notify userspace by sending an uevent
 *
 * @action: action that is happening
 * @kobj: struct kobject that the action is happening to
**/
 ---kobject_uevent(&dev->kobj, KOBJ_ADD);  
  
/**
 * bus_probe_device - probe drivers for a new device
 * @dev: device to probe
 * 
 * - Automatically probe for a driver if the bus allows it.
 
 *-->priv->drivers_autoprobe = 1;-->bus_register()
**/
 ---bus_probe_device(dev);     
 
 if (parent)
  klist_add_tail(&dev->p->knode_parent,
          &parent->p->klist_children);  /*和父内核对象建立联系*/


 if (dev->class) {        /*添加到设备类中*/
  mutex_lock(&dev->class->p->class_mutex);
  /* tie the class to the device */
  klist_add_tail(&dev->knode_class,
          &dev->class->p->klist_devices);

  /* notify any interfaces that the device is here */
  list_for_each_entry(class_intf,
        &dev->class->p->class_interfaces, node)
   if (class_intf->add_dev)
    class_intf->add_dev(dev, class_intf);
  mutex_unlock(&dev->class->p->class_mutex);
 }
}  

/**************************************关于class类*****************************/

/**关于class(device classes)--相对于设备device,class是一种更高层次的抽象,
用于对设备进行功能上的划分,有时候也被称为设备类。
linux设备模型引入类class,是将其用来作为具有同类型功能设备的一个容器.
*/
struct class {
 const char  *name;   /*设备类名字*/
 struct module  *owner;  /*拥有该类的模块的指针*/

 struct class_attribute  *class_attrs; /*类的属性*/
 struct device_attribute  *dev_attrs;  /*设备的属性*/
 struct bin_attribute  *dev_bin_attrs; /*struct bin_attribute在struct attribute的基础上,
            /*增加了read、write等函数,因此它所生成的sysfs文件可以用任何方式读写*/ 
 
 struct kobject   *dev_kobj;   /*设备的内核对象*/
 
 struct subsys_private *p;    /*类的私有数据--->bus的私有数据*/
};
**/

在系统初始化期间,调用class_init() 产生类的顶层kset-->class_kset--->/sys/class/
int __init classes_init(void)
{
 class_kset = kset_create_and_add("class", NULL, NULL);
 if (!class_kset)
  return -ENOMEM;
 return 0;
}
  
常用操作:
/*用来创建设备类,并添加到/sys/class/目录下*/
struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key);

/*销毁设备类*/
void class_destroy(struct class *cls);


/****************************关于设备的创建*************************************/

/*创建设备-->在驱动中通常被屏蔽*/  --->创建设备-->注册设备
struct device *device_create(struct class *class, struct device *parent,
        dev_t devt, void *drvdata, const char *fmt, ...)

--->struct device *device_create_vargs(struct class *class, struct device *parent,
       dev_t devt, void *drvdata, const char *fmt,
       va_list args)
{
 dev = kzalloc(sizeof(*dev), GFP_KERNEL);

 dev->devt = devt;
 dev->class = class;  /*指明设备所在的类*/
 dev->parent = parent;
 dev->release = device_create_release;
 dev_set_drvdata(dev, drvdata);
 retval = kobject_set_name_vargs(&dev->kobj, fmt, args);


 retval = device_register(dev); /*注册设备*/

 return dev;
}

/*销毁设备*/
void device_destroy(struct class *class, dev_t devt)
{
 struct device *dev;

 dev = class_find_device(class, NULL, &devt, __match_devt);/*通过class设备类找到dev*/
 if (dev) {
  put_device(dev);
  device_unregister(dev);   /*销毁设备*/
 }
}

猜你喜欢

转载自blog.csdn.net/jun_8018/article/details/77577853
今日推荐