/**
* uclass_add() - Create new uclass in list
* @id: Id number to create
* @ucp: Returns pointer to uclass, or NULL on error
* @return 0 on success, -ve on error
*
* The new uclass is added to the list. There must be only one uclass for
* each id.
*/
static int uclass_add(enum uclass_id id, struct uclass **ucp)
{
struct uclass_driver *uc_drv;
struct uclass *uc;
int ret;
*ucp = NULL;
//查找驱动程序是否存在
uc_drv = lists_uclass_lookup(id);
if (!uc_drv) {
debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
id);
/*
* Use a strange error to make this case easier to find. When
* a uclass is not available it can prevent driver model from
* starting up and this failure is otherwise hard to debug.
*/
return -EPFNOSUPPORT;
}
//分配空间给uclass
/**
* struct uclass - a U-Boot drive class, collecting together similar drivers
*
* A uclass provides an interface to a particular function, which is
* implemented by one or more drivers. Every driver belongs to a uclass even
* if it is the only driver in that uclass. An example uclass is GPIO, which
* provides the ability to change read inputs, set and clear outputs, etc.
* There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and
* PMIC IO lines, all made available in a unified way through the uclass.
*
* @priv_: Private data for this uclass (do not access outside driver model)
* @uc_drv: The driver for the uclass itself, not to be confused with a
* 'struct driver'
* @dev_head: List of devices in this uclass (devices are attached to their
* uclass when their bind method is called)
* @sibling_node: Next uclass in the linked list of uclasses
*/
struct uclass {
void *priv_;
struct uclass_driver *uc_drv;
struct list_head dev_head;
struct list_head sibling_node;
};
uc = calloc(1, sizeof(*uc));
if (!uc)
return -ENOMEM;
//驱动程序的私有数据是否存在,添加priv_.
if (uc_drv->priv_auto) {
void *ptr;
ptr = calloc(1, uc_drv->priv_auto);
if (!ptr) {
ret = -ENOMEM;
goto fail_mem;
}
uclass_set_priv(uc, ptr);
}
//设置uclass的驱动程序
uc->uc_drv = uc_drv;
//建立uclass链表
INIT_LIST_HEAD(&uc->sibling_node);
INIT_LIST_HEAD(&uc->dev_head);
list_add(&uc->sibling_node, DM_UCLASS_ROOT_NON_CONST);
//调用uclass driver驱动程序的初始化,函数的输入参数为uclass指针
if (uc_drv->init) {
ret = uc_drv->init(uc);
if (ret)
goto fail;
}
//返回分配的uclass
*ucp = uc;
return 0;
//失败处理
fail:
if (uc_drv->priv_auto) {
free(uclass_get_priv(uc));
uclass_set_priv(uc, NULL);
}
list_del(&uc->sibling_node);
fail_mem:
free(uc);
return ret;
}
/**
* struct uclass_driver - Driver for the uclass
*
* A uclass_driver provides a consistent interface to a set of related
* drivers.
*
* @name: Name of uclass driver
* @id: ID number of this uclass
* @post_bind: Called after a new device is bound to this uclass
* @pre_unbind: Called before a device is unbound from this uclass
* @pre_probe: Called before a new device is probed
* @post_probe: Called after a new device is probed
* @pre_remove: Called before a device is removed
* @child_post_bind: Called after a child is bound to a device in this uclass
* @child_pre_probe: Called before a child in this uclass is probed
* @child_post_probe: Called after a child in this uclass is probed
* @init: Called to set up the uclass
* @destroy: Called to destroy the uclass
* @priv_auto: If non-zero this is the size of the private data
* to be allocated in the uclass's ->priv pointer. If zero, then the uclass
* driver is responsible for allocating any data required.
* @per_device_auto: Each device can hold private data owned
* by the uclass. If required this will be automatically allocated if this
* value is non-zero.
* @per_device_plat_auto: Each device can hold platform data
* owned by the uclass as 'dev->uclass_plat'. If the value is non-zero,
* then this will be automatically allocated.
* @per_child_auto: Each child device (of a parent in this
* uclass) can hold parent data for the device/uclass. This value is only
* used as a fallback if this member is 0 in the driver.
* @per_child_plat_auto: A bus likes to store information about
* its children. If non-zero this is the size of this data, to be allocated
* in the child device's parent_plat pointer. This value is only used as
* a fallback if this member is 0 in the driver.
* @flags: Flags for this uclass (DM_UC_...)
*/
struct uclass_driver {
const char *name;
enum uclass_id id;
int (*post_bind)(struct udevice *dev);
int (*pre_unbind)(struct udevice *dev);
int (*pre_probe)(struct udevice *dev);
int (*post_probe)(struct udevice *dev);
int (*pre_remove)(struct udevice *dev);
int (*child_post_bind)(struct udevice *dev);
int (*child_pre_probe)(struct udevice *dev);
int (*child_post_probe)(struct udevice *dev);
int (*init)(struct uclass *class);
int (*destroy)(struct uclass *class);
int priv_auto;
int per_device_auto;
int per_device_plat_auto;
int per_child_auto;
int per_child_plat_auto;
uint32_t flags;
};