/** * 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; };