src/devices/bin/driver_manager/coordinator.cc
// Add a new device to a parent device (same driver_host)
// New device is published in devfs.
// Caller closes handles on error, so we don't have to.
Add a new device to a parent device (same driver_host)
New device is published in devfs.
Caller closes handles on error, so we don't have to.
Add a new device to a parent device ( same driver_host ) New device is published in devfs . Caller closes handles on error so we don ' t have to .
zx_status_t Coordinator::AddDevice(
    const fbl::RefPtr<Device>& parent, zx::channel device_controller, zx::channel coordinator,
    const llcpp::fuchsia::device::manager::DeviceProperty* props_data, size_t props_count,
    fbl::StringPiece name, uint32_t protocol_id, fbl::StringPiece driver_path,
    fbl::StringPiece args, bool invisible, bool skip_autobind, bool has_init, bool always_init,
    zx::vmo inspect, zx::channel client_remote, fbl::RefPtr<Device>* new_device) {
  static_assert(fuchsia_device_manager_DEVICE_NAME_MAX == ZX_DEVICE_NAME_MAX);
  static_assert(fuchsia_device_manager_PROPERTIES_MAX <= UINT32_MAX);
  if (InSuspend()) {
    LOGF(ERROR, "Add device '%.*s' forbidden in suspend", static_cast<int>(name.size()),
         name.data());
    return ZX_ERR_BAD_STATE;
  }
  if (InResume()) {
    LOGF(ERROR, "Add device '%.*s' forbidden in resume", static_cast<int>(name.size()),
         name.data());
    return ZX_ERR_BAD_STATE;
  }
  if (parent->state() == Device::State::kUnbinding) {
    LOGF(ERROR, "Add device '%.*s' forbidden while parent is unbinding",
         static_cast<int>(name.size()), name.data());
    return ZX_ERR_BAD_STATE;
  }
  fbl::Array<zx_device_prop_t> props(new zx_device_prop_t[props_count], props_count);
  if (!props) {
    return ZX_ERR_NO_MEMORY;
  }
  for (uint32_t i = 0; i < props_count; i++) {
    props[i] = zx_device_prop_t{
        .id = props_data[i].id,
        .reserved = props_data[i].reserved,
        .value = props_data[i].value,
    };
  }
  fbl::AllocChecker ac;
  fbl::String name_str(name, &ac);
  if (!ac.check()) {
    return ZX_ERR_NO_MEMORY;
  }
  fbl::String driver_path_str(driver_path, &ac);
  if (!ac.check()) {
    return ZX_ERR_NO_MEMORY;
  }
  fbl::String args_str(args, &ac);
  if (!ac.check()) {
    return ZX_ERR_NO_MEMORY;
  }
  bool want_init_task = has_init || always_init;
  bool init_wait_make_visible = invisible && !has_init;
  fbl::RefPtr<Device> dev;
  zx_status_t status =
      Device::Create(this, parent, std::move(name_str), std::move(driver_path_str),
                     std::move(args_str), protocol_id, std::move(props), std::move(coordinator),
                     std::move(device_controller), init_wait_make_visible, want_init_task,
                     skip_autobind, std::move(inspect), std::move(client_remote), &dev);
  if (status != ZX_OK) {
    return status;
  }
  devices_.push_back(dev);
  if (fragment_driver_ != nullptr && dev->libname() == fragment_driver_->libname) {
    for (auto& cur_fragment : dev->parent()->fragments()) {
      if (cur_fragment.fragment_device() == nullptr) {
        cur_fragment.set_fragment_device(dev);
        status = cur_fragment.composite()->TryAssemble();
        if (status != ZX_OK && status != ZX_ERR_SHOULD_WAIT) {
          LOGF(ERROR, "Failed to assemble composite device: %s", zx_status_get_string(status));
        }
        break;
      }
    }
  }
  VLOGF(1, "Added device %p '%s'", dev.get(), dev->name().data());
  if (!invisible && !want_init_task) {
    status = dev->SignalReadyForBind();
    if (status != ZX_OK) {
      return status;
    }
    VLOGF(1, "Published device %p '%s' args='%s' props=%zu parent=%p", dev.get(),
          dev->name().data(), dev->args().data(), dev->props().size(), dev->parent().get());
  }
  *new_device = std::move(dev);
  return ZX_OK;
}
zx_status_t Coordinator :: AddDevice ( const fbl :: RefPtr < Device > & parent , zx :: channel device_controller , zx :: channel coordinator , const llcpp :: fuchsia :: device :: manager :: DeviceProperty * props_data , size_t props_count , fbl :: StringPiece name , uint32_t protocol_id , fbl :: StringPiece driver_path , fbl :: StringPiece args , bool invisible , bool skip_autobind , bool has_init , bool always_init , zx :: vmo inspect , zx :: channel client_remote , fbl :: RefPtr < Device > * new_device ) { static_assert ( fuchsia_device_manager_DEVICE_NAME_MAX == ZX_DEVICE_NAME_MAX ) ; static_assert ( fuchsia_device_manager_PROPERTIES_MAX <= UINT32_MAX ) ; if ( InSuspend ( ) ) { LOGF ( ERROR , " " , static_cast < int > ( name . size ( ) ) , name . data ( ) ) ; return ZX_ERR_BAD_STATE ; } if ( InResume ( ) ) { LOGF ( ERROR , " " , static_cast < int > ( name . size ( ) ) , name . data ( ) ) ; return ZX_ERR_BAD_STATE ; } if ( parent -> state ( ) == Device :: State :: kUnbinding ) { LOGF ( ERROR , " " , static_cast < int > ( name . size ( ) ) , name . data ( ) ) ; return ZX_ERR_BAD_STATE ; } fbl :: Array < zx_device_prop_t > props ( new zx_device_prop_t [ props_count ] , props_count ) ; if ( ! props ) { return ZX_ERR_NO_MEMORY ; } for ( uint32_t i = 0 ; i < props_count ; i ++ ) { props [ i ] = zx_device_prop_t { . id = props_data [ i ] . id , . reserved = props_data [ i ] . reserved , . value = props_data [ i ] . value , } ; } fbl :: AllocChecker ac ; fbl :: String name_str ( name , & ac ) ; if ( ! ac . check ( ) ) { return ZX_ERR_NO_MEMORY ; } fbl :: String driver_path_str ( driver_path , & ac ) ; if ( ! ac . check ( ) ) { return ZX_ERR_NO_MEMORY ; } fbl :: String args_str ( args , & ac ) ; if ( ! ac . check ( ) ) { return ZX_ERR_NO_MEMORY ; } bool want_init_task = has_init || always_init ; bool init_wait_make_visible = invisible && ! has_init ; fbl :: RefPtr < Device > dev ; zx_status_t status = Device :: Create ( this , parent , std :: move ( name_str ) , std :: move ( driver_path_str ) , std :: move ( args_str ) , protocol_id , std :: move ( props ) , std :: move ( coordinator ) , std :: move ( device_controller ) , init_wait_make_visible , want_init_task , skip_autobind , std :: move ( inspect ) , std :: move ( client_remote ) , & dev ) ; if ( status != ZX_OK ) { return status ; } devices_ . push_back ( dev ) ; if ( fragment_driver_ != nullptr && dev -> libname ( ) == fragment_driver_ -> libname ) { for ( auto & cur_fragment : dev -> parent ( ) -> fragments ( ) ) { if ( cur_fragment . fragment_device ( ) == nullptr ) { cur_fragment . set_fragment_device ( dev ) ; status = cur_fragment . composite ( ) -> TryAssemble ( ) ; if ( status != ZX_OK && status != ZX_ERR_SHOULD_WAIT ) { LOGF ( ERROR , " " , zx_status_get_string ( status ) ) ; } break ; } } } VLOGF ( 1 , " " , dev . get ( ) , dev -> name ( ) . data ( ) ) ; if ( ! invisible && ! want_init_task ) { status = dev -> SignalReadyForBind ( ) ; if ( status != ZX_OK ) { return status ; } VLOGF ( 1 , " " , dev . get ( ) , dev -> name ( ) . data ( ) , dev -> args ( ) . data ( ) , dev -> props ( ) . size ( ) , dev -> parent ( ) . get ( ) ) ; } * new_device = std :: move ( dev ) ; return ZX_OK ; }
Add a new device to a parent device (same driver_host)
New device is published in devfs.
Add a new device to a parent device ( same driver_host ) New device is published in devfs .
// If this is true, then |name_data|'s size is properly bounded. // TODO(fxbug.dev/43370): remove this check once init tasks can be enabled for all devices. // We use the legacy invisible / device_make_visible behavior if the device is added // as invisible and the device has not implemented the init hook. // TODO(fxbug.dev/43261): remove |has_init| once device_make_visible() is deprecated. // Note that |dev->parent()| may not match |parent| here, so we should always // use |dev->parent()|.  This case can happen if |parent| refers to a device // proxy. // If we're creating a device that's using the fragment driver, inform the // fragment. // Pick the first fragment that does not have a device added by the fragment // driver. // TODO(fxbug.dev/43370): remove this once init tasks can be enabled for all devices.