static void fu_wac_module_constructed (GObject *object) { FuWacModule *self = FU_WAC_MODULE (object); FuWacModulePrivate *priv = GET_PRIVATE (self); g_autofree gchar *devid = NULL; g_autofree gchar *vendor_id = NULL; /* set vendor ID */ vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); fu_device_set_vendor_id (FU_DEVICE (self), vendor_id); /* set USB physical and logical IDs */ fu_device_set_physical_id (FU_DEVICE (self), g_usb_device_get_platform_id (priv->usb_device)); fu_device_set_logical_id (FU_DEVICE (self), fu_wac_module_fw_type_to_string (priv->fw_type)); /* append the firmware kind to the generated GUID */ devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X-%s", g_usb_device_get_vid (priv->usb_device), g_usb_device_get_pid (priv->usb_device), fu_wac_module_fw_type_to_string (priv->fw_type)); fu_device_add_instance_id (FU_DEVICE (self), devid); G_OBJECT_CLASS (fu_wac_module_parent_class)->constructed (object); }
static gboolean fu_plugin_dell_dock_probe (FuPlugin *plugin, FuDevice *symbiote, GError **error) { g_autoptr(FuDellDockEc) ec_device = NULL; /* create all static endpoints */ ec_device = fu_dell_dock_ec_new (symbiote); if (!fu_plugin_dell_dock_create_node (plugin, FU_DEVICE (ec_device), error)) return FALSE; /* create TBT endpoint if Thunderbolt SKU and Thunderbolt link inactive */ if (fu_dell_dock_ec_needs_tbt (FU_DEVICE (ec_device))) { g_autoptr(FuDellDockTbt) tbt_device = fu_dell_dock_tbt_new (); fu_device_add_child (FU_DEVICE (ec_device), FU_DEVICE (tbt_device)); if (!fu_plugin_dell_dock_create_node (plugin, FU_DEVICE (tbt_device), error)) return FALSE; } return TRUE; }
/** * fu_usb_device_set_dev: * @device: A #FuUsbDevice * @usb_device: A #GUsbDevice, or %NULL * * Sets the #GUsbDevice to use. * * Since: 1.0.2 **/ void fu_usb_device_set_dev (FuUsbDevice *device, GUsbDevice *usb_device) { FuUsbDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FU_IS_USB_DEVICE (device)); /* need to re-probe hardware */ fu_device_probe_invalidate (FU_DEVICE (device)); /* allow replacement */ g_set_object (&priv->usb_device, usb_device); if (usb_device == NULL) { g_clear_object (&priv->usb_device_locker); return; } /* set device ID automatically */ fu_device_set_physical_id (FU_DEVICE (device), g_usb_device_get_platform_id (usb_device)); }
gboolean fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuWacDevice) dev = NULL; g_autoptr(FuDeviceLocker) locker = NULL; dev = fu_wac_device_new (device); locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; }
/* now with kind and usb_device set */ static void fu_altos_device_init_real (FuAltosDevice *self) { /* allowed, but requires manual bootloader step */ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); /* set default vendor */ fu_device_set_vendor (FU_DEVICE (self), "altusmetrum.org"); /* set name */ switch (self->kind) { case FU_ALTOS_DEVICE_KIND_BOOTLOADER: fu_device_set_name (FU_DEVICE (self), "Altos [bootloader]"); break; case FU_ALTOS_DEVICE_KIND_CHAOSKEY: fu_device_set_name (FU_DEVICE (self), "Altos ChaosKey"); break; default: g_assert_not_reached (); break; } /* set one line summary */ fu_device_set_summary (FU_DEVICE (self), "A USB hardware random number generator"); /* only the bootloader can do the update */ if (self->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } }
FuAltosDevice * fu_altos_device_new (FuUsbDevice *device) { const FuAltosDeviceVidPid vidpids[] = { { 0xfffe, 0x000a, FU_ALTOS_DEVICE_KIND_BOOTLOADER }, { 0x1d50, 0x60c6, FU_ALTOS_DEVICE_KIND_CHAOSKEY }, { 0x0000, 0x0000, FU_ALTOS_DEVICE_KIND_UNKNOWN } }; /* set kind */ for (guint j = 0; vidpids[j].vid != 0x0000; j++) { if (fu_usb_device_get_vid (device) == vidpids[j].vid && fu_usb_device_get_pid (device) == vidpids[j].pid) { FuAltosDevice *self = g_object_new (FU_TYPE_ALTOS_DEVICE, NULL); fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); self->kind = vidpids[j].kind; fu_altos_device_init_real (self); return self; } } return NULL; }
gboolean fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuRts54HubDevice) dev = NULL; /* open the device */ dev = fu_rts54hub_device_new (device); locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; /* success */ fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; }
gboolean fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuNitrokeyDevice) device = NULL; /* open the device */ device = fu_nitrokey_device_new (usb_device); locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; /* success */ fu_plugin_device_add (plugin, FU_DEVICE (device)); return TRUE; }
gboolean fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuColorhugDevice) dev = NULL; /* open the device */ dev = fu_colorhug_device_new (device); locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; /* insert to hash */ fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; }
static gboolean fu_altos_device_probe (FuDevice *device, GError **error) { FuAltosDevice *self = FU_ALTOS_DEVICE (device); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); /* bootloader uses tty */ if (self->kind == FU_ALTOS_DEVICE_KIND_BOOTLOADER) return fu_altos_device_probe_bootloader (self, error); /* get version */ if (self->kind == FU_ALTOS_DEVICE_KIND_CHAOSKEY) { const gchar *version_prefix = "ChaosKey-hw-1.0-sw-"; guint8 version_idx; g_autofree gchar *version = NULL; g_autoptr(FuDeviceLocker) locker = NULL; /* open */ locker = fu_device_locker_new (usb_device, error); if (locker == NULL) return FALSE; /* get string */ version_idx = g_usb_device_get_product_index (usb_device); version = g_usb_device_get_string_descriptor (usb_device, version_idx, error); if (version == NULL) return FALSE; if (!g_str_has_prefix (version, version_prefix)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not a ChaosKey v1.0 device: %s", version); return FALSE; } fu_device_set_version (FU_DEVICE (self), version + 19); } /* success */ return TRUE; }
gboolean fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuDellDockHub) hub = fu_dell_dock_hub_new (device); FuDevice *fu_device = FU_DEVICE (hub); const gchar *key = NULL; locker = fu_device_locker_new (fu_device, error); if (locker == NULL) return FALSE; fu_plugin_device_add (plugin, fu_device); if (fu_device_has_custom_flag (fu_device, "has-bridge")) { g_autoptr(GError) error_local = NULL; /* only add the device with parent to cache */ key = fu_device_get_id (fu_device); if (fu_plugin_cache_lookup (plugin, key) != NULL) { g_debug ("Ignoring already added device %s", key); return TRUE; } fu_plugin_cache_add (plugin, key, fu_device); /* probe for extended devices */ if (!fu_plugin_dell_dock_probe (plugin, fu_device, &error_local)) { g_warning ("Failed to probe bridged devices for %s: %s", key, error_local->message); } } /* clear updatable flag if parent doesn't have it */ fu_dell_dock_clone_updatable (fu_device); return TRUE; }
static gboolean fu_wac_module_refresh (FuWacModule *self, GError **error) { FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); FuWacModulePrivate *priv = GET_PRIVATE (self); guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, [1 ... FU_WAC_PACKET_LEN - 1] = 0xff }; /* get from hardware */ if (!fu_wac_device_get_feature_report (parent_device, buf, sizeof(buf), FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC | FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG, error)) { g_prefix_error (error, "failed to refresh status: "); return FALSE; } /* check fw type */ if (priv->fw_type != buf[1]) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Submodule GetFeature fw_Type invalid " "got 0x%02x expected 0x%02x", (guint) buf[1], (guint) priv->fw_type); return FALSE; } /* current phase and status */ if (priv->command != buf[2] || priv->status != buf[3]) { priv->command = buf[2]; priv->status = buf[3]; g_debug ("command: %s, status: %s", fu_wac_module_command_to_string (priv->command), fu_wac_module_status_to_string (priv->status)); } /* success */ return TRUE; }
gboolean fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; /* open device */ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; /* switch to bootloader mode is not required */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { g_debug ("already in bootloader mode, skipping"); return TRUE; } /* reset */ if (!fu_device_detach (FU_DEVICE (device), error)) return FALSE; /* wait for replug */ fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; }
gboolean fu_wac_module_set_feature (FuWacModule *self, guint8 command, GBytes *blob, /* optional */ GError **error) { FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); FuWacModulePrivate *priv = GET_PRIVATE (self); const guint8 *data; gsize len = 0; guint busy_poll_loops = 100; /* 1s */ guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, [1] = priv->fw_type, [2] = command, [3 ... FU_WAC_PACKET_LEN - 1] = 0xff }; /* verify the size of the blob */ if (blob != NULL) { data = g_bytes_get_data (blob, &len); if (len > 509) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Submodule SetFeature blob larger than " "buffer %" G_GSIZE_FORMAT, len); return FALSE; } } /* build packet */ if (len > 0) memcpy (&buf[3], data, len); /* tell the daemon the current status */ switch (command) { case FU_WAC_MODULE_COMMAND_START: fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); break; case FU_WAC_MODULE_COMMAND_DATA: fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); break; case FU_WAC_MODULE_COMMAND_END: fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); break; default: break; } /* send to hardware */ if (!fu_wac_device_set_feature_report (parent_device, buf, len + 3, FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC, error)) { g_prefix_error (error, "failed to set module feature: "); return FALSE; } /* special case StartProgram, as it can take much longer as it is * erasing the blocks (15s) */ if (command == FU_WAC_MODULE_COMMAND_START) busy_poll_loops *= 15; /* wait for hardware */ for (guint i = 0; i < busy_poll_loops; i++) { if (!fu_wac_module_refresh (self, error)) return FALSE; if (priv->status == FU_WAC_MODULE_STATUS_BUSY) { g_usleep (10000); /* 10ms */ continue; } if (priv->status == FU_WAC_MODULE_STATUS_OK) break; g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Failed to SetFeature: %s", fu_wac_module_status_to_string (priv->status)); return FALSE; } /* too many retries */ if (priv->status != FU_WAC_MODULE_STATUS_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Timed out after %u loops with status %s", busy_poll_loops, fu_wac_module_status_to_string (priv->status)); return FALSE; } /* success */ return TRUE; }
int main (int argc, char *argv[]) { gboolean action_enable = FALSE; gboolean action_info = FALSE; gboolean action_list = FALSE; gboolean action_log = FALSE; gboolean action_set_debug = FALSE; gboolean action_supported = FALSE; gboolean action_unset_debug = FALSE; gboolean action_version = FALSE; gboolean ret; gboolean verbose = FALSE; g_autofree gchar *apply = FALSE; g_autofree gchar *esp_path = NULL; g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; const GOptionEntry options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, /* TRANSLATORS: command line option */ _("Show extra debugging information"), NULL }, { "version", '\0', 0, G_OPTION_ARG_NONE, &action_version, /* TRANSLATORS: command line option */ _("Display version"), NULL }, { "log", 'L', 0, G_OPTION_ARG_NONE, &action_log, /* TRANSLATORS: command line option */ _("Show the debug log from the last attempted update"), NULL }, { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, /* TRANSLATORS: command line option */ _("List supported firmware updates"), NULL }, { "supported", 's', 0, G_OPTION_ARG_NONE, &action_supported, /* TRANSLATORS: command line option */ _("Query for firmware update support"), NULL }, { "info", 'i', 0, G_OPTION_ARG_NONE, &action_info, /* TRANSLATORS: command line option */ _("Show the information of firmware update status"), NULL }, { "enable", 'e', 0, G_OPTION_ARG_NONE, &action_enable, /* TRANSLATORS: command line option */ _("Enable firmware update support on supported systems"), NULL }, { "esp-path", 'p', 0, G_OPTION_ARG_STRING, &esp_path, /* TRANSLATORS: command line option */ _("Override the default ESP path"), "PATH" }, { "set-debug", 'd', 0, G_OPTION_ARG_NONE, &action_set_debug, /* TRANSLATORS: command line option */ _("Set the debugging flag during update"), NULL }, { "unset-debug", 'D', 0, G_OPTION_ARG_NONE, &action_unset_debug, /* TRANSLATORS: command line option */ _("Unset the debugging flag during update"), NULL }, { "apply", 'a', 0, G_OPTION_ARG_STRING, &apply, /* TRANSLATORS: command line option */ _("Apply firmware updates"), "GUID" }, { NULL} }; setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* ensure root user */ if (getuid () != 0 || geteuid () != 0) /* TRANSLATORS: we're poking around as a power user */ g_printerr ("%s\n", _("This program may only work correctly as root")); /* get a action_list of the commands */ priv->context = g_option_context_new (NULL); g_option_context_set_description (priv->context, "This tool allows an administrator to debug UpdateCapsule operation."); /* TRANSLATORS: program name */ g_set_application_name (_("UEFI Firmware Utility")); g_option_context_add_main_entries (priv->context, options, NULL); ret = g_option_context_parse (priv->context, &argc, &argv, &error); if (!ret) { /* TRANSLATORS: the user didn't read the man page */ g_print ("%s: %s\n", _("Failed to parse arguments"), error->message); return EXIT_FAILURE; } /* set verbose? */ if (verbose) { g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); } else { g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fu_util_ignore_cb, NULL); } /* nothing specified */ if (!action_enable && !action_info && !action_list && !action_log && !action_set_debug && !action_supported && !action_unset_debug && !action_version) { g_autofree gchar *tmp = NULL; tmp = g_option_context_get_help (priv->context, TRUE, NULL); g_printerr ("%s\n\n%s", _("No action specified!"), tmp); return EXIT_FAILURE; } /* action_version first */ if (action_version) g_print ("fwupd version: %s\n", PACKAGE_VERSION); /* override the default ESP path */ if (esp_path != NULL) { if (!fu_uefi_check_esp_path (esp_path, &error)) { /* TRANSLATORS: ESP is EFI System Partition */ g_print ("%s: %s\n", _("ESP specified was not valid"), error->message); return EXIT_FAILURE; } } else { esp_path = fu_uefi_guess_esp_path (); if (esp_path == NULL) { g_printerr ("Unable to determine EFI system partition " "location, override using --esp-path\n"); return EXIT_FAILURE; } } /* check free space */ if (!fu_uefi_check_esp_free_space (esp_path, FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE, &error)) { g_printerr ("Unable to use EFI system partition: %s\n", error->message); return EXIT_FAILURE; } g_debug ("ESP mountpoint set as %s", esp_path); /* show the debug action_log from the last attempted update */ if (action_log) { gsize sz = 0; g_autofree guint8 *buf = NULL; g_autofree guint16 *buf_ucs2 = NULL; g_autofree gchar *str = NULL; g_autoptr(GError) error_local = NULL; if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, "FWUPDATE_DEBUG_LOG", &buf, &sz, NULL, &error_local)) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } buf_ucs2 = g_new0 (guint16, (sz / 2) + 1); memcpy (buf_ucs2, buf, sz); str = fu_ucs2_to_uft8 (buf_ucs2, sz / 2); g_print ("%s", str); } if (action_list || action_supported || action_info) { g_autoptr(GPtrArray) entries = NULL; g_autofree gchar *esrt_path = NULL; g_autofree gchar *sysfsfwdir = NULL; g_autoptr(GError) error_local = NULL; /* get the directory of ESRT entries */ sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error_local); if (entries == NULL) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } /* add each device */ devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); g_autoptr(GError) error_parse = NULL; g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); if (dev == NULL) { g_warning ("failed to parse %s: %s", path, error_parse->message); continue; } fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); g_ptr_array_add (devices, g_object_ref (dev)); } } /* action_list action_supported firmware updates */ if (action_list) { for (guint i = 0; i < devices->len; i++) { FuUefiDevice *dev = g_ptr_array_index (devices, i); g_print ("%s type, {%s} action_version %" G_GUINT32_FORMAT " can be updated " "to any action_version above %" G_GUINT32_FORMAT "\n", fu_uefi_device_kind_to_string (fu_uefi_device_get_kind (dev)), fu_uefi_device_get_guid (dev), fu_uefi_device_get_version (dev), fu_uefi_device_get_version_lowest (dev) - 1); } } /* query for firmware update support */ if (action_supported) { if (devices->len > 0) { g_print ("%s\n", _("Firmware updates are supported on this machine.")); } else { g_print ("%s\n", _("Firmware updates are not supported on this machine.")); } } /* show the information of firmware update status */ if (action_info) { for (guint i = 0; i < devices->len; i++) { FuUefiDevice *dev = g_ptr_array_index (devices, i); g_autoptr(FuUefiUpdateInfo) info = NULL; g_autoptr(GError) error_local = NULL; /* load any existing update info */ info = fu_uefi_device_load_update_info (dev, &error_local); if (info == NULL) { g_printerr ("failed: %s\n", error_local->message); continue; } g_print ("Information for the update status entry %u:\n", i); g_print (" Information Version: %" G_GUINT32_FORMAT "\n", fu_uefi_update_info_get_version (info)); g_print (" Firmware GUID: {%s}\n", fu_uefi_update_info_get_guid (info)); g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", fu_uefi_update_info_get_capsule_flags (info)); g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", fu_uefi_update_info_get_hw_inst (info)); g_print (" Update Status: %s\n", fu_uefi_update_info_status_to_string (fu_uefi_update_info_get_status (info))); g_print (" Capsule File Path: %s\n\n", fu_uefi_update_info_get_capsule_fn (info)); } } /* action_enable firmware update support on action_supported systems */ if (action_enable) { g_printerr ("Unsupported, use `fwupdmgr unlock`\n"); return EXIT_FAILURE; } /* set the debugging flag during update */ if (action_set_debug) { const guint8 data = 1; g_autoptr(GError) error_local = NULL; if (!fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_FWUPDATE, "FWUPDATE_VERBOSE", &data, sizeof(data), EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, &error_local)) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } g_print ("%s\n", _("Enabled fwupdate debugging")); } /* unset the debugging flag during update */ if (action_unset_debug) { g_autoptr(GError) error_local = NULL; if (!fu_uefi_vars_delete (FU_UEFI_VARS_GUID_FWUPDATE, "FWUPDATE_VERBOSE", &error_local)) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } g_print ("%s\n", _("Disabled fwupdate debugging")); } /* apply firmware updates */ if (apply != NULL) { g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_guid (apply); g_autoptr(GError) error_local = NULL; g_autoptr(GBytes) fw = fu_common_get_contents_bytes (argv[1], &error_local); if (fw == NULL) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } if (!fu_device_write_firmware (FU_DEVICE (dev), fw, &error_local)) { g_printerr ("failed: %s\n", error_local->message); return EXIT_FAILURE; } } /* success */ return EXIT_SUCCESS; }
static gboolean fu_altos_device_probe_bootloader (FuAltosDevice *self, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; g_auto(GStrv) lines = NULL; g_autoptr(GString) str = NULL; /* get tty for upload */ if (!fu_altos_device_find_tty (self, error)) return FALSE; locker = fu_device_locker_new_full (self, (FuDeviceLockerFunc) fu_altos_device_tty_open, (FuDeviceLockerFunc) fu_altos_device_tty_close, error); if (locker == NULL) return FALSE; /* get the version information */ if (!fu_altos_device_tty_write (self, "v\n", -1, error)) return FALSE; str = fu_altos_device_tty_read (self, 100, -1, error); if (str == NULL) return FALSE; /* parse each line */ lines = g_strsplit_set (str->str, "\n\r", -1); for (guint i = 0; lines[i] != NULL; i++) { /* ignore */ if (lines[i][0] == '\0') continue; if (g_str_has_prefix (lines[i], "manufacturer ")) continue; if (g_str_has_prefix (lines[i], "product ")) continue; /* we can flash firmware */ if (g_strcmp0 (lines[i], "altos-loader") == 0) { fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); continue; } /* version number */ if (g_str_has_prefix (lines[i], "software-version ")) { fu_device_set_version (FU_DEVICE (self), lines[i] + 17); continue; } /* address base and bound */ if (g_str_has_prefix (lines[i], "flash-range ")) { g_auto(GStrv) addrs = g_strsplit (lines[i] + 17, " ", -1); self->addr_base = g_ascii_strtoull (addrs[0], NULL, 16); self->addr_bound = g_ascii_strtoull (addrs[1], NULL, 16); g_debug ("base: %x, bound: %x", (guint) self->addr_base, (guint) self->addr_bound); continue; } /* unknown line */ g_debug ("unknown data: '%s'", lines[i]); } return TRUE; }