void genIOKitDevice(const io_service_t& device,
                    const io_service_t& parent,
                    const io_name_t plane,
                    int depth,
                    QueryData& results) {
  Row r;
  io_name_t name, device_class;
  auto kr = IORegistryEntryGetName(device, name);
  if (kr == KERN_SUCCESS) {
    r["name"] = std::string(name);
  }

  // Get the device class.
  kr = IOObjectGetClass(device, device_class);
  if (kr == KERN_SUCCESS) {
    r["class"] = std::string(device_class);
  }

  // The entry into the registry is the ID, and is used for children as parent.
  uint64_t device_id, parent_id;
  kr = IORegistryEntryGetRegistryEntryID(device, &device_id);
  if (kr == KERN_SUCCESS) {
    r["id"] = BIGINT(device_id);
  } else {
    r["id"] = "-1";
  }

  kr = IORegistryEntryGetRegistryEntryID(parent, &parent_id);
  if (kr == KERN_SUCCESS) {
    r["parent"] = BIGINT(parent_id);
  } else {
    r["parent"] = "-1";
  }

  r["depth"] = INTEGER(depth);

  if (IORegistryEntryInPlane(device, kIODeviceTreePlane)) {
    io_string_t device_path;
    kr = IORegistryEntryGetPath(device, kIODeviceTreePlane, device_path);
    if (kr == KERN_SUCCESS) {
      // Remove the "IODeviceTree:" from the device tree path.
      r["device_path"] = std::string(device_path).substr(13);
    }
  }

  // Fill in service bits and busy/latency time.
  if (IOObjectConformsTo(device, "IOService")) {
    r["service"] = "1";
  } else {
    r["service"] = "0";
  }

  uint32_t busy_state;
  kr = IOServiceGetBusyState(device, &busy_state);
  if (kr == KERN_SUCCESS) {
    r["busy_state"] = INTEGER(busy_state);
  } else {
    r["busy_state"] = "0";
  }

  auto retain_count = IOObjectGetKernelRetainCount(device);
  r["retain_count"] = INTEGER(retain_count);

  results.push_back(r);
}
void traverse(unsigned int options,
	      io_name_t plane, io_iterator_t services,
	      io_registry_entry_t serviceUpNext,
	      int depth, UInt64 stackOfBits)
{
    io_registry_entry_t service;                                ///ok
    Boolean		doProps;

    // We loop for every service in the list of services provided.

    while ( (service = serviceUpNext) )
    {
        io_iterator_t		children;
        Boolean			hasChildren;
        io_name_t    		name;
        kern_return_t		status;
	io_registry_entry_t	child;
	int			busy;

        // Obtain the next service entry, if any.

        serviceUpNext = IOIteratorNext(services);

        // Obtain the current service entry's children, if any.

        status = IORegistryEntryGetChildIterator(service,
                                                 plane,
                                                 &children);
        assert(status == KERN_SUCCESS);

        child = IOIteratorNext(children); ///ok
        hasChildren = child ? true : false;

        // Save has-more-siblings state into stackOfBits for this depth.

        if (serviceUpNext)
            stackOfBits |=  (1 << depth);
        else
            stackOfBits &= ~(1 << depth);

        // Save has-children state into stackOfBits for this depth.

        if (hasChildren)
            stackOfBits |=  (2 << depth);
        else
            stackOfBits &= ~(2 << depth);

        indent(true, depth, stackOfBits);

        // Print out the name of the service.

        status = IORegistryEntryGetName(service, name);
        assert(status == KERN_SUCCESS);

        printf("%s", name);

	if (strcmp("Root", name))
            doProps = (options & kDoPropsOption) != 0;
	else
            doProps = (options & kDoRootOption) != 0;

        // Print out the class of the service.

        status = IOObjectGetClass(service, name);
        assert(status == KERN_SUCCESS);
        printf("  <class %s", name);

	status = IOServiceGetBusyState(service, &busy);
	if(status == KERN_SUCCESS)
            printf(", busy %d", busy);

        // Print out the retain count of the service.

        printf(", retain count %d>\n", IOObjectGetRetainCount(service));

        // Print out the properties of the service.

	if (doProps)
            properties(service, depth, stackOfBits);

        // Recurse down.

	traverse(options, plane, children, child, depth + 1, stackOfBits);

        // Release resources.

        IOObjectRelease(children); children = 0;
        IOObjectRelease(service);  service  = 0;
    }
}