diff --git a/plugins/unifying/Makefile.am b/plugins/unifying/Makefile.am index 3f397f638..fc55efc46 100644 --- a/plugins/unifying/Makefile.am +++ b/plugins/unifying/Makefile.am @@ -6,13 +6,16 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/libfwupd \ -I$(top_srcdir)/src +FWUPD_LIBS = \ + $(top_builddir)/libfwupd/libfwupd.la + plugindir = $(libdir)/fwupd-plugins-2 plugin_LTLIBRARIES = libfu_plugin_unifying.la libfu_plugin_unifying_la_SOURCES = \ - fu-plugin-unifying.c \ - unifying-dongle.c \ - unifying-dongle.h + fu-device-unifying.c \ + fu-device-unifying.h \ + fu-plugin-unifying.c libfu_plugin_unifying_la_LIBADD = $(GUSB_LIBS) libfu_plugin_unifying_la_LDFLAGS = -module -avoid-version libfu_plugin_unifying_la_CFLAGS = $(WARN_CFLAGS) \ @@ -21,16 +24,19 @@ libfu_plugin_unifying_la_CFLAGS = $(WARN_CFLAGS) \ EXTRA_DIST = README.md noinst_PROGRAMS = \ - unifying-tool + fu-unifying-tool -unifying_tool_SOURCES = \ - unifying-dongle.c \ - unifying-dongle.h \ - unifying-tool.c +fu_unifying_tool_SOURCES = \ + fu-device-unifying.c \ + fu-device-unifying.h \ + ../../src/fu-device.c \ + ../../src/fu-device.h \ + fu-unifying-tool.c -unifying_tool_LDADD = \ +fu_unifying_tool_LDADD = \ $(lib_LTLIBRARIES) \ $(APPSTREAM_GLIB_LIBS) \ + $(FWUPD_LIBS) \ $(GLIB_LIBS) \ $(GUSB_LIBS) \ $(LIBM) diff --git a/plugins/unifying/unifying-dongle.c b/plugins/unifying/fu-device-unifying.c similarity index 69% rename from plugins/unifying/unifying-dongle.c rename to plugins/unifying/fu-device-unifying.c index 06c64e1fa..865abb749 100644 --- a/plugins/unifying/unifying-dongle.c +++ b/plugins/unifying/fu-device-unifying.c @@ -24,12 +24,12 @@ #include #include -#include "unifying-dongle.h" +#include "fu-device-unifying.h" #define UNIFYING_REQUEST_SET_REPORT 0x09 -#define UNIFYING_DONGLE_TIMEOUT_MS 2500 -#define UNIFYING_DONGLE_EP1 0x81 -#define UNIFYING_DONGLE_EP3 0x83 +#define FU_DEVICE_UNIFYING_TIMEOUT_MS 2500 +#define FU_DEVICE_UNIFYING_EP1 0x81 +#define FU_DEVICE_UNIFYING_EP3 0x83 /* * Based on the HID++ documentation provided by Nestor Lopez Casado at: @@ -123,16 +123,13 @@ typedef enum { typedef struct { - UnifyingDongleKind kind; + FuDeviceUnifyingKind kind; GUsbDevice *usb_device; - gchar *guid; - gchar *version_firmware; - gchar *version_bootloader; -} UnifyingDonglePrivate; +} FuDeviceUnifyingPrivate; -G_DEFINE_TYPE_WITH_PRIVATE (UnifyingDongle, unifying_dongle, G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_PRIVATE (FuDeviceUnifying, fu_device_unifying, FU_TYPE_DEVICE) -#define GET_PRIVATE(o) (unifying_dongle_get_instance_private (o)) +#define GET_PRIVATE(o) (fu_device_unifying_get_instance_private (o)) static void fu_unifying_dump_raw (const gchar *title, const guint8 *data, gsize len) @@ -151,73 +148,70 @@ fu_unifying_dump_raw (const gchar *title, const guint8 *data, gsize len) g_debug ("%s", str->str); } -UnifyingDongleKind -unifying_dongle_kind_from_string (const gchar *kind) +FuDeviceUnifyingKind +fu_device_unifying_kind_from_string (const gchar *kind) { if (g_strcmp0 (kind, "runtime") == 0) - return UNIFYING_DONGLE_KIND_RUNTIME; + return FU_DEVICE_UNIFYING_KIND_RUNTIME; if (g_strcmp0 (kind, "bootloader-nordic") == 0) - return UNIFYING_DONGLE_KIND_BOOTLOADER_NORDIC; + return FU_DEVICE_UNIFYING_KIND_BOOTLOADER_NORDIC; if (g_strcmp0 (kind, "bootloader-texas") == 0) - return UNIFYING_DONGLE_KIND_BOOTLOADER_TEXAS; - return UNIFYING_DONGLE_KIND_UNKNOWN; + return FU_DEVICE_UNIFYING_KIND_BOOTLOADER_TEXAS; + return FU_DEVICE_UNIFYING_KIND_UNKNOWN; } const gchar * -unifying_dongle_kind_to_string (UnifyingDongleKind kind) +fu_device_unifying_kind_to_string (FuDeviceUnifyingKind kind) { - if (kind == UNIFYING_DONGLE_KIND_RUNTIME) + if (kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) return "runtime"; - if (kind == UNIFYING_DONGLE_KIND_BOOTLOADER_NORDIC) + if (kind == FU_DEVICE_UNIFYING_KIND_BOOTLOADER_NORDIC) return "bootloader-nordic"; - if (kind == UNIFYING_DONGLE_KIND_BOOTLOADER_TEXAS) + if (kind == FU_DEVICE_UNIFYING_KIND_BOOTLOADER_TEXAS) return "bootloader-texas"; return NULL; } static void -unifying_dongle_finalize (GObject *object) +fu_device_unifying_finalize (GObject *object) { - UnifyingDongle *dongle = UNIFYING_DONGLE (object); - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); + FuDeviceUnifying *device = FU_DEVICE_UNIFYING (object); + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); - g_free (priv->guid); - g_free (priv->version_firmware); - g_free (priv->version_bootloader); if (priv->usb_device != NULL) g_object_unref (priv->usb_device); - G_OBJECT_CLASS (unifying_dongle_parent_class)->finalize (object); + G_OBJECT_CLASS (fu_device_unifying_parent_class)->finalize (object); } static void -unifying_dongle_init (UnifyingDongle *dongle) +fu_device_unifying_init (FuDeviceUnifying *device) { } static void -unifying_dongle_class_init (UnifyingDongleClass *klass) +fu_device_unifying_class_init (FuDeviceUnifyingClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = unifying_dongle_finalize; + object_class->finalize = fu_device_unifying_finalize; } -UnifyingDongleKind -unifying_dongle_get_kind (UnifyingDongle *dongle) +FuDeviceUnifyingKind +fu_device_unifying_get_kind (FuDeviceUnifying *device) { - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); return priv->kind; } GUsbDevice * -unifying_dongle_get_usb_device (UnifyingDongle *dongle) +fu_device_unifying_get_usb_device (FuDeviceUnifying *device) { - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); return priv->usb_device; } static gboolean -unifying_dongle_send_command (UnifyingDongle *dongle, +fu_device_unifying_send_command (FuDeviceUnifying *device, guint16 value, guint16 idx, const guint8 *data_in, @@ -227,7 +221,7 @@ unifying_dongle_send_command (UnifyingDongle *dongle, guint8 endpoint, GError **error) { - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); gsize actual_length = 0; guint8 buf[32]; @@ -242,7 +236,7 @@ unifying_dongle_send_command (UnifyingDongle *dongle, value, idx, data_in, data_in_length, &actual_length, - UNIFYING_DONGLE_TIMEOUT_MS, + FU_DEVICE_UNIFYING_TIMEOUT_MS, NULL, error)) { g_prefix_error (error, "failed to send data: "); @@ -257,7 +251,7 @@ unifying_dongle_send_command (UnifyingDongle *dongle, buf, sizeof (buf), &actual_length, - UNIFYING_DONGLE_TIMEOUT_MS, + FU_DEVICE_UNIFYING_TIMEOUT_MS, NULL, error)) { g_prefix_error (error, "failed to get data: "); @@ -267,7 +261,7 @@ unifying_dongle_send_command (UnifyingDongle *dongle, /* emulated */ actual_length = data_out_length; } - fu_unifying_dump_raw ("dongle->host", buf, actual_length); + fu_unifying_dump_raw ("device->host", buf, actual_length); /* check sizes */ if (data_out != NULL) { @@ -275,7 +269,7 @@ unifying_dongle_send_command (UnifyingDongle *dongle, g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "dongle output %" G_GSIZE_FORMAT " bytes, " + "device output %" G_GSIZE_FORMAT " bytes, " "buffer size only %" G_GSIZE_FORMAT, actual_length, data_out_length); return FALSE; @@ -287,24 +281,24 @@ unifying_dongle_send_command (UnifyingDongle *dongle, } gboolean -unifying_dongle_detach (UnifyingDongle *dongle, GError **error) +fu_device_unifying_detach (FuDeviceUnifying *device, GError **error) { - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - const guint8 cmd[] = { HIDPP_REPORT_ID_SHORT, - HIDPP_RECEIVER_IDX, - HIDPP_SET_REGISTER_REQ, - HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE, - 0x49, 0x43, 0x50 /* value */}; + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); + guint8 cmd[] = { HIDPP_REPORT_ID_SHORT, + HIDPP_RECEIVER_IDX, + HIDPP_SET_REGISTER_REQ, + HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE, + 0x49, 0x43, 0x50 /* value */}; - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); + g_return_val_if_fail (FU_IS_DEVICE_UNIFYING (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* check kind */ - if (priv->kind != UNIFYING_DONGLE_KIND_RUNTIME) { + if (priv->kind != FU_DEVICE_UNIFYING_KIND_RUNTIME) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "dongle is not in runtime state"); + "device is not in runtime state"); return FALSE; } @@ -318,7 +312,7 @@ unifying_dongle_detach (UnifyingDongle *dongle, GError **error) 0x0210, 0x0002, cmd, sizeof (cmd), NULL, - UNIFYING_DONGLE_TIMEOUT_MS, + FU_DEVICE_UNIFYING_TIMEOUT_MS, NULL, error)) { g_prefix_error (error, "failed to detach to bootloader: "); @@ -329,20 +323,20 @@ unifying_dongle_detach (UnifyingDongle *dongle, GError **error) } gboolean -unifying_dongle_attach (UnifyingDongle *dongle, GError **error) +fu_device_unifying_attach (FuDeviceUnifying *device, GError **error) { - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); guint8 cmd[32]; - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); + g_return_val_if_fail (FU_IS_DEVICE_UNIFYING (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* check kind */ - if (priv->kind == UNIFYING_DONGLE_KIND_RUNTIME) { + if (priv->kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "dongle is not in bootloader state"); + "device is not in bootloader state"); return FALSE; } @@ -350,11 +344,11 @@ unifying_dongle_attach (UnifyingDongle *dongle, GError **error) memset (cmd, 0x0, sizeof(cmd)); cmd[0x0] = UNIFYING_BOOTLOADER_CMD_REBOOT; fu_unifying_dump_raw ("host->device", cmd, sizeof (cmd)); - if (!unifying_dongle_send_command (dongle, + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, cmd, sizeof (cmd), NULL, 0, - UNIFYING_DONGLE_EP1, + FU_DEVICE_UNIFYING_EP1, error)) { g_prefix_error (error, "failed to attach back to runtime: "); return FALSE; @@ -364,17 +358,17 @@ unifying_dongle_attach (UnifyingDongle *dongle, GError **error) } static gboolean -unifying_dongle_reset (UnifyingDongle *dongle, GError **error) +fu_device_unifying_reset (FuDeviceUnifying *device, GError **error) { const guint8 cmd[] = { HIDPP_REPORT_ID_SHORT, HIDPP_RECEIVER_IDX, HIDPP_GET_REGISTER_REQ, HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION, 0x00, 0x00, 0x00 }; - if (!unifying_dongle_send_command (dongle, 0x0210, 0x0002, + if (!fu_device_unifying_send_command (device, 0x0210, 0x0002, cmd, sizeof (cmd), NULL, 0, - UNIFYING_DONGLE_EP3, + FU_DEVICE_UNIFYING_EP3, error)) { g_prefix_error (error, "failed to reset"); return FALSE; @@ -383,26 +377,494 @@ unifying_dongle_reset (UnifyingDongle *dongle, GError **error) } gboolean -unifying_dongle_open (UnifyingDongle *dongle, GError **error) +fu_device_unifying_open (FuDeviceUnifying *device, GError **error) { - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - guint16 pid_for_guid = 0xffff; + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); guint i; guint num_interfaces = 0x1; g_autofree gchar *devid = NULL; - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); + g_return_val_if_fail (FU_IS_DEVICE_UNIFYING (device), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* emulated */ if (priv->usb_device == NULL) { - priv->version_firmware = g_strdup ("001.002.00003"); - priv->version_bootloader = g_strdup ("BL.004.005"); + fu_device_set_version (FU_DEVICE (device), "001.002.00003"); + fu_device_set_version_bootloader (FU_DEVICE (device), "BL.004.005"); return TRUE; } + /* open device */ + g_debug ("opening unifying device"); + if (!g_usb_device_open (priv->usb_device, error)) + return FALSE; + if (priv->kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) + num_interfaces = 0x03; + for (i = 0; i < num_interfaces; i++) { + g_debug ("claiming interface 0x%02x", i); + if (!g_usb_device_claim_interface (priv->usb_device, i, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "Failed to claim 0x%02x: ", i); + return FALSE; + } + } + + /* get config */ + if (priv->kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) { + guint8 config[10]; + guint8 buf[15]; + guint8 cmd[] = { HIDPP_REPORT_ID_SHORT, + HIDPP_RECEIVER_IDX, + HIDPP_GET_REGISTER_REQ, + HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION, + 0x00, 0x00, 0x00 }; + g_autofree gchar *version_fw = NULL; + g_autofree gchar *version_bl = NULL; + + g_debug ("clearing existing data"); + if (!fu_device_unifying_reset (device, error)) + return FALSE; + + /* read all 10 bytes of the version register */ + memset (config, 0x00, sizeof (config)); + for (i = 0; i < 0x05; i++) { + cmd[4] = i; + memset (buf, 0x00, sizeof (buf)); + if (!fu_device_unifying_send_command (device, 0x0210, 0x0002, + cmd, sizeof (cmd), + buf, sizeof (buf), + FU_DEVICE_UNIFYING_EP3, + error)) { + g_prefix_error (error, "failed to read config 0x%02x: ", i); + return FALSE; + } + memcpy (config + (i * 2), buf + 5, 2); + } + + /* logitech sends base 16 and then pads as if base 10... */ + version_fw = g_strdup_printf ("%03x.%03x.%02x%03x", + config[2], + config[3], + config[4], + config[5]); + version_bl = g_strdup_printf ("BL.%03x.%03x", + config[8], + config[9]); + fu_device_set_version (FU_DEVICE (device), version_fw); + fu_device_set_version_bootloader (FU_DEVICE (device), version_bl); + } else { + fu_device_set_version (FU_DEVICE (device), "000.000.00000"); + fu_device_set_version_bootloader (FU_DEVICE (device), "BL.000.000"); + } + + return TRUE; +} + +gboolean +fu_device_unifying_close (FuDeviceUnifying *device, GError **error) +{ + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); + guint i; + guint num_interfaces = 0x1; + + g_return_val_if_fail (FU_IS_DEVICE_UNIFYING (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* emulated */ + if (priv->usb_device == NULL) + return TRUE; + + if (priv->kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) + num_interfaces = 0x03; + for (i = 0; i < num_interfaces; i++) { + g_debug ("releasing interface 0x%02x", i); + if (!g_usb_device_release_interface (priv->usb_device, i, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "Failed to release 0x%02x: ", i); + return FALSE; + } + } + + g_debug ("closing device"); + if (!g_usb_device_close (priv->usb_device, error)) + return FALSE; + return TRUE; +} + +static guint8 +read_uint8 (const gchar *str) +{ + guint64 tmp; + gchar buf[3] = { 0x0, 0x0, 0x0 }; + memcpy (buf, str, 2); + tmp = g_ascii_strtoull (buf, NULL, 16); + return tmp; +} + +typedef struct { + guint8 op; + guint16 addr; + guint8 data[32]; + gsize data_len; +} FuDeviceUnifyingPayload; + +static GPtrArray * +fu_device_unifying_generate_payloads (GBytes *fw) +{ + GPtrArray *payloads; + const gchar *tmp; + g_auto(GStrv) lines = NULL; + + payloads = g_ptr_array_new_with_free_func (g_free); + tmp = g_bytes_get_data (fw, NULL); + lines = g_strsplit_set (tmp, "\n\r", -1); + for (guint i = 0; lines[i] != NULL; i++) { + FuDeviceUnifyingPayload *payload; + guint idx = 0x00; + + /* skip empty lines */ + tmp = lines[i]; + if (strlen (tmp) < 5) + continue; + + payload = g_new0 (FuDeviceUnifyingPayload, 1); + payload->op = read_uint8 (tmp + 0x01); + payload->addr = ((guint16) read_uint8 (tmp + 0x03)) << 8; + payload->addr |= read_uint8 (tmp + 0x05); + + /* read the data, but skip the checksum byte */ + for (guint j = 0x09; tmp[j + 2] != '\0'; j += 2) + payload->data[idx++] = read_uint8 (tmp + j); + payload->data_len = idx; + g_ptr_array_add (payloads, payload); + } + return payloads; +} + +static gboolean +fu_device_unifying_nordic_write_firmware (FuDeviceUnifying *device, + GBytes *fw, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error) +{ + const FuDeviceUnifyingPayload *payload; + g_autoptr(GPtrArray) payloads = NULL; + guint8 buf[32]; + + /* init firmware transfer */ + memset (buf, 0x0, sizeof(buf)); + buf[0x00] = UNIFYING_BOOTLOADER_CMD_INIT_TRANSFER; + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, + sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to init fw transfer: "); + return FALSE; + } + + /* erase firmware pages up to the bootloader */ + memset (buf, 0x0, sizeof(buf)); + for (guint i = 0; i < UNIFYING_FIRMWARE_SIZE; i += 0x200) { + buf[0x00] = UNIFYING_BOOTLOADER_CMD_ERASE_PAGE; + buf[0x01] = i << 8; + buf[0x02] = 0x00; + buf[0x03] = 0x01; + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to erase fw @0x%02x: ", i); + return FALSE; + } + } + + /* transfer payload */ + payloads = fu_device_unifying_generate_payloads (fw); + for (guint i = 1; i < payloads->len; i++) { + payload = g_ptr_array_index (payloads, i); + + /* skip the bootloader */ + if (payload->addr > UNIFYING_FIRMWARE_SIZE) + break; + + /* build packet */ + memset (buf, 0x00, sizeof (buf)); + buf[0x00] = UNIFYING_BOOTLOADER_CMD_PAYLOAD; + buf[0x01] = payload->addr >> 8; + buf[0x02] = payload->addr & 0xff; + buf[0x03] = payload->op; + memcpy (buf + 0x04, payload->data, payload->data_len); + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to transfer fw @0x%02x: ", i); + return FALSE; + } + if (progress_cb != NULL) { + progress_cb ((goffset) i * 32, + (goffset) payloads->len * 32, + progress_data); + } + } + + /* send the first managed packet last */ + payload = g_ptr_array_index (payloads, 0); + memset (buf, 0x00, sizeof (buf)); + buf[0x00] = UNIFYING_BOOTLOADER_CMD_PAYLOAD; + buf[0x01] = (payload->addr + 1) >> 8; + buf[0x02] = (payload->addr + 1) & 0xff; + buf[0x03] = payload->op - 1; + memcpy (buf + 0x04, payload->data + 1, payload->data_len - 1); + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to transfer fw start: "); + return FALSE; + } + + /* mark as complete */ + if (progress_cb != NULL) { + progress_cb ((goffset) payloads->len * 32, + (goffset) payloads->len * 32, + progress_data); + } + + /* completed upload */ + memset (buf, 0x0, sizeof(buf)); + buf[0x00] = UNIFYING_BOOTLOADER_CMD_PAYLOAD; + buf[0x01] = 0x00; + buf[0x02] = 0x00; + buf[0x03] = 0x01; + buf[0x04] = 0x02; + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to set completed: "); + return FALSE; + } + + /* success! */ + return TRUE; +} + +static gboolean +fu_device_unifying_texas_write_address (FuDeviceUnifying *device, + guint16 addr, + GError **error) +{ + guint8 buf[32]; + memset (buf, 0x00, sizeof (buf)); + if (addr == 0x0400) { + buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; + buf[0x01] = 0x00; + buf[0x02] = 0x00; + buf[0x03] = 0x01; + buf[0x04] = 0x00; + } else { + guint16 addr_tmp = addr - 0x80; + buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; + buf[0x01] = addr_tmp >> 8; + buf[0x02] = addr_tmp & 0xff; + buf[0x03] = 0x01; + buf[0x04] = 0x01; + } + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to set address @0x%04x: ", addr); + return FALSE; + } + memset (buf, 0x00, sizeof (buf)); + if (addr == 0x6c00) { + buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; + buf[0x01] = 0x00; + buf[0x02] = 0x00; + buf[0x03] = 0x01; + buf[0x04] = 0x03; + } else { + buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; + buf[0x01] = 0x00; + buf[0x02] = 0x00; + buf[0x03] = 0x01; + buf[0x04] = 0x02; + } + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to clear address @0x%04x: ", addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_device_unifying_texas_write_firmware (FuDeviceUnifying *device, + GBytes *fw, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error) +{ + const FuDeviceUnifyingPayload *payload; + guint16 last_set_addr = 0xffff; + guint8 buf[32]; + g_autoptr(GPtrArray) payloads = NULL; + + /* init firmware transfer */ + memset (buf, 0x0, sizeof(buf)); + buf[0x00] = UNIFYING_BOOTLOADER_CMD_INIT_TRANSFER; + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, + sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to init fw transfer: "); + return FALSE; + } + + /* transfer payload */ + payloads = fu_device_unifying_generate_payloads (fw); + for (guint i = 0; i < payloads->len; i++) { + payload = g_ptr_array_index (payloads, i); + + /* skip the bootloader */ + if (payload->addr >= UNIFYING_FIRMWARE_SIZE) + break; + + /* skip the header */ + if (payload->addr < 0x0400) + continue; + + /* skip record ??? */ + if (payload->op == 0x02) + continue; + + /* set address */ + if (last_set_addr == 0xffff || payload->addr - last_set_addr >= 0x80) { + if (!fu_device_unifying_texas_write_address (device, + payload->addr, + error)) + return FALSE; + last_set_addr = payload->addr; + } + + /* build packet */ + memset (buf, 0x00, sizeof (buf)); + buf[0x00] = UNIFYING_BOOTLOADER_CMD_WRITE_PAGE; + buf[0x01] = 0x00; + buf[0x02] = payload->addr & 0x7f; + buf[0x03] = payload->op; + memcpy (buf + 0x04, payload->data, payload->data_len); + if (!fu_device_unifying_send_command (device, 0x0200, 0x0000, + buf, sizeof (buf), + NULL, 0, + FU_DEVICE_UNIFYING_EP1, + error)) { + g_prefix_error (error, "failed to transfer fw @0x%02x: ", i); + return FALSE; + } + if (progress_cb != NULL) { + progress_cb ((goffset) i * 32, + (goffset) payloads->len * 32, + progress_data); + } + } + + /* finish page */ + if (!fu_device_unifying_texas_write_address (device, + last_set_addr + 0x80, + error)) + return FALSE; + + /* success! */ + return TRUE; +} + +gboolean +fu_device_unifying_write_firmware (FuDeviceUnifying *device, + GBytes *fw, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error) +{ + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); + + g_return_val_if_fail (FU_IS_DEVICE_UNIFYING (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* corrupt */ + if (g_bytes_get_size (fw) < 0x4000) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is too small"); + return FALSE; + } + + /* nordic style */ + if (priv->kind == FU_DEVICE_UNIFYING_KIND_BOOTLOADER_NORDIC) { + return fu_device_unifying_nordic_write_firmware (device, + fw, + progress_cb, + progress_data, + error); + } + + /* texas style */ + if (priv->kind == FU_DEVICE_UNIFYING_KIND_BOOTLOADER_TEXAS) { + return fu_device_unifying_texas_write_firmware (device, + fw, + progress_cb, + progress_data, + error); + } + + /* eeek */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "bootloader is not supported"); + return FALSE; +} + +/* now with kind and usb_device set */ +static void +fu_device_unifying_init_real (FuDeviceUnifying *device) +{ + FuDeviceUnifyingPrivate *priv = GET_PRIVATE (device); + guint16 pid_for_guid = 0xffff; + g_autofree gchar *devid = NULL; + g_autofree gchar *name = NULL; + + /* allowed, but requires manual bootloader step */ + fu_device_add_flag (FU_DEVICE (device), + FWUPD_DEVICE_FLAG_ALLOW_ONLINE); + + /* set default vendor */ + fu_device_set_vendor (FU_DEVICE (device), "Logitech"); + + /* generate name */ + name = g_strdup_printf ("Unifying [%s]", + fu_device_unifying_kind_to_string (priv->kind)); + /* generate GUID -- in runtime mode we have to use the release */ - if (priv->kind == UNIFYING_DONGLE_KIND_RUNTIME) { + if (priv->kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) { guint16 release = g_usb_device_get_release (priv->usb_device); switch (release &= 0xff00) { case 0x1200: @@ -423,517 +885,53 @@ unifying_dongle_open (UnifyingDongle *dongle, GError **error) devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X", g_usb_device_get_vid (priv->usb_device), pid_for_guid); - priv->guid = as_utils_guid_from_string (devid); - g_debug ("Using %s for GUID %s", devid, priv->guid); - /* open device */ - g_debug ("opening unifying device"); - if (!g_usb_device_open (priv->usb_device, error)) - return FALSE; - if (priv->kind == UNIFYING_DONGLE_KIND_RUNTIME) - num_interfaces = 0x03; - for (i = 0; i < num_interfaces; i++) { - g_debug ("claiming interface 0x%02x", i); - if (!g_usb_device_claim_interface (priv->usb_device, i, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "Failed to claim 0x%02x: ", i); - return FALSE; - } + fu_device_add_guid (FU_DEVICE (device), devid); + + /* only the bootloader can do the update */ + if (priv->kind == FU_DEVICE_UNIFYING_KIND_RUNTIME) { + fu_device_add_flag (FU_DEVICE (device), + FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } - - /* get config */ - if (priv->kind == UNIFYING_DONGLE_KIND_RUNTIME) { - guint8 config[10]; - guint8 buf[15]; - guint8 cmd[] = { HIDPP_REPORT_ID_SHORT, - HIDPP_RECEIVER_IDX, - HIDPP_GET_REGISTER_REQ, - HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION, - 0x00, 0x00, 0x00 }; - - g_debug ("clearing existing data"); - if (!unifying_dongle_reset (dongle, error)) - return FALSE; - - /* read all 10 bytes of the version register */ - memset (config, 0x00, sizeof (config)); - for (i = 0; i < 0x05; i++) { - cmd[4] = i; - memset (buf, 0x00, sizeof (buf)); - if (!unifying_dongle_send_command (dongle, 0x0210, 0x0002, - cmd, sizeof (cmd), - buf, sizeof (buf), - UNIFYING_DONGLE_EP3, - error)) { - g_prefix_error (error, "failed to read config 0x%02x: ", i); - return FALSE; - } - memcpy (config + (i * 2), buf + 5, 2); - } - - /* logitech sends base 16 and then pads as if base 10... */ - priv->version_firmware = g_strdup_printf ("%03x.%03x.%02x%03x", - config[2], - config[3], - config[4], - config[5]); - priv->version_bootloader = g_strdup_printf ("BL.%03x.%03x", - config[8], - config[9]); - } else { - priv->version_firmware = g_strdup ("000.000.00000"); - priv->version_bootloader = g_strdup ("BL.000.000"); - } - - return TRUE; } -gboolean -unifying_dongle_close (UnifyingDongle *dongle, GError **error) -{ - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - guint i; - guint num_interfaces = 0x1; - - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* emulated */ - if (priv->usb_device == NULL) - return TRUE; - - if (priv->kind == UNIFYING_DONGLE_KIND_RUNTIME) - num_interfaces = 0x03; - for (i = 0; i < num_interfaces; i++) { - g_debug ("releasing interface 0x%02x", i); - if (!g_usb_device_release_interface (priv->usb_device, i, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "Failed to release 0x%02x: ", i); - return FALSE; - } - } - - g_debug ("closing device"); - if (!g_usb_device_close (priv->usb_device, error)) - return FALSE; - return TRUE; -} - -const gchar * -unifying_dongle_get_guid (UnifyingDongle *dongle) -{ - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); - return priv->guid; -} - -const gchar * -unifying_dongle_get_version_fw (UnifyingDongle *dongle) -{ - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); - return priv->version_firmware; -} - -const gchar * -unifying_dongle_get_version_bl (UnifyingDongle *dongle) -{ - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); - return priv->version_bootloader; -} - -static guint8 -read_uint8 (const gchar *str) -{ - guint64 tmp; - gchar buf[3] = { 0x0, 0x0, 0x0 }; - memcpy (buf, str, 2); - tmp = g_ascii_strtoull (buf, NULL, 16); - return tmp; -} - -typedef struct { - guint8 op; - guint16 addr; - guint8 data[32]; - gsize data_len; -} UnifyingDonglePayload; - -static GPtrArray * -unifying_dongle_generate_payloads (GBytes *fw) -{ - GPtrArray *payloads; - const gchar *tmp; - g_auto(GStrv) lines = NULL; - - payloads = g_ptr_array_new_with_free_func (g_free); - tmp = g_bytes_get_data (fw, NULL); - lines = g_strsplit_set (tmp, "\n\r", -1); - for (guint i = 0; lines[i] != NULL; i++) { - UnifyingDonglePayload *payload; - guint idx = 0x00; - - /* skip empty lines */ - tmp = lines[i]; - if (strlen (tmp) < 5) - continue; - - payload = g_new0 (UnifyingDonglePayload, 1); - payload->op = read_uint8 (tmp + 0x01); - payload->addr = ((guint16) read_uint8 (tmp + 0x03)) << 8; - payload->addr |= read_uint8 (tmp + 0x05); - - /* read the data, but skip the checksum byte */ - for (guint j = 0x09; tmp[j + 2] != '\0'; j += 2) - payload->data[idx++] = read_uint8 (tmp + j); - payload->data_len = idx; - g_ptr_array_add (payloads, payload); - } - return payloads; -} - -static gboolean -unifying_dongle_nordic_write_firmware (UnifyingDongle *dongle, - GBytes *fw, - GFileProgressCallback progress_cb, - gpointer progress_data, - GError **error) -{ - const UnifyingDonglePayload *payload; - g_autoptr(GPtrArray) payloads = NULL; - guint8 buf[32]; - - /* init firmware transfer */ - memset (buf, 0x0, sizeof(buf)); - buf[0x00] = UNIFYING_BOOTLOADER_CMD_INIT_TRANSFER; - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, - sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to init fw transfer: "); - return FALSE; - } - - /* erase firmware pages up to the bootloader */ - memset (buf, 0x0, sizeof(buf)); - for (guint i = 0; i < UNIFYING_FIRMWARE_SIZE; i += 0x200) { - buf[0x00] = UNIFYING_BOOTLOADER_CMD_ERASE_PAGE; - buf[0x01] = i << 8; - buf[0x02] = 0x00; - buf[0x03] = 0x01; - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to erase fw @0x%02x: ", i); - return FALSE; - } - } - - /* transfer payload */ - payloads = unifying_dongle_generate_payloads (fw); - for (guint i = 1; i < payloads->len; i++) { - payload = g_ptr_array_index (payloads, i); - - /* skip the bootloader */ - if (payload->addr > UNIFYING_FIRMWARE_SIZE) - break; - - /* build packet */ - memset (buf, 0x00, sizeof (buf)); - buf[0x00] = UNIFYING_BOOTLOADER_CMD_PAYLOAD; - buf[0x01] = payload->addr >> 8; - buf[0x02] = payload->addr & 0xff; - buf[0x03] = payload->op; - memcpy (buf + 0x04, payload->data, payload->data_len); - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to transfer fw @0x%02x: ", i); - return FALSE; - } - if (progress_cb != NULL) { - progress_cb ((goffset) i * 32, - (goffset) payloads->len * 32, - progress_data); - } - } - - /* send the first managed packet last */ - payload = g_ptr_array_index (payloads, 0); - memset (buf, 0x00, sizeof (buf)); - buf[0x00] = UNIFYING_BOOTLOADER_CMD_PAYLOAD; - buf[0x01] = (payload->addr + 1) >> 8; - buf[0x02] = (payload->addr + 1) & 0xff; - buf[0x03] = payload->op - 1; - memcpy (buf + 0x04, payload->data + 1, payload->data_len - 1); - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to transfer fw start: "); - return FALSE; - } - - /* mark as complete */ - if (progress_cb != NULL) { - progress_cb ((goffset) payloads->len * 32, - (goffset) payloads->len * 32, - progress_data); - } - - /* completed upload */ - memset (buf, 0x0, sizeof(buf)); - buf[0x00] = UNIFYING_BOOTLOADER_CMD_PAYLOAD; - buf[0x01] = 0x00; - buf[0x02] = 0x00; - buf[0x03] = 0x01; - buf[0x04] = 0x02; - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to set completed: "); - return FALSE; - } - - /* success! */ - return TRUE; -} - -static gboolean -unifying_dongle_texas_write_address (UnifyingDongle *dongle, - guint16 addr, - GError **error) -{ - guint8 buf[32]; - memset (buf, 0x00, sizeof (buf)); - if (addr == 0x0400) { - buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; - buf[0x01] = 0x00; - buf[0x02] = 0x00; - buf[0x03] = 0x01; - buf[0x04] = 0x00; - } else { - guint16 addr_tmp = addr - 0x80; - buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; - buf[0x01] = addr_tmp >> 8; - buf[0x02] = addr_tmp & 0xff; - buf[0x03] = 0x01; - buf[0x04] = 0x01; - } - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to set address @0x%04x: ", addr); - return FALSE; - } - memset (buf, 0x00, sizeof (buf)); - if (addr == 0x6c00) { - buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; - buf[0x01] = 0x00; - buf[0x02] = 0x00; - buf[0x03] = 0x01; - buf[0x04] = 0x03; - } else { - buf[0x00] = UNIFYING_BOOTLOADER_CMD_SET_ADDRESS; - buf[0x01] = 0x00; - buf[0x02] = 0x00; - buf[0x03] = 0x01; - buf[0x04] = 0x02; - } - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to clear address @0x%04x: ", addr); - return FALSE; - } - return TRUE; -} - -static gboolean -unifying_dongle_texas_write_firmware (UnifyingDongle *dongle, - GBytes *fw, - GFileProgressCallback progress_cb, - gpointer progress_data, - GError **error) -{ - const UnifyingDonglePayload *payload; - guint16 last_set_addr = 0xffff; - guint8 buf[32]; - g_autoptr(GPtrArray) payloads = NULL; - - /* init firmware transfer */ - memset (buf, 0x0, sizeof(buf)); - buf[0x00] = UNIFYING_BOOTLOADER_CMD_INIT_TRANSFER; - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, - sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to init fw transfer: "); - return FALSE; - } - - /* transfer payload */ - payloads = unifying_dongle_generate_payloads (fw); - for (guint i = 0; i < payloads->len; i++) { - payload = g_ptr_array_index (payloads, i); - - /* skip the bootloader */ - if (payload->addr >= UNIFYING_FIRMWARE_SIZE) - break; - - /* skip the header */ - if (payload->addr < 0x0400) - continue; - - /* skip record ??? */ - if (payload->op == 0x02) - continue; - - /* set address */ - if (last_set_addr == 0xffff || payload->addr - last_set_addr >= 0x80) { - if (!unifying_dongle_texas_write_address (dongle, - payload->addr, - error)) - return FALSE; - last_set_addr = payload->addr; - } - - /* build packet */ - memset (buf, 0x00, sizeof (buf)); - buf[0x00] = UNIFYING_BOOTLOADER_CMD_WRITE_PAGE; - buf[0x01] = 0x00; - buf[0x02] = payload->addr & 0x7f; - buf[0x03] = payload->op; - memcpy (buf + 0x04, payload->data, payload->data_len); - if (!unifying_dongle_send_command (dongle, 0x0200, 0x0000, - buf, sizeof (buf), - NULL, 0, - UNIFYING_DONGLE_EP1, - error)) { - g_prefix_error (error, "failed to transfer fw @0x%02x: ", i); - return FALSE; - } - if (progress_cb != NULL) { - progress_cb ((goffset) i * 32, - (goffset) payloads->len * 32, - progress_data); - } - } - - /* finish page */ - if (!unifying_dongle_texas_write_address (dongle, - last_set_addr + 0x80, - error)) - return FALSE; - - /* success! */ - return TRUE; -} - -gboolean -unifying_dongle_write_firmware (UnifyingDongle *dongle, - GBytes *fw, - GFileProgressCallback progress_cb, - gpointer progress_data, - GError **error) -{ - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - - g_return_val_if_fail (UNIFYING_IS_DONGLE (dongle), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* corrupt */ - if (g_bytes_get_size (fw) < 0x4000) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware is too small"); - return FALSE; - } - - /* nordic style */ - if (priv->kind == UNIFYING_DONGLE_KIND_BOOTLOADER_NORDIC) { - return unifying_dongle_nordic_write_firmware (dongle, - fw, - progress_cb, - progress_data, - error); - } - - /* texas style */ - if (priv->kind == UNIFYING_DONGLE_KIND_BOOTLOADER_TEXAS) { - return unifying_dongle_texas_write_firmware (dongle, - fw, - progress_cb, - progress_data, - error); - } - - /* eeek */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "bootloader is not supported"); - return FALSE; -} - -typedef struct { - guint16 vid; - guint16 pid; -} UnifyingVidPid; - -UnifyingDongle * -unifying_dongle_new (GUsbDevice *usb_device) +FuDeviceUnifying * +fu_device_unifying_new (GUsbDevice *usb_device) { + FuDeviceUnifying *device; + FuDeviceUnifyingPrivate *priv; struct { guint16 vid; guint16 pid; - UnifyingDongleKind kind; - } vid_pids[] = { - { 0x046d, 0xc52b, UNIFYING_DONGLE_KIND_RUNTIME}, - { 0x046d, 0xaaaa, UNIFYING_DONGLE_KIND_BOOTLOADER_NORDIC}, - { 0x046d, 0xaaac, UNIFYING_DONGLE_KIND_BOOTLOADER_TEXAS}, + FuDeviceUnifyingKind kind; + } vidpids[] = { + { 0x046d, 0xc52b, FU_DEVICE_UNIFYING_KIND_RUNTIME}, + { 0x046d, 0xaaaa, FU_DEVICE_UNIFYING_KIND_BOOTLOADER_NORDIC}, + { 0x046d, 0xaaac, FU_DEVICE_UNIFYING_KIND_BOOTLOADER_TEXAS}, { 0x0000, 0x0000, 0 } }; - for (guint i = 0; vid_pids[i].vid != 0x0000; i++) { - if (g_usb_device_get_vid (usb_device) == vid_pids[i].vid && - g_usb_device_get_pid (usb_device) == vid_pids[i].pid) { - UnifyingDongle *dongle = g_object_new (UNIFYING_TYPE_DONGLE, NULL); - UnifyingDonglePrivate *priv = GET_PRIVATE (dongle); - priv->usb_device = g_object_ref (usb_device); - priv->kind = vid_pids[i].kind; - return dongle; - } + for (guint i = 0; vidpids[i].vid != 0x0000; i++) { + if (g_usb_device_get_vid (usb_device) != vidpids[i].vid) + continue; + if (g_usb_device_get_pid (usb_device) != vidpids[i].pid) + continue; + device = g_object_new (FU_TYPE_DEVICE_UNIFYING, NULL); + priv = GET_PRIVATE (device); + priv->kind = vidpids[i].kind; + priv->usb_device = g_object_ref (usb_device); + fu_device_unifying_init_real (device); + return device; } - return NULL; } -UnifyingDongle * -unifying_dongle_emulated_new (UnifyingDongleKind kind) +FuDeviceUnifying * +fu_device_unifying_emulated_new (FuDeviceUnifyingKind kind) { - UnifyingDongle *dongle; - UnifyingDonglePrivate *priv; - dongle = g_object_new (UNIFYING_TYPE_DONGLE, NULL); - priv = GET_PRIVATE (dongle); + FuDeviceUnifying *device; + FuDeviceUnifyingPrivate *priv; + device = g_object_new (FU_TYPE_DEVICE_UNIFYING, NULL); + priv = GET_PRIVATE (device); priv->kind = kind; - return dongle; + return device; } diff --git a/plugins/unifying/fu-device-unifying.h b/plugins/unifying/fu-device-unifying.h new file mode 100644 index 000000000..adcf67c40 --- /dev/null +++ b/plugins/unifying/fu-device-unifying.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2016 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __FU_DEVICE_UNIFYING_H +#define __FU_DEVICE_UNIFYING_H + +#include +#include + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DEVICE_UNIFYING (fu_device_unifying_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDeviceUnifying, fu_device_unifying, FU, DEVICE_UNIFYING, FuDevice) + +struct _FuDeviceUnifyingClass +{ + FuDeviceClass parent_class; +}; + +typedef enum { + FU_DEVICE_UNIFYING_KIND_UNKNOWN, + FU_DEVICE_UNIFYING_KIND_RUNTIME, + FU_DEVICE_UNIFYING_KIND_BOOTLOADER_NORDIC, + FU_DEVICE_UNIFYING_KIND_BOOTLOADER_TEXAS, + /*< private >*/ + FU_DEVICE_UNIFYING_KIND_LAST +} FuDeviceUnifyingKind; + +FuDeviceUnifying *fu_device_unifying_new (GUsbDevice *usb_device); +FuDeviceUnifying *fu_device_unifying_emulated_new (FuDeviceUnifyingKind kind); + +FuDeviceUnifyingKind fu_device_unifying_kind_from_string (const gchar *kind); +const gchar *fu_device_unifying_kind_to_string (FuDeviceUnifyingKind kind); + +FuDeviceUnifyingKind fu_device_unifying_get_kind (FuDeviceUnifying *device); +GUsbDevice *fu_device_unifying_get_usb_device (FuDeviceUnifying *device); + +gboolean fu_device_unifying_open (FuDeviceUnifying *device, + GError **error); +gboolean fu_device_unifying_detach (FuDeviceUnifying *device, + GError **error); +gboolean fu_device_unifying_attach (FuDeviceUnifying *device, + GError **error); +gboolean fu_device_unifying_close (FuDeviceUnifying *device, + GError **error); +gboolean fu_device_unifying_write_firmware (FuDeviceUnifying *device, + GBytes *fw, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error); + +G_END_DECLS + +#endif /* __FU_DEVICE_UNIFYING_H */ diff --git a/plugins/unifying/fu-plugin-unifying.c b/plugins/unifying/fu-plugin-unifying.c index aba311370..8fdf7db7b 100644 --- a/plugins/unifying/fu-plugin-unifying.c +++ b/plugins/unifying/fu-plugin-unifying.c @@ -28,20 +28,18 @@ #include "fu-plugin.h" #include "fu-plugin-vfuncs.h" -#include "unifying-dongle.h" +#include "fu-device-unifying.h" static gboolean fu_plugin_unifying_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) { - UnifyingDongleKind fu_unifying_kind; const gchar *platform_id = NULL; g_autofree gchar *name = NULL; g_autoptr(AsProfile) profile = as_profile_new (); g_autoptr(AsProfileTask) ptask = NULL; - g_autoptr(FuDevice) dev = NULL; - g_autoptr(UnifyingDongle) dongle = NULL; + g_autoptr(FuDeviceUnifying) dev = NULL; /* profile */ ptask = as_profile_start (profile, "FuPluginUnifying:added{%04x:%04x}", @@ -51,40 +49,27 @@ fu_plugin_unifying_device_added (FuPlugin *plugin, /* get version */ platform_id = g_usb_device_get_platform_id (usb_device); - dongle = unifying_dongle_new (usb_device); - if (dongle == NULL || - unifying_dongle_get_kind (dongle) == UNIFYING_DONGLE_KIND_UNKNOWN) { + dev = fu_device_unifying_new (usb_device); + if (dev == NULL || + fu_device_unifying_get_kind (dev) == FU_DEVICE_UNIFYING_KIND_UNKNOWN) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "invalid Logitech device type detected"); return FALSE; } + fu_device_set_id (FU_DEVICE (dev), platform_id); /* open the device */ - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (dev, error)) return FALSE; - /* generate name */ - fu_unifying_kind = unifying_dongle_get_kind (dongle); - name = g_strdup_printf ("Logitech Unifying [%s]", - unifying_dongle_kind_to_string (fu_unifying_kind)); - - /* create the device */ - dev = fu_device_new (); - fu_device_set_id (dev, platform_id); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_ALLOW_ONLINE); - fu_device_add_guid (dev, unifying_dongle_get_guid (dongle)); - fu_device_set_version (dev, unifying_dongle_get_version_fw (dongle)); - fu_device_set_version_bootloader (dev, unifying_dongle_get_version_bl (dongle)); - fu_device_set_name (dev, name); - /* close the device */ - if (!unifying_dongle_close (dongle, error)) + if (!fu_device_unifying_close (dev, error)) return FALSE; /* insert to hash */ - fu_plugin_device_add (plugin, dev); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); fu_plugin_cache_add (plugin, platform_id, dev); return TRUE; } @@ -101,7 +86,7 @@ fu_unifying_write_progress_cb (goffset current, goffset total, gpointer user_dat fu_plugin_set_percentage (plugin, (guint) percentage); } -static UnifyingDongle * +static FuDeviceUnifying * fu_plugin_unifying_get_dongle (FuPlugin *plugin, FuDevice *dev, GError **error) @@ -109,7 +94,7 @@ fu_plugin_unifying_get_dongle (FuPlugin *plugin, GUsbContext *usb_ctx = fu_plugin_get_usb_context (plugin); const gchar *platform_id; g_autoptr(GUsbDevice) usb_device = NULL; - g_autoptr(UnifyingDongle) dongle = NULL; + g_autoptr(FuDeviceUnifying) device = NULL; /* get version */ platform_id = fu_device_get_id (dev); @@ -118,32 +103,32 @@ fu_plugin_unifying_get_dongle (FuPlugin *plugin, error); if (usb_device == NULL) return NULL; - dongle = unifying_dongle_new (usb_device); - if (dongle == NULL) + device = fu_device_unifying_new (usb_device); + if (device == NULL) return NULL; - if (unifying_dongle_get_kind (dongle) == UNIFYING_DONGLE_KIND_UNKNOWN) { + if (fu_device_unifying_get_kind (device) == FU_DEVICE_UNIFYING_KIND_UNKNOWN) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "invalid Logitech device type detected"); return NULL; } - return g_steal_pointer (&dongle); + return g_steal_pointer (&device); } static gboolean fu_plugin_unifying_detach_cb (gpointer user_data) { - UnifyingDongle *dongle = UNIFYING_DONGLE (user_data); + FuDeviceUnifying *device = FU_DEVICE_UNIFYING (user_data); g_autoptr(GError) error = NULL; /* ditch this device */ g_debug ("detaching"); - if (!unifying_dongle_detach (dongle, &error)) { + if (!fu_device_unifying_detach (device, &error)) { g_warning ("failed to detach: %s", error->message); return FALSE; } - if (!unifying_dongle_close (dongle, &error)) { + if (!fu_device_unifying_close (device, &error)) { g_warning ("failed to close: %s", error->message); return FALSE; } @@ -159,47 +144,47 @@ fu_plugin_update_online (FuPlugin *plugin, GError **error) { GUsbContext *usb_ctx = fu_plugin_get_usb_context (plugin); - g_autoptr(UnifyingDongle) dongle = NULL; + g_autoptr(FuDeviceUnifying) device = NULL; /* get version */ - dongle = fu_plugin_unifying_get_dongle (plugin, dev, error); - if (dongle == NULL) + device = fu_plugin_unifying_get_dongle (plugin, dev, error); + if (device == NULL) return FALSE; - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (device, error)) return FALSE; /* switch to bootloader */ - if (unifying_dongle_get_kind (dongle) == UNIFYING_DONGLE_KIND_RUNTIME) { + if (fu_device_unifying_get_kind (device) == FU_DEVICE_UNIFYING_KIND_RUNTIME) { g_autoptr(GUsbDevice) usb_device = NULL; /* wait for device to come back */ - g_timeout_add (50, fu_plugin_unifying_detach_cb, dongle); + g_timeout_add (50, fu_plugin_unifying_detach_cb, device); usb_device = g_usb_context_wait_for_replug (usb_ctx, - unifying_dongle_get_usb_device (dongle), + fu_device_unifying_get_usb_device (device), 2000, error); if (usb_device == NULL) return FALSE; /* find new device */ - g_object_unref (dongle); - dongle = unifying_dongle_new (usb_device); - if (dongle == NULL) + g_object_unref (device); + device = fu_device_unifying_new (usb_device); + if (device == NULL) return FALSE; - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (device, error)) return FALSE; } /* write the firmware */ fu_plugin_set_status (plugin, FWUPD_STATUS_DEVICE_WRITE); - if (!unifying_dongle_write_firmware (dongle, blob_fw, + if (!fu_device_unifying_write_firmware (device, blob_fw, fu_unifying_write_progress_cb, plugin, error)) return FALSE; fu_plugin_set_status (plugin, FWUPD_STATUS_DEVICE_RESTART); - if (!unifying_dongle_attach (dongle, error)) + if (!fu_device_unifying_attach (device, error)) return FALSE; - if (!unifying_dongle_close (dongle, error)) + if (!fu_device_unifying_close (device, error)) return FALSE; /* success */ diff --git a/plugins/unifying/unifying-tool.c b/plugins/unifying/fu-unifying-tool.c similarity index 62% rename from plugins/unifying/unifying-tool.c rename to plugins/unifying/fu-unifying-tool.c index f76b13267..e4cdbd9fd 100644 --- a/plugins/unifying/unifying-tool.c +++ b/plugins/unifying/fu-unifying-tool.c @@ -23,16 +23,16 @@ #include #include -#include "unifying-dongle.h" +#include "fu-device-unifying.h" typedef struct { GCancellable *cancellable; GPtrArray *cmd_array; - UnifyingDongleKind emulation_kind; -} UnifyingToolPrivate; + FuDeviceUnifyingKind emulation_kind; +} FuUnifyingToolPrivate; static void -unifying_tool_private_free (UnifyingToolPrivate *priv) +fu_unifying_tool_private_free (FuUnifyingToolPrivate *priv) { if (priv == NULL) return; @@ -41,9 +41,9 @@ unifying_tool_private_free (UnifyingToolPrivate *priv) g_ptr_array_unref (priv->cmd_array); g_free (priv); } -G_DEFINE_AUTOPTR_CLEANUP_FUNC(UnifyingToolPrivate, unifying_tool_private_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUnifyingToolPrivate, fu_unifying_tool_private_free) -typedef gboolean (*UnifyingToolPrivateCb) (UnifyingToolPrivate *util, +typedef gboolean (*FuUnifyingToolPrivateCb) (FuUnifyingToolPrivate *util, gchar **values, GError **error); @@ -51,11 +51,11 @@ typedef struct { gchar *name; gchar *arguments; gchar *description; - UnifyingToolPrivateCb callback; -} UnifyingToolItem; + FuUnifyingToolPrivateCb callback; +} FuUnifyingToolItem; static void -unifying_tool_item_free (UnifyingToolItem *item) +fu_unifying_tool_item_free (FuUnifyingToolItem *item) { g_free (item->name); g_free (item->arguments); @@ -64,20 +64,20 @@ unifying_tool_item_free (UnifyingToolItem *item) } static gint -unifying_tool_sort_command_name_cb (UnifyingToolItem **item1, UnifyingToolItem **item2) +fu_unifying_tool_sort_command_name_cb (FuUnifyingToolItem **item1, FuUnifyingToolItem **item2) { return g_strcmp0 ((*item1)->name, (*item2)->name); } static void -unifying_tool_add (GPtrArray *array, +fu_unifying_tool_add (GPtrArray *array, const gchar *name, const gchar *arguments, const gchar *description, - UnifyingToolPrivateCb callback) + FuUnifyingToolPrivateCb callback) { guint i; - UnifyingToolItem *item; + FuUnifyingToolItem *item; g_auto(GStrv) names = NULL; g_return_if_fail (name != NULL); @@ -87,7 +87,7 @@ unifying_tool_add (GPtrArray *array, /* add each one */ names = g_strsplit (name, ",", -1); for (i = 0; names[i] != NULL; i++) { - item = g_new0 (UnifyingToolItem, 1); + item = g_new0 (FuUnifyingToolItem, 1); item->name = g_strdup (names[i]); if (i == 0) { item->description = g_strdup (description); @@ -101,13 +101,13 @@ unifying_tool_add (GPtrArray *array, } static gchar * -unifying_tool_get_descriptions (GPtrArray *array) +fu_unifying_tool_get_descriptions (GPtrArray *array) { guint i; gsize j; gsize len; const gsize max_len = 31; - UnifyingToolItem *item; + FuUnifyingToolItem *item; GString *string; /* print each command */ @@ -144,13 +144,13 @@ unifying_tool_get_descriptions (GPtrArray *array) } static gboolean -unifying_tool_run (UnifyingToolPrivate *priv, - const gchar *command, - gchar **values, - GError **error) +fu_unifying_tool_run (FuUnifyingToolPrivate *priv, + const gchar *command, + gchar **values, + GError **error) { guint i; - UnifyingToolItem *item; + FuUnifyingToolItem *item; /* find command */ for (i = 0; i < priv->cmd_array->len; i++) { @@ -167,10 +167,10 @@ unifying_tool_run (UnifyingToolPrivate *priv, return FALSE; } -static UnifyingDongle * -fu_unifying_get_default_dongle (UnifyingToolPrivate *priv, GError **error) +static FuDeviceUnifying * +fu_unifying_get_default_dongle (FuUnifyingToolPrivate *priv, GError **error) { - UnifyingDongle *dongle = NULL; + FuDeviceUnifying *device = NULL; g_autoptr(GUsbContext) usb_ctx = NULL; g_autoptr(GPtrArray) devices = NULL; @@ -184,54 +184,57 @@ fu_unifying_get_default_dongle (UnifyingToolPrivate *priv, GError **error) devices = g_usb_context_get_devices (usb_ctx); for (guint i = 0; i < devices->len; i++) { GUsbDevice *usb_dev_tmp = g_ptr_array_index (devices, i); - g_autoptr(UnifyingDongle) dev_tmp = unifying_dongle_new (usb_dev_tmp); + g_autoptr(FuDeviceUnifying) dev_tmp = fu_device_unifying_new (usb_dev_tmp); if (dev_tmp == NULL) continue; - if (unifying_dongle_get_kind (dev_tmp) != UNIFYING_DONGLE_KIND_UNKNOWN) { - dongle = g_object_ref (dev_tmp); + if (fu_device_unifying_get_kind (dev_tmp) != FU_DEVICE_UNIFYING_KIND_UNKNOWN) { + device = g_object_ref (dev_tmp); break; } } /* nothing supported */ - if (dongle == NULL) { + if (device == NULL) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No supported device plugged in"); return NULL; } - return dongle; + return device; } static gboolean -unifying_tool_info (UnifyingToolPrivate *priv, gchar **values, GError **error) +fu_unifying_tool_info (FuUnifyingToolPrivate *priv, gchar **values, GError **error) { - g_autoptr(UnifyingDongle) dongle = NULL; + g_autoptr(FuDeviceUnifying) device = NULL; /* open device */ - dongle = fu_unifying_get_default_dongle (priv, error); - if (dongle == NULL) + device = fu_unifying_get_default_dongle (priv, error); + if (device == NULL) return FALSE; - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (device, error)) return FALSE; /* show on console */ - g_debug ("Found %s", unifying_dongle_kind_to_string (unifying_dongle_get_kind (dongle))); - g_print ("Firmware Ver: %s\n", unifying_dongle_get_version_fw (dongle)); - g_print ("Bootloader Ver: %s\n", unifying_dongle_get_version_bl (dongle)); - g_print ("GUID: %s\n", unifying_dongle_get_guid (dongle)); + g_debug ("Found %s", fu_device_unifying_kind_to_string (fu_device_unifying_get_kind (device))); + g_print ("Firmware Ver: %s\n", + fu_device_get_version (FU_DEVICE (device))); + g_print ("Bootloader Ver: %s\n", + fu_device_get_version_bootloader (FU_DEVICE (device))); + g_print ("GUID: %s\n", + fu_device_get_guid_default (FU_DEVICE (device))); /* close device */ - return unifying_dongle_close (dongle, error); + return fu_device_unifying_close (device, error); } static void fu_unifying_write_progress_cb (goffset current, goffset total, gpointer user_data) { - UnifyingToolPrivate *priv = (UnifyingToolPrivate *) user_data; + FuUnifyingToolPrivate *priv = (FuUnifyingToolPrivate *) user_data; gdouble percentage = -1.f; - if (priv->emulation_kind != UNIFYING_DONGLE_KIND_UNKNOWN) + if (priv->emulation_kind != FU_DEVICE_UNIFYING_KIND_UNKNOWN) return; if (total > 0) percentage = (100.f * (gdouble) current) / (gdouble) total; @@ -240,12 +243,12 @@ fu_unifying_write_progress_cb (goffset current, goffset total, gpointer user_dat } static gboolean -unifying_tool_write (UnifyingToolPrivate *priv, gchar **values, GError **error) +fu_unifying_tool_write (FuUnifyingToolPrivate *priv, gchar **values, GError **error) { gsize len; g_autofree guint8 *data = NULL; g_autoptr(GBytes) fw = NULL; - g_autoptr(UnifyingDongle) dongle = NULL; + g_autoptr(FuDeviceUnifying) device = NULL; /* check args */ if (g_strv_length (values) != 1) { @@ -258,19 +261,19 @@ unifying_tool_write (UnifyingToolPrivate *priv, gchar **values, GError **error) } /* open device */ - if (priv->emulation_kind == UNIFYING_DONGLE_KIND_UNKNOWN) { - dongle = fu_unifying_get_default_dongle (priv, error); - if (dongle == NULL) + if (priv->emulation_kind == FU_DEVICE_UNIFYING_KIND_UNKNOWN) { + device = fu_unifying_get_default_dongle (priv, error); + if (device == NULL) return FALSE; } else { - dongle = unifying_dongle_emulated_new (priv->emulation_kind); + device = fu_device_unifying_emulated_new (priv->emulation_kind); } - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (device, error)) return FALSE; /* do we need to go into bootloader mode */ - if (unifying_dongle_get_kind (dongle) == UNIFYING_DONGLE_KIND_RUNTIME) { - if (!unifying_dongle_detach (dongle, error)) + if (fu_device_unifying_get_kind (device) == FU_DEVICE_UNIFYING_KIND_RUNTIME) { + if (!fu_device_unifying_detach (device, error)) return FALSE; g_print ("Switched to bootloader, now run again\n"); return TRUE; @@ -284,54 +287,54 @@ unifying_tool_write (UnifyingToolPrivate *priv, gchar **values, GError **error) /* update with data blob */ fw = g_bytes_new (data, len); - if (!unifying_dongle_write_firmware (dongle, fw, + if (!fu_device_unifying_write_firmware (device, fw, fu_unifying_write_progress_cb, priv, error)) return FALSE; /* detach back into runtime */ - if (!unifying_dongle_attach (dongle, error)) + if (!fu_device_unifying_attach (device, error)) return FALSE; - if (!unifying_dongle_close (dongle, error)) + if (!fu_device_unifying_close (device, error)) return FALSE; return TRUE; } static gboolean -unifying_tool_attach (UnifyingToolPrivate *priv, gchar **values, GError **error) +fu_unifying_tool_attach (FuUnifyingToolPrivate *priv, gchar **values, GError **error) { - g_autoptr(UnifyingDongle) dongle = NULL; - dongle = fu_unifying_get_default_dongle (priv, error); - if (dongle == NULL) + g_autoptr(FuDeviceUnifying) device = NULL; + device = fu_unifying_get_default_dongle (priv, error); + if (device == NULL) return FALSE; - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (device, error)) return FALSE; - if (!unifying_dongle_attach (dongle, error)) + if (!fu_device_unifying_attach (device, error)) return FALSE; - if (!unifying_dongle_close (dongle, error)) + if (!fu_device_unifying_close (device, error)) return FALSE; return TRUE; } static gboolean -unifying_tool_detach (UnifyingToolPrivate *priv, gchar **values, GError **error) +fu_unifying_tool_detach (FuUnifyingToolPrivate *priv, gchar **values, GError **error) { - g_autoptr(UnifyingDongle) dongle = NULL; - dongle = fu_unifying_get_default_dongle (priv, error); - if (dongle == NULL) + g_autoptr(FuDeviceUnifying) device = NULL; + device = fu_unifying_get_default_dongle (priv, error); + if (device == NULL) return FALSE; - if (!unifying_dongle_open (dongle, error)) + if (!fu_device_unifying_open (device, error)) return FALSE; - if (!unifying_dongle_detach (dongle, error)) + if (!fu_device_unifying_detach (device, error)) return FALSE; - if (!unifying_dongle_close (dongle, error)) + if (!fu_device_unifying_close (device, error)) return FALSE; return TRUE; } static void -unifying_tool_log_handler_cb (const gchar *log_domain, +fu_unifying_tool_log_handler_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) @@ -347,8 +350,8 @@ main (int argc, char **argv) g_autofree gchar *emulation_kind = NULL; g_autoptr(GError) error = NULL; g_autoptr(GOptionContext) context = NULL; - g_autoptr(UnifyingDongle) dongle = NULL; - g_autoptr(UnifyingToolPrivate) priv = g_new0 (UnifyingToolPrivate, 1); + g_autoptr(FuDeviceUnifying) device = NULL; + g_autoptr(FuUnifyingToolPrivate) priv = g_new0 (FuUnifyingToolPrivate, 1); const GOptionEntry options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Print verbose debug statements", NULL }, @@ -361,32 +364,32 @@ main (int argc, char **argv) priv->cancellable = g_cancellable_new (); /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) unifying_tool_item_free); - unifying_tool_add (priv->cmd_array, - "info", NULL, - "Show information about the device", - unifying_tool_info); - unifying_tool_add (priv->cmd_array, - "write", "FILENAME", - "Update the firmware", - unifying_tool_write); - unifying_tool_add (priv->cmd_array, - "attach", NULL, - "Attach to firmware mode", - unifying_tool_attach); - unifying_tool_add (priv->cmd_array, - "detach", NULL, - "Detach to bootloader mode", - unifying_tool_detach); + priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_unifying_tool_item_free); + fu_unifying_tool_add (priv->cmd_array, + "info", NULL, + "Show information about the device", + fu_unifying_tool_info); + fu_unifying_tool_add (priv->cmd_array, + "write", "FILENAME", + "Update the firmware", + fu_unifying_tool_write); + fu_unifying_tool_add (priv->cmd_array, + "attach", NULL, + "Attach to firmware mode", + fu_unifying_tool_attach); + fu_unifying_tool_add (priv->cmd_array, + "detach", NULL, + "Detach to bootloader mode", + fu_unifying_tool_detach); /* sort by command name */ g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) unifying_tool_sort_command_name_cb); + (GCompareFunc) fu_unifying_tool_sort_command_name_cb); /* get a list of the commands */ context = g_option_context_new (NULL); - cmd_descriptions = unifying_tool_get_descriptions (priv->cmd_array); + cmd_descriptions = fu_unifying_tool_get_descriptions (priv->cmd_array); g_option_context_set_summary (context, cmd_descriptions); g_set_application_name ("Logitech Unifying Debug Tool"); g_option_context_add_main_entries (context, options, NULL); @@ -396,16 +399,16 @@ main (int argc, char **argv) } /* emulate */ - priv->emulation_kind = unifying_dongle_kind_from_string (emulation_kind); - if (priv->emulation_kind != UNIFYING_DONGLE_KIND_UNKNOWN) - g_log_set_default_handler (unifying_tool_log_handler_cb, priv); + priv->emulation_kind = fu_device_unifying_kind_from_string (emulation_kind); + if (priv->emulation_kind != FU_DEVICE_UNIFYING_KIND_UNKNOWN) + g_log_set_default_handler (fu_unifying_tool_log_handler_cb, priv); /* set verbose? */ if (verbose) g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); /* run the specified command */ - if (!unifying_tool_run (priv, argv[1], (gchar**) &argv[2], &error)) { + if (!fu_unifying_tool_run (priv, argv[1], (gchar**) &argv[2], &error)) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_autofree gchar *tmp = NULL; tmp = g_option_context_get_help (context, TRUE, NULL); diff --git a/plugins/unifying/unifying-dongle.h b/plugins/unifying/unifying-dongle.h deleted file mode 100644 index 2ff78720d..000000000 --- a/plugins/unifying/unifying-dongle.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __UNIFYING_DONGLE_H -#define __UNIFYING_DONGLE_H - -#include -#include - -G_BEGIN_DECLS - -#define UNIFYING_TYPE_DONGLE (unifying_dongle_get_type ()) -G_DECLARE_DERIVABLE_TYPE (UnifyingDongle, unifying_dongle, UNIFYING, DONGLE, GObject) - -struct _UnifyingDongleClass -{ - GObjectClass parent_class; -}; - -typedef enum { - UNIFYING_DONGLE_KIND_UNKNOWN, - UNIFYING_DONGLE_KIND_RUNTIME, - UNIFYING_DONGLE_KIND_BOOTLOADER_NORDIC, - UNIFYING_DONGLE_KIND_BOOTLOADER_TEXAS, - UNIFYING_DONGLE_KIND_LAST -} UnifyingDongleKind; - -UnifyingDongle *unifying_dongle_new (GUsbDevice *usb_device); -UnifyingDongle *unifying_dongle_emulated_new (UnifyingDongleKind kind); - -UnifyingDongleKind unifying_dongle_kind_from_string (const gchar *kind); -const gchar *unifying_dongle_kind_to_string (UnifyingDongleKind kind); - -UnifyingDongleKind unifying_dongle_get_kind (UnifyingDongle *dongle); -const gchar *unifying_dongle_get_version_fw (UnifyingDongle *dongle); -const gchar *unifying_dongle_get_version_bl (UnifyingDongle *dongle); -const gchar *unifying_dongle_get_guid (UnifyingDongle *dongle); -GUsbDevice *unifying_dongle_get_usb_device (UnifyingDongle *dongle); - -gboolean unifying_dongle_open (UnifyingDongle *dongle, - GError **error); -gboolean unifying_dongle_detach (UnifyingDongle *dongle, - GError **error); -gboolean unifying_dongle_attach (UnifyingDongle *dongle, - GError **error); -gboolean unifying_dongle_close (UnifyingDongle *dongle, - GError **error); -gboolean unifying_dongle_write_firmware (UnifyingDongle *dongle, - GBytes *fw, - GFileProgressCallback progress_cb, - gpointer progress_data, - GError **error); - -G_END_DECLS - -#endif /* __UNIFYING_DONGLE_H */