1 /* 2 * Copyright (c) 2013 Google, Inc 3 * 4 * (C) Copyright 2012 5 * Pavel Herrmann <morpheus.ibis@gmail.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <errno.h> 12 #include <malloc.h> 13 #include <dm/device.h> 14 #include <dm/device-internal.h> 15 #include <dm/lists.h> 16 #include <dm/uclass.h> 17 #include <dm/uclass-internal.h> 18 #include <dm/util.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 struct uclass *uclass_find(enum uclass_id key) 23 { 24 struct uclass *uc; 25 26 /* 27 * TODO(sjg@chromium.org): Optimise this, perhaps moving the found 28 * node to the start of the list, or creating a linear array mapping 29 * id to node. 30 */ 31 list_for_each_entry(uc, &gd->uclass_root, sibling_node) { 32 if (uc->uc_drv->id == key) 33 return uc; 34 } 35 36 return NULL; 37 } 38 39 /** 40 * uclass_add() - Create new uclass in list 41 * @id: Id number to create 42 * @ucp: Returns pointer to uclass, or NULL on error 43 * @return 0 on success, -ve on error 44 * 45 * The new uclass is added to the list. There must be only one uclass for 46 * each id. 47 */ 48 static int uclass_add(enum uclass_id id, struct uclass **ucp) 49 { 50 struct uclass_driver *uc_drv; 51 struct uclass *uc; 52 int ret; 53 54 *ucp = NULL; 55 uc_drv = lists_uclass_lookup(id); 56 if (!uc_drv) { 57 dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n", 58 id); 59 return -ENOENT; 60 } 61 if (uc_drv->ops) { 62 dm_warn("No ops for uclass id %d\n", id); 63 return -EINVAL; 64 } 65 uc = calloc(1, sizeof(*uc)); 66 if (!uc) 67 return -ENOMEM; 68 if (uc_drv->priv_auto_alloc_size) { 69 uc->priv = calloc(1, uc_drv->priv_auto_alloc_size); 70 if (!uc->priv) { 71 ret = -ENOMEM; 72 goto fail_mem; 73 } 74 } 75 uc->uc_drv = uc_drv; 76 INIT_LIST_HEAD(&uc->sibling_node); 77 INIT_LIST_HEAD(&uc->dev_head); 78 list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST); 79 80 if (uc_drv->init) { 81 ret = uc_drv->init(uc); 82 if (ret) 83 goto fail; 84 } 85 86 *ucp = uc; 87 88 return 0; 89 fail: 90 if (uc_drv->priv_auto_alloc_size) { 91 free(uc->priv); 92 uc->priv = NULL; 93 } 94 list_del(&uc->sibling_node); 95 fail_mem: 96 free(uc); 97 98 return ret; 99 } 100 101 int uclass_destroy(struct uclass *uc) 102 { 103 struct uclass_driver *uc_drv; 104 struct udevice *dev, *tmp; 105 int ret; 106 107 list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) { 108 ret = device_remove(dev); 109 if (ret) 110 return ret; 111 ret = device_unbind(dev); 112 if (ret) 113 return ret; 114 } 115 116 uc_drv = uc->uc_drv; 117 if (uc_drv->destroy) 118 uc_drv->destroy(uc); 119 list_del(&uc->sibling_node); 120 if (uc_drv->priv_auto_alloc_size) 121 free(uc->priv); 122 free(uc); 123 124 return 0; 125 } 126 127 int uclass_get(enum uclass_id id, struct uclass **ucp) 128 { 129 struct uclass *uc; 130 131 *ucp = NULL; 132 uc = uclass_find(id); 133 if (!uc) 134 return uclass_add(id, ucp); 135 *ucp = uc; 136 137 return 0; 138 } 139 140 int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) 141 { 142 struct uclass *uc; 143 struct udevice *dev; 144 int ret; 145 146 *devp = NULL; 147 ret = uclass_get(id, &uc); 148 if (ret) 149 return ret; 150 151 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 152 if (!index--) { 153 *devp = dev; 154 return 0; 155 } 156 } 157 158 return -ENODEV; 159 } 160 161 int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, 162 bool find_req_seq, struct udevice **devp) 163 { 164 struct uclass *uc; 165 struct udevice *dev; 166 int ret; 167 168 *devp = NULL; 169 debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq); 170 if (seq_or_req_seq == -1) 171 return -ENODEV; 172 ret = uclass_get(id, &uc); 173 if (ret) 174 return ret; 175 176 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 177 debug(" - %d %d\n", dev->req_seq, dev->seq); 178 if ((find_req_seq ? dev->req_seq : dev->seq) == 179 seq_or_req_seq) { 180 *devp = dev; 181 debug(" - found\n"); 182 return 0; 183 } 184 } 185 debug(" - not found\n"); 186 187 return -ENODEV; 188 } 189 190 /** 191 * uclass_get_device_tail() - handle the end of a get_device call 192 * 193 * This handles returning an error or probing a device as needed. 194 * 195 * @dev: Device that needs to be probed 196 * @ret: Error to return. If non-zero then the device is not probed 197 * @devp: Returns the value of 'dev' if there is no error 198 * @return ret, if non-zero, else the result of the device_probe() call 199 */ 200 static int uclass_get_device_tail(struct udevice *dev, int ret, 201 struct udevice **devp) 202 { 203 if (ret) 204 return ret; 205 206 ret = device_probe(dev); 207 if (ret) 208 return ret; 209 210 *devp = dev; 211 212 return 0; 213 } 214 215 int uclass_get_device(enum uclass_id id, int index, struct udevice **devp) 216 { 217 struct udevice *dev; 218 int ret; 219 220 *devp = NULL; 221 ret = uclass_find_device(id, index, &dev); 222 return uclass_get_device_tail(dev, ret, devp); 223 } 224 225 int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp) 226 { 227 struct udevice *dev; 228 int ret; 229 230 *devp = NULL; 231 ret = uclass_find_device_by_seq(id, seq, false, &dev); 232 if (ret == -ENODEV) { 233 /* 234 * We didn't find it in probed devices. See if there is one 235 * that will request this seq if probed. 236 */ 237 ret = uclass_find_device_by_seq(id, seq, true, &dev); 238 } 239 return uclass_get_device_tail(dev, ret, devp); 240 } 241 242 int uclass_first_device(enum uclass_id id, struct udevice **devp) 243 { 244 struct uclass *uc; 245 struct udevice *dev; 246 int ret; 247 248 *devp = NULL; 249 ret = uclass_get(id, &uc); 250 if (ret) 251 return ret; 252 if (list_empty(&uc->dev_head)) 253 return 0; 254 255 dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node); 256 ret = device_probe(dev); 257 if (ret) 258 return ret; 259 *devp = dev; 260 261 return 0; 262 } 263 264 int uclass_next_device(struct udevice **devp) 265 { 266 struct udevice *dev = *devp; 267 int ret; 268 269 *devp = NULL; 270 if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) 271 return 0; 272 273 dev = list_entry(dev->uclass_node.next, struct udevice, 274 uclass_node); 275 ret = device_probe(dev); 276 if (ret) 277 return ret; 278 *devp = dev; 279 280 return 0; 281 } 282 283 int uclass_bind_device(struct udevice *dev) 284 { 285 struct uclass *uc; 286 int ret; 287 288 uc = dev->uclass; 289 290 list_add_tail(&dev->uclass_node, &uc->dev_head); 291 292 if (uc->uc_drv->post_bind) { 293 ret = uc->uc_drv->post_bind(dev); 294 if (ret) { 295 list_del(&dev->uclass_node); 296 return ret; 297 } 298 } 299 300 return 0; 301 } 302 303 int uclass_unbind_device(struct udevice *dev) 304 { 305 struct uclass *uc; 306 int ret; 307 308 uc = dev->uclass; 309 if (uc->uc_drv->pre_unbind) { 310 ret = uc->uc_drv->pre_unbind(dev); 311 if (ret) 312 return ret; 313 } 314 315 list_del(&dev->uclass_node); 316 return 0; 317 } 318 319 int uclass_resolve_seq(struct udevice *dev) 320 { 321 struct udevice *dup; 322 int seq; 323 int ret; 324 325 assert(dev->seq == -1); 326 ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq, 327 false, &dup); 328 if (!ret) { 329 dm_warn("Device '%s': seq %d is in use by '%s'\n", 330 dev->name, dev->req_seq, dup->name); 331 } else if (ret == -ENODEV) { 332 /* Our requested sequence number is available */ 333 if (dev->req_seq != -1) 334 return dev->req_seq; 335 } else { 336 return ret; 337 } 338 339 for (seq = 0; seq < DM_MAX_SEQ; seq++) { 340 ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq, 341 false, &dup); 342 if (ret == -ENODEV) 343 break; 344 if (ret) 345 return ret; 346 } 347 return seq; 348 } 349 350 int uclass_post_probe_device(struct udevice *dev) 351 { 352 struct uclass_driver *uc_drv = dev->uclass->uc_drv; 353 354 if (uc_drv->post_probe) 355 return uc_drv->post_probe(dev); 356 357 return 0; 358 } 359 360 int uclass_pre_remove_device(struct udevice *dev) 361 { 362 struct uclass_driver *uc_drv; 363 struct uclass *uc; 364 int ret; 365 366 uc = dev->uclass; 367 uc_drv = uc->uc_drv; 368 if (uc->uc_drv->pre_remove) { 369 ret = uc->uc_drv->pre_remove(dev); 370 if (ret) 371 return ret; 372 } 373 if (uc_drv->per_device_auto_alloc_size) { 374 free(dev->uclass_priv); 375 dev->uclass_priv = NULL; 376 } 377 dev->seq = -1; 378 379 return 0; 380 } 381