thelio-io: Add a plugin to detach the Thelio IO board

This does not use the DFU runtime to detach.
This commit is contained in:
Richard Hughes 2019-09-06 00:25:06 +01:00
parent a1f9d5850b
commit 59593b0c50
10 changed files with 267 additions and 0 deletions

View File

@ -336,6 +336,7 @@ rm ${RPM_BUILD_ROOT}%{_sbindir}/flashrom
%if 0%{?enable_dummy} %if 0%{?enable_dummy}
%{_libdir}/fwupd-plugins-3/libfu_plugin_test.so %{_libdir}/fwupd-plugins-3/libfu_plugin_test.so
%endif %endif
%{_libdir}/fwupd-plugins-3/libfu_plugin_thelio_io.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_thunderbolt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_thunderbolt.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_thunderbolt_power.so %{_libdir}/fwupd-plugins-3/libfu_plugin_thunderbolt_power.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_udev.so %{_libdir}/fwupd-plugins-3/libfu_plugin_udev.so

View File

@ -12,6 +12,7 @@ subdir('solokey')
subdir('synaptics-cxaudio') subdir('synaptics-cxaudio')
subdir('synaptics-prometheus') subdir('synaptics-prometheus')
subdir('test') subdir('test')
subdir('thelio-io')
subdir('udev') subdir('udev')
subdir('unifying') subdir('unifying')
subdir('upower') subdir('upower')

View File

@ -0,0 +1,17 @@
Thelio IO Support
=================
Introduction
------------
This plugin is used to detach the Thelio IO device to DFU mode.
To switch to this mode `1` has to be written to the `bootloader` file
in sysfs.
GUID Generation
---------------
These devices use the standard USB DeviceInstanceId values, e.g.
* `USB\VID_1209&PID_1776&REV_0001`

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2019 Jeremy Soller <jeremy@system76.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-plugin-vfuncs.h"
#include "fu-thelio-io-device.h"
void
fu_plugin_init (FuPlugin *plugin)
{
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN);
}
gboolean
fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error)
{
g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error);
if (locker == NULL)
return FALSE;
if (!fu_device_detach (device, error))
return FALSE;
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
return TRUE;
}
gboolean
fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error)
{
g_autoptr(FuThelioIoDevice) dev = NULL;
g_autoptr(FuDeviceLocker) locker = NULL;
dev = fu_thelio_io_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;
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2019 Jeremy Soller <jeremy@system76.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-io-channel.h"
#include "fu-thelio-io-device.h"
struct _FuThelioIoDevice {
FuUsbDevice parent_instance;
};
G_DEFINE_TYPE (FuThelioIoDevice, fu_thelio_io_device, FU_TYPE_USB_DEVICE)
static gboolean
fu_thelio_io_device_probe (FuDevice *device, GError **error)
{
const gchar *devpath;
g_autofree gchar *fn = NULL;
g_autofree gchar *buf = NULL;
g_autoptr(GUdevDevice) udev_device = NULL;
fu_device_add_instance_id (device, "USB\\VID_03EB&PID_2FF4");
/* convert GUsbDevice to GUdevDevice */
udev_device = fu_usb_device_find_udev_device (FU_USB_DEVICE (device), error);
if (udev_device == NULL)
return FALSE;
devpath = g_udev_device_get_sysfs_path (udev_device);
if (G_UNLIKELY (devpath == NULL)) {
g_set_error_literal (error,
FWUPD_ERROR, FWUPD_ERROR_INTERNAL,
"Could not determine sysfs path for device");
return FALSE;
}
fn = g_build_filename (devpath, "revision", NULL);
if (!g_file_get_contents(fn, &buf, NULL, error))
return FALSE;
fu_device_set_version (device, (const gchar *) buf, FWUPD_VERSION_FORMAT_TRIPLET);
return TRUE;
}
static gboolean
fu_thelio_io_device_detach (FuDevice *device, GError **error)
{
const gchar *devpath;
g_autofree gchar *fn = NULL;
g_autoptr(FuIOChannel) io_channel = NULL;
g_autoptr(GUdevDevice) udev_device = NULL;
const guint8 buf[] = { '1', '\n' };
/* convert GUsbDevice to GUdevDevice */
udev_device = fu_usb_device_find_udev_device (FU_USB_DEVICE (device), error);
if (udev_device == NULL)
return FALSE;
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
devpath = g_udev_device_get_sysfs_path (udev_device);
if (G_UNLIKELY (devpath == NULL)) {
g_set_error_literal (error,
FWUPD_ERROR, FWUPD_ERROR_INTERNAL,
"Could not determine sysfs path for device");
return FALSE;
}
fn = g_build_filename (devpath, "bootloader", NULL);
io_channel = fu_io_channel_new_file (fn, error);
if (io_channel == NULL)
return FALSE;
return fu_io_channel_write_raw (io_channel, buf, sizeof(buf),
500, FU_IO_CHANNEL_FLAG_SINGLE_SHOT, error);
}
static void
fu_thelio_io_device_init (FuThelioIoDevice *self)
{
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
}
static void
fu_thelio_io_device_class_init (FuThelioIoDeviceClass *klass)
{
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
klass_device->probe = fu_thelio_io_device_probe;
klass_device->detach = fu_thelio_io_device_detach;
}
FuThelioIoDevice *
fu_thelio_io_device_new (FuUsbDevice *device)
{
FuThelioIoDevice *self = g_object_new (FU_TYPE_THELIO_IO_DEVICE, NULL);
fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device));
return self;
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2019 Jeremy Soller <jeremy@system76.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include "fu-plugin.h"
G_BEGIN_DECLS
#define FU_TYPE_THELIO_IO_DEVICE (fu_thelio_io_device_get_type ())
G_DECLARE_FINAL_TYPE (FuThelioIoDevice, fu_thelio_io_device, FU, THELIO_IO_DEVICE, FuUsbDevice)
FuThelioIoDevice *fu_thelio_io_device_new (FuUsbDevice *device);
G_END_DECLS

