"Das U-Boot" Source Tree
at master 260 lines 5.5 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2018 JJ Hiblot <jjhiblot@ti.com> 4 */ 5 6#include <command.h> 7#include <dm.h> 8#include <dm/device-internal.h> 9#include <dm/lists.h> 10#include <dm/root.h> 11#include <dm/uclass-internal.h> 12 13static int bind_by_class_seq(const char *uclass, int seq, 14 const char *drv_name) 15{ 16 static enum uclass_id uclass_id; 17 struct udevice *dev; 18 struct udevice *parent; 19 int ret; 20 struct driver *drv; 21 22 drv = lists_driver_lookup_name(drv_name); 23 if (!drv) { 24 printf("Cannot find driver '%s'\n", drv_name); 25 return -ENOENT; 26 } 27 28 uclass_id = uclass_get_by_name(uclass); 29 if (uclass_id == UCLASS_INVALID) { 30 printf("%s is not a valid uclass\n", uclass); 31 return -EINVAL; 32 } 33 34 ret = uclass_find_device_by_seq(uclass_id, seq, &parent); 35 if (!parent || ret) { 36 printf("Cannot find device %d of class %s\n", seq, uclass); 37 return ret; 38 } 39 40 ret = device_bind_with_driver_data(parent, drv, drv->name, 0, 41 ofnode_null(), &dev); 42 if (!dev || ret) { 43 printf("Unable to bind. err:%d\n", ret); 44 return ret; 45 } 46 47 return 0; 48} 49 50static int find_dev(const char *uclass, int seq, struct udevice **devp) 51{ 52 static enum uclass_id uclass_id; 53 int rc; 54 55 uclass_id = uclass_get_by_name(uclass); 56 if (uclass_id == UCLASS_INVALID) { 57 printf("%s is not a valid uclass\n", uclass); 58 return -EINVAL; 59 } 60 61 rc = uclass_find_device_by_seq(uclass_id, seq, devp); 62 if (!*devp || rc) { 63 printf("Cannot find device %d of class %s\n", seq, uclass); 64 return rc; 65 } 66 67 return 0; 68} 69 70static int unbind_by_class_seq(const char *uclass, int seq) 71{ 72 int ret; 73 struct udevice *dev; 74 75 ret = find_dev(uclass, seq, &dev); 76 if (ret) 77 return ret; 78 79 ret = device_remove(dev, DM_REMOVE_NORMAL); 80 if (ret) { 81 printf("Unable to remove. err:%d\n", ret); 82 return ret; 83 } 84 85 ret = device_unbind(dev); 86 if (ret) { 87 printf("Unable to unbind. err:%d\n", ret); 88 return ret; 89 } 90 91 return 0; 92} 93 94static int unbind_child_by_class_seq(const char *uclass, int seq, 95 const char *drv_name) 96{ 97 struct udevice *parent; 98 int ret; 99 struct driver *drv; 100 101 drv = lists_driver_lookup_name(drv_name); 102 if (!drv) { 103 printf("Cannot find driver '%s'\n", drv_name); 104 return -ENOENT; 105 } 106 107 ret = find_dev(uclass, seq, &parent); 108 if (ret) 109 return ret; 110 111 ret = device_chld_remove(parent, drv, DM_REMOVE_NORMAL); 112 if (ret) 113 printf("Unable to remove all. err:%d\n", ret); 114 115 ret = device_chld_unbind(parent, drv); 116 if (ret) 117 printf("Unable to unbind all. err:%d\n", ret); 118 119 return ret; 120} 121 122static int bind_by_node_path(const char *path, const char *drv_name) 123{ 124 struct udevice *dev; 125 struct udevice *parent = NULL; 126 int ret; 127 ofnode ofnode; 128 struct driver *drv; 129 130 drv = lists_driver_lookup_name(drv_name); 131 if (!drv) { 132 printf("%s is not a valid driver name\n", drv_name); 133 return -ENOENT; 134 } 135 136 ofnode = ofnode_path(path); 137 if (!ofnode_valid(ofnode)) { 138 printf("%s is not a valid node path\n", path); 139 return -EINVAL; 140 } 141 142 while (ofnode_valid(ofnode)) { 143 if (!device_find_global_by_ofnode(ofnode, &parent)) 144 break; 145 ofnode = ofnode_get_parent(ofnode); 146 } 147 148 if (!parent) { 149 printf("Cannot find a parent device for node path %s\n", path); 150 return -ENODEV; 151 } 152 153 ofnode = ofnode_path(path); 154 ret = lists_bind_fdt(parent, ofnode, &dev, drv, false); 155 156 if (!dev || ret) { 157 printf("Unable to bind. err:%d\n", ret); 158 return ret; 159 } 160 161 return 0; 162} 163 164static int unbind_by_node_path(const char *path) 165{ 166 struct udevice *dev; 167 int ret; 168 ofnode ofnode; 169 170 ofnode = ofnode_path(path); 171 if (!ofnode_valid(ofnode)) { 172 printf("%s is not a valid node path\n", path); 173 return -EINVAL; 174 } 175 176 ret = device_find_global_by_ofnode(ofnode, &dev); 177 178 if (!dev || ret) { 179 printf("Cannot find a device with path %s\n", path); 180 return -ENODEV; 181 } 182 183 ret = device_remove(dev, DM_REMOVE_NORMAL); 184 if (ret) { 185 printf("Unable to remove. err:%d\n", ret); 186 return ret; 187 } 188 189 ret = device_unbind(dev); 190 if (ret) { 191 printf("Unable to unbind. err:%d\n", ret); 192 return ret; 193 } 194 195 return 0; 196} 197 198static int do_bind_unbind(struct cmd_tbl *cmdtp, int flag, int argc, 199 char *const argv[]) 200{ 201 int ret = 0; 202 bool bind; 203 bool by_node; 204 205 if (argc < 2) 206 return CMD_RET_USAGE; 207 208 bind = (argv[0][0] == 'b'); 209 by_node = (argv[1][0] == '/'); 210 211 if (by_node && bind) { 212 if (argc != 3) 213 return CMD_RET_USAGE; 214 ret = bind_by_node_path(argv[1], argv[2]); 215 } else if (by_node && !bind) { 216 if (argc != 2) 217 return CMD_RET_USAGE; 218 ret = unbind_by_node_path(argv[1]); 219 } else if (!by_node && bind) { 220 int seq = (argc > 2) ? dectoul(argv[2], NULL) : 0; 221 222 if (argc != 4) 223 return CMD_RET_USAGE; 224 ret = bind_by_class_seq(argv[1], seq, argv[3]); 225 } else if (!by_node && !bind) { 226 int seq = (argc > 2) ? dectoul(argv[2], NULL) : 0; 227 228 if (argc == 3) 229 ret = unbind_by_class_seq(argv[1], seq); 230 else if (argc == 4) 231 ret = unbind_child_by_class_seq(argv[1], seq, 232 argv[3]); 233 else 234 return CMD_RET_USAGE; 235 } 236 237 if (ret) 238 return CMD_RET_FAILURE; 239 else 240 return CMD_RET_SUCCESS; 241} 242 243U_BOOT_CMD( 244 bind, 4, 0, do_bind_unbind, 245 "Bind a device to a driver", 246 "<node path> <driver>\n" 247 "bind <class> <seq> <driver>\n" 248 "Use 'dm tree' to list all devices registered in the driver model,\n" 249 "their path, class, sequence and current driver.\n" 250); 251 252U_BOOT_CMD( 253 unbind, 4, 0, do_bind_unbind, 254 "Unbind a device from a driver", 255 "<node path>\n" 256 "unbind <class> <seq>\n" 257 "unbind <class> <seq> <driver>\n" 258 "Use 'dm tree' to list all devices registered in the driver model,\n" 259 "their path, class, sequence and current driver.\n" 260);