mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-16 23:26:19 +00:00

Future metadata from the LVFS will set the protocol the firmware is expected to use. As vendors love to re-use common terms like DFU for incompatible protocols, namespace them with the controlling company ID with an approximate reverse DNS namespace. This also allows more than one plugin to define support for the same protocol, for instance rts54hid+rts54hub and synapticsmst+dell-dock.
181 lines
4.9 KiB
C
181 lines
4.9 KiB
C
/*
|
|
* Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupd.h>
|
|
|
|
#include "fu-plugin-vfuncs.h"
|
|
|
|
#include "fu-unifying-bootloader-nordic.h"
|
|
#include "fu-unifying-bootloader-texas.h"
|
|
#include "fu-unifying-common.h"
|
|
#include "fu-unifying-peripheral.h"
|
|
#include "fu-unifying-runtime.h"
|
|
|
|
gboolean
|
|
fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error)
|
|
{
|
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
|
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER))
|
|
return TRUE;
|
|
locker = fu_device_locker_new (device, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
return fu_device_detach (device, error);
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error)
|
|
{
|
|
g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
return fu_device_attach (device, error);
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error)
|
|
{
|
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
|
locker = fu_device_locker_new (device, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_update (FuPlugin *plugin,
|
|
FuDevice *device,
|
|
GBytes *blob_fw,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
return fu_device_write_firmware (device, blob_fw, error);
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_unifying_check_supported_device (FuPlugin *plugin, FuDevice *device)
|
|
{
|
|
GPtrArray *guids = fu_device_get_guids (device);
|
|
for (guint i = 0; i < guids->len; i++) {
|
|
const gchar *guid = g_ptr_array_index (guids, i);
|
|
if (fu_plugin_check_supported (plugin, guid))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error)
|
|
{
|
|
g_autoptr(FuDevice) dev = NULL;
|
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
|
|
|
/* interesting device? */
|
|
if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0)
|
|
return TRUE;
|
|
|
|
/* logitech */
|
|
if (fu_udev_device_get_vendor (device) != FU_UNIFYING_DEVICE_VID)
|
|
return TRUE;
|
|
|
|
/* runtime */
|
|
if (fu_device_has_custom_flag (FU_DEVICE (device), "is-receiver")) {
|
|
dev = g_object_new (FU_TYPE_UNIFYING_RUNTIME, NULL);
|
|
fu_device_incorporate (dev, FU_DEVICE (device));
|
|
} else {
|
|
|
|
/* create device so we can run ->probe() and add UFY GUIDs */
|
|
dev = g_object_new (FU_TYPE_UNIFYING_PERIPHERAL, NULL);
|
|
fu_device_incorporate (dev, FU_DEVICE (device));
|
|
if (!fu_device_probe (dev, error))
|
|
return FALSE;
|
|
|
|
/* there are a lot of unifying peripherals, but not all respond
|
|
* well to opening -- so limit to ones with issued updates */
|
|
if (!fu_plugin_unifying_check_supported_device (plugin, dev)) {
|
|
g_autofree gchar *guids = fu_device_get_guids_as_str (FU_DEVICE (device));
|
|
g_debug ("%s has no updates, so ignoring device", guids);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* open to get the version */
|
|
locker = fu_device_locker_new (dev, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
fu_plugin_device_add (plugin, dev);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error)
|
|
{
|
|
g_autoptr(FuDevice) dev = NULL;
|
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
|
|
|
/* logitech */
|
|
if (fu_usb_device_get_vid (device) != FU_UNIFYING_DEVICE_VID)
|
|
return TRUE;
|
|
|
|
/* check is bootloader */
|
|
if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
|
|
g_debug ("not in bootloader mode, ignoring");
|
|
return TRUE;
|
|
}
|
|
if (fu_device_has_custom_flag (FU_DEVICE (device), "is-nordic")) {
|
|
dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_NORDIC, NULL);
|
|
fu_device_incorporate (dev, FU_DEVICE (device));
|
|
} else if (fu_device_has_custom_flag (FU_DEVICE (device), "is-texas")) {
|
|
dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_TEXAS, NULL);
|
|
fu_device_incorporate (dev, FU_DEVICE (device));
|
|
g_usleep (200*1000);
|
|
}
|
|
|
|
/* not supported */
|
|
if (dev == NULL) {
|
|
g_set_error_literal (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"bootloader device not supported");
|
|
return FALSE;
|
|
}
|
|
|
|
/* open to get the version */
|
|
locker = fu_device_locker_new (dev, error);
|
|
if (locker == NULL)
|
|
return FALSE;
|
|
fu_plugin_device_add (plugin, dev);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
fu_plugin_startup (FuPlugin *plugin, GError **error)
|
|
{
|
|
/* check the kernel has CONFIG_HIDRAW */
|
|
if (!g_file_test ("/sys/class/hidraw", G_FILE_TEST_IS_DIR)) {
|
|
g_set_error_literal (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"no kernel support for CONFIG_HIDRAW");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
fu_plugin_init (FuPlugin *plugin)
|
|
{
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN);
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying");
|
|
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned");
|
|
fu_plugin_add_udev_subsystem (plugin, "hidraw");
|
|
}
|