View File

@ -0,0 +1,27 @@
cargs = ['-DG_LOG_DOMAIN="FuPluginThelioIo"']
install_data(['thelio-io.quirk'],
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
)
shared_module('fu_plugin_thelio_io',
fu_hash,
sources : [
'fu-plugin-thelio-io.c',
'fu-thelio-io-device.c',
],
include_directories : [
include_directories('../..'),
include_directories('../../src'),
include_directories('../../libfwupd'),
],
install : true,
install_dir: plugin_dir,
link_with : [
libfwupdprivate,
],
c_args : cargs,
dependencies : [
plugin_deps,
],
)

View File

@ -0,0 +1,3 @@
# System76 Thelio IO
[DeviceInstanceId=USB\VID_1209&PID_1776&REV_0001]
Plugin = thelio_io

View File

@ -388,6 +388,55 @@ fu_usb_device_set_dev (FuUsbDevice *device, GUsbDevice *usb_device)
g_usb_device_get_platform_id (usb_device)); g_usb_device_get_platform_id (usb_device));
} }
/**
* fu_usb_device_find_udev_device:
* @device: A #FuUsbDevice
* @usb_device: A #GUsbDevice, or %NULL
*
* Gets the matching #GUdevDevice for the #GUsbDevice.
*
* Returns: a #GUdevDevice, or NULL if unset or invalid
*
* Since: 1.3.2
**/
GUdevDevice *
fu_usb_device_find_udev_device (FuUsbDevice *device, GError **error)
{
FuUsbDevicePrivate *priv = GET_PRIVATE (device);
g_autoptr(GList) devices = NULL;
g_autoptr(GUdevClient) gudev_client = g_udev_client_new (NULL);
/* find all tty devices */
devices = g_udev_client_query_by_subsystem (gudev_client, "usb");
for (GList *l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = G_UDEV_DEVICE (l->data);
/* check correct device */
if (g_udev_device_get_sysfs_attr_as_int (dev, "busnum") !=
g_usb_device_get_bus (priv->usb_device))
continue;
if (g_udev_device_get_sysfs_attr_as_int (dev, "devnum") !=
g_usb_device_get_address (priv->usb_device))
continue;
/* success */
g_debug ("USB device %u:%u is %s",
g_usb_device_get_bus (priv->usb_device),
g_usb_device_get_address (priv->usb_device),
g_udev_device_get_sysfs_path (dev));
return g_object_ref (dev);
}
/* failure */
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"could not find sysfs device for %u:%u",
g_usb_device_get_bus (priv->usb_device),
g_usb_device_get_address (priv->usb_device));
return NULL;
}
/** /**
* fu_usb_device_get_dev: * fu_usb_device_get_dev:
* @device: A #FuUsbDevice * @device: A #FuUsbDevice

View File

@ -8,6 +8,7 @@
#include <glib-object.h> #include <glib-object.h>
#include <gusb.h> #include <gusb.h>
#include <gudev/gudev.h>
#include "fu-plugin.h" #include "fu-plugin.h"
@ -45,5 +46,7 @@ GUsbDevice *fu_usb_device_get_dev (FuUsbDevice *device);
void fu_usb_device_set_dev (FuUsbDevice *device, void fu_usb_device_set_dev (FuUsbDevice *device,
GUsbDevice *usb_device); GUsbDevice *usb_device);
gboolean fu_usb_device_is_open (FuUsbDevice *device); gboolean fu_usb_device_is_open (FuUsbDevice *device);
GUdevDevice *fu_usb_device_find_udev_device (FuUsbDevice *device,
GError **error);
G_END_DECLS G_END_DECLS