/* Test that we can bind/unbind and the lists update correctly */ static int dm_test_ordering(struct unit_test_state *uts) { struct dm_test_state *dms = uts->priv; struct udevice *dev, *dev_penultimate, *dev_last, *test_dev; int pingret; ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, &dev)); ut_assert(dev); /* Bind two new devices (numbers 4 and 5) */ ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, &dev_penultimate)); ut_assert(dev_penultimate); ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, &dev_last)); ut_assert(dev_last); /* Now remove device 3 */ ut_assertok(device_remove(dev)); ut_assertok(device_unbind(dev)); /* The device numbering should have shifted down one */ ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); ut_assert(dev_penultimate == test_dev); ut_assertok(uclass_find_device(UCLASS_TEST, 4, &test_dev)); ut_assert(dev_last == test_dev); /* Add back the original device 3, now in position 5 */ ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, &dev)); ut_assert(dev); /* Try ping */ ut_assertok(test_ping(dev, 100, &pingret)); ut_assert(pingret == 102); /* Remove 3 and 4 */ ut_assertok(device_remove(dev_penultimate)); ut_assertok(device_unbind(dev_penultimate)); ut_assertok(device_remove(dev_last)); ut_assertok(device_unbind(dev_last)); /* Our device should now be in position 3 */ ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); ut_assert(dev == test_dev); /* Now remove device 3 */ ut_assertok(device_remove(dev)); ut_assertok(device_unbind(dev)); return 0; }
int dm_uninit(void) { device_remove(dm_root()); device_unbind(dm_root()); return 0; }
static int i2c_bind_driver(struct udevice *bus, uint chip_addr, struct udevice **devp) { struct dm_i2c_chip chip; char name[30], *str; struct udevice *dev; int ret; snprintf(name, sizeof(name), "generic_%x", chip_addr); str = strdup(name); ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev); debug("%s: device_bind_driver: ret=%d\n", __func__, ret); if (ret) goto err_bind; /* Tell the device what we know about it */ memset(&chip, '\0', sizeof(chip)); chip.chip_addr = chip_addr; chip.offset_len = 1; /* we assume */ ret = device_probe_child(dev, &chip); debug("%s: device_probe_child: ret=%d\n", __func__, ret); if (ret) goto err_probe; *devp = dev; return 0; err_probe: device_unbind(dev); err_bind: free(str); return ret; }
/* Test that we can bind, probe, remove, unbind a driver */ static int dm_test_lifecycle(struct unit_test_state *uts) { struct dm_test_state *dms = uts->priv; int op_count[DM_TEST_OP_COUNT]; struct udevice *dev, *test_dev; int pingret; int ret; memcpy(op_count, dm_testdrv_op_count, sizeof(op_count)); ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, &dev)); ut_assert(dev); ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND] == op_count[DM_TEST_OP_BIND] + 1); ut_assert(!dev->priv); /* Probe the device - it should fail allocating private data */ dms->force_fail_alloc = 1; ret = device_probe(dev); ut_assert(ret == -ENOMEM); ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] == op_count[DM_TEST_OP_PROBE] + 1); ut_assert(!dev->priv); /* Try again without the alloc failure */ dms->force_fail_alloc = 0; ut_assertok(device_probe(dev)); ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] == op_count[DM_TEST_OP_PROBE] + 2); ut_assert(dev->priv); /* This should be device 3 in the uclass */ ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); ut_assert(dev == test_dev); /* Try ping */ ut_assertok(test_ping(dev, 100, &pingret)); ut_assert(pingret == 102); /* Now remove device 3 */ ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]); ut_assertok(device_remove(dev)); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]); ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); ut_assertok(device_unbind(dev)); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); return 0; }
int mmc_unbind(struct udevice *dev) { struct udevice *bdev; device_find_first_child(dev, &bdev); if (bdev) { device_remove(bdev); device_unbind(bdev); } return 0; }
static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len, struct udevice **devp) { struct dm_i2c_chip *chip; char name[30], *str; struct udevice *dev; int ret; snprintf(name, sizeof(name), "generic_%x", chip_addr); str = strdup(name); if (!str) return -ENOMEM; ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev); debug("%s: device_bind_driver: ret=%d\n", __func__, ret); if (ret) goto err_bind; /* Tell the device what we know about it */ chip = dev_get_parent_platdata(dev); chip->chip_addr = chip_addr; chip->offset_len = offset_len; ret = device_probe(dev); debug("%s: device_probe: ret=%d\n", __func__, ret); if (ret) goto err_probe; *devp = dev; return 0; err_probe: /* * If the device failed to probe, unbind it. There is nothing there * on the bus so we don't want to leave it lying around */ device_unbind(dev); err_bind: free(str); return ret; }
int blk_unbind_all(int if_type) { struct uclass *uc; struct udevice *dev, *next; int ret; ret = uclass_get(UCLASS_BLK, &uc); if (ret) return ret; uclass_foreach_dev_safe(dev, next, uc) { struct blk_desc *desc = dev_get_uclass_platdata(dev); if (desc->if_type == if_type) { ret = device_remove(dev); if (ret) return ret; ret = device_unbind(dev); if (ret) return ret; } } return 0; }
static int dm_test_children(struct unit_test_state *uts) { struct dm_test_state *dms = uts->priv; struct udevice *top[NODE_COUNT]; struct udevice *child[NODE_COUNT]; struct udevice *grandchild[NODE_COUNT]; struct udevice *dev; int total; int ret; int i; /* We don't care about the numbering for this test */ dms->skip_post_probe = 1; ut_assert(NODE_COUNT > 5); /* First create 10 top-level children */ ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top)); /* Now a few have their own children */ ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL)); ut_assertok(create_children(uts, top[5], NODE_COUNT, 5, child)); /* And grandchildren */ for (i = 0; i < NODE_COUNT; i++) ut_assertok(create_children(uts, child[i], NODE_COUNT, 50 * i, i == 2 ? grandchild : NULL)); /* Check total number of devices */ total = NODE_COUNT * (3 + NODE_COUNT); ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]); /* Try probing one of the grandchildren */ ut_assertok(uclass_get_device(UCLASS_TEST, NODE_COUNT * 3 + 2 * NODE_COUNT, &dev)); ut_asserteq_ptr(grandchild[0], dev); /* * This should have probed the child and top node also, for a total * of 3 nodes. */ ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_PROBE]); /* Probe the other grandchildren */ for (i = 1; i < NODE_COUNT; i++) ut_assertok(device_probe(grandchild[i])); ut_asserteq(2 + NODE_COUNT, dm_testdrv_op_count[DM_TEST_OP_PROBE]); /* Probe everything */ for (ret = uclass_first_device(UCLASS_TEST, &dev); dev; ret = uclass_next_device(&dev)) ; ut_assertok(ret); ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_PROBE]); /* Remove a top-level child and check that the children are removed */ ut_assertok(device_remove(top[2])); ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_REMOVE]); dm_testdrv_op_count[DM_TEST_OP_REMOVE] = 0; /* Try one with grandchildren */ ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev)); ut_asserteq_ptr(dev, top[5]); ut_assertok(device_remove(dev)); ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT), dm_testdrv_op_count[DM_TEST_OP_REMOVE]); /* Try the same with unbind */ ut_assertok(device_unbind(top[2])); ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); dm_testdrv_op_count[DM_TEST_OP_UNBIND] = 0; /* Try one with grandchildren */ ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev)); ut_asserteq_ptr(dev, top[6]); ut_assertok(device_unbind(top[5])); ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT), dm_testdrv_op_count[DM_TEST_OP_UNBIND]); return 0; }
int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, const char *drv_name, const char *dev_name, struct udevice **busp, struct spi_slave **devp) { struct udevice *bus, *dev; struct dm_spi_slave_platdata *plat; bool created = false; int ret; ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); if (ret) { printf("Invalid bus %d (err=%d)\n", busnum, ret); return ret; } ret = spi_find_chip_select(bus, cs, &dev); /* * If there is no such device, create one automatically. This means * that we don't need a device tree node or platform data for the * SPI flash chip - we will bind to the correct driver. */ if (ret == -ENODEV && drv_name) { debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n", __func__, dev_name, busnum, cs, drv_name); ret = device_bind_driver(bus, drv_name, dev_name, &dev); if (ret) return ret; plat = dev_get_parent_platdata(dev); plat->cs = cs; plat->max_hz = speed; plat->mode = mode; created = true; } else if (ret) { printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs, ret); return ret; } if (!device_active(dev)) { struct spi_slave *slave; ret = device_probe(dev); if (ret) goto err; slave = dev_get_parent_priv(dev); slave->dev = dev; } plat = dev_get_parent_platdata(dev); if (!speed) { speed = plat->max_hz; mode = plat->mode; } ret = spi_set_speed_mode(bus, speed, mode); if (ret) goto err; *busp = bus; *devp = dev_get_parent_priv(dev); debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp); return 0; err: debug("%s: Error path, created=%d, device '%s'\n", __func__, created, dev->name); if (created) { device_remove(dev); device_unbind(dev); } return ret; }
/* Test that we can find buses and chip-selects */ static int dm_test_spi_find(struct dm_test_state *dms) { struct sandbox_state *state = state_get_current(); struct spi_slave *slave; struct udevice *bus, *dev; const int busnum = 0, cs = 0, mode = 0, speed = 1000000, cs_b = 1; struct spi_cs_info info; int of_offset; ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus)); /* * spi_post_bind() will bind devices to chip selects. Check this then * remove the emulation and the slave device. */ ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus)); ut_assertok(spi_cs_info(bus, cs, &info)); of_offset = info.dev->of_offset; device_remove(info.dev); device_unbind(info.dev); /* * Even though the device is gone, the sandbox SPI drivers always * reports that CS 0 is present */ ut_assertok(spi_cs_info(bus, cs, &info)); ut_asserteq_ptr(NULL, info.dev); /* This finds nothing because we removed the device */ ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev)); ut_asserteq(-ENODEV, spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &bus, &slave)); /* * This forces the device to be re-added, but there is no emulation * connected so the probe will fail. We require that bus is left * alone on failure, and that the spi_get_bus_and_cs() does not add * a 'partially-inited' device. */ ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev)); ut_asserteq(-ENOENT, spi_get_bus_and_cs(busnum, cs, speed, mode, "spi_flash_std", "name", &bus, &slave)); sandbox_sf_unbind_emul(state_get_current(), busnum, cs); ut_assertok(spi_cs_info(bus, cs, &info)); ut_asserteq_ptr(NULL, info.dev); /* Add the emulation and try again */ ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, of_offset, "name")); ut_assertok(spi_find_bus_and_cs(busnum, cs, &bus, &dev)); ut_assertok(spi_get_bus_and_cs(busnum, cs, speed, mode, "spi_flash_std", "name", &bus, &slave)); ut_assertok(spi_cs_info(bus, cs, &info)); ut_asserteq_ptr(info.dev, slave->dev); /* We should be able to add something to another chip select */ ut_assertok(sandbox_sf_bind_emul(state, busnum, cs_b, bus, of_offset, "name")); ut_assertok(spi_get_bus_and_cs(busnum, cs_b, speed, mode, "spi_flash_std", "name", &bus, &slave)); ut_assertok(spi_cs_info(bus, cs_b, &info)); ut_asserteq_ptr(info.dev, slave->dev); /* * Since we are about to destroy all devices, we must tell sandbox * to forget the emulation device */ sandbox_sf_unbind_emul(state_get_current(), busnum, cs); sandbox_sf_unbind_emul(state_get_current(), busnum, cs_b); return 0; }
static int test_bus_parent_platdata(struct unit_test_state *uts) { struct dm_test_parent_platdata *plat; struct udevice *bus, *dev; int child_count; /* Check that the bus has no children */ ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus)); device_find_first_child(bus, &dev); ut_asserteq_ptr(NULL, dev); ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); for (device_find_first_child(bus, &dev), child_count = 0; dev; device_find_next_child(&dev)) { /* Check that platform data is allocated */ plat = dev_get_parent_platdata(dev); ut_assert(plat != NULL); /* * Check that it is not affected by the device being * probed/removed */ plat->count++; ut_asserteq(1, plat->count); device_probe(dev); device_remove(dev); ut_asserteq_ptr(plat, dev_get_parent_platdata(dev)); ut_asserteq(1, plat->count); ut_assertok(device_probe(dev)); child_count++; } ut_asserteq(3, child_count); /* Removing the bus should also have no effect (it is still bound) */ device_remove(bus); for (device_find_first_child(bus, &dev), child_count = 0; dev; device_find_next_child(&dev)) { /* Check that platform data is allocated */ plat = dev_get_parent_platdata(dev); ut_assert(plat != NULL); ut_asserteq(1, plat->count); child_count++; } ut_asserteq(3, child_count); /* Unbind all the children */ do { device_find_first_child(bus, &dev); if (dev) device_unbind(dev); } while (dev); /* Now the child platdata should be removed and re-added */ device_probe(bus); for (device_find_first_child(bus, &dev), child_count = 0; dev; device_find_next_child(&dev)) { /* Check that platform data is allocated */ plat = dev_get_parent_platdata(dev); ut_assert(plat != NULL); ut_asserteq(0, plat->count); child_count++; } ut_asserteq(3, child_count); return 0; }
int host_dev_bind(int devnum, char *filename) { struct host_block_dev *host_dev; struct udevice *dev; char dev_name[20], *str, *fname; int ret, fd; /* Remove and unbind the old device, if any */ ret = blk_get_device(IF_TYPE_HOST, devnum, &dev); if (ret == 0) { ret = device_remove(dev); if (ret) return ret; ret = device_unbind(dev); if (ret) return ret; } else if (ret != -ENODEV) { return ret; } if (!filename) return 0; snprintf(dev_name, sizeof(dev_name), "host%d", devnum); str = strdup(dev_name); if (!str) return -ENOMEM; fname = strdup(filename); if (!fname) { free(str); return -ENOMEM; } fd = os_open(filename, OS_O_RDWR); if (fd == -1) { printf("Failed to access host backing file '%s'\n", filename); ret = -ENOENT; goto err; } ret = blk_create_device(gd->dm_root, "sandbox_host_blk", str, IF_TYPE_HOST, devnum, 512, os_lseek(fd, 0, OS_SEEK_END), &dev); if (ret) goto err_file; ret = device_probe(dev); if (ret) { device_unbind(dev); goto err_file; } host_dev = dev_get_priv(dev); host_dev->fd = fd; host_dev->filename = fname; return blk_prepare_device(dev); err_file: os_close(fd); err: free(fname); free(str); return ret; }