Add a Udev firmware provider

This allows us to support showing firmware updates for VIA USB hubs
This commit is contained in:
Richard Hughes 2015-05-29 15:35:37 +01:00
parent a5f06a895d
commit ebb58a3495
9 changed files with 453 additions and 0 deletions

View File

@ -162,6 +162,13 @@ AC_ARG_WITH([systemdunitdir],
[with_systemdunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
AC_SUBST([systemdunitdir], [$with_systemdunitdir])
# udev rules
AC_ARG_WITH([udevrulesdir],
AS_HELP_STRING([--with-udevrulesdir=DIR], [Directory for udev rules files]),
[],
[with_udevrulesdir=$($PKG_CONFIG --variable=udevdir udev)/rules.d])
AC_SUBST([udevrulesdir], [$with_udevrulesdir])
dnl ---------------------------------------------------------------------------
dnl - Makefiles, etc.
dnl ---------------------------------------------------------------------------

View File

@ -94,6 +94,7 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';'
%dir %{_localstatedir}/cache/app-info
%dir %{_localstatedir}/cache/app-info/icons
%dir %{_localstatedir}/cache/app-info/xmls
/usr/lib/udev/rules.d/*.rules
%files devel
%{_includedir}/fwupd-1

View File

@ -0,0 +1,24 @@
########################################################################
# Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
#
# Licensed under the GNU General Public License Version 2
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# VIA USB 3.0 VL811 Hub
SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0810", ENV{FWUPD_GUID}="adbb9034-b577-42c2-a661-1ee4f49ef64c", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811 Hub"
# VIA USB 3.0 VL811+ Hub
SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0811", ENV{FWUPD_GUID}="54f84d05-c917-4c50-8b35-44feabaaa323", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811+ Hub"
# VIA USB 3.0 VL812 Hub
SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0812", ENV{FWUPD_GUID}="cd0314ec-b80f-4d1a-a24f-c409183a8b2d", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 Hub"
# VIA USB 3.0 VL812 B2 Hub
SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="2812", ENV{FWUPD_GUID}="26470009-97a8-4028-867a-bbbac6ee7bf0", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 B2 Hub"
ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=usb"

View File

@ -25,7 +25,11 @@ install-data-hook:
mkdir -p $(DESTDIR)$(systemdunitdir)/system-update.target.wants
ln -sf ../fwupd-offline-update.service $(DESTDIR)$(systemdunitdir)/system-update.target.wants/fwupd-offline-update.service
udevrules_DATA = \
90-fwupd-devices.rules
EXTRA_DIST = \
$(udevrules_DATA) \
$(dbusservicemain_in_files) \
$(systemdservice_in_files)

101
data/via-firmware.xml Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<components version="0.9" origin="VIA">
<!-- VL811
Latest=9.83
VL811: 36FC9E60-C465-11CF-8056-444553540000
http://www.via-labs.com/product_show.php?id=43
http://www.via-labs.com/archive/doc/Usb3HubFWUpgrade_Setup_V1.1_VL811_0983.zip
-->
<component type="firmware">
<id>adbb9034-b577-42c2-a661-1ee4f49ef64c</id>
<name>VL811 Firmware</name>
<summary>Firmware for VIA USB 3.0 hub</summary>
<developer_name>VIA</developer_name>
<url type="homepage">http://www.via.com.tw/</url>
<releases>
<release version="0983" timestamp="1400000000">
<description>
<p>This stable release fixes the following problems with USB 3.0:</p>
<ul>
<li>Do not wake during transition to S4</li>
<li>Do not drop from Apple USB 3.0 Host during S3/S4 and Device PnP</li>
<li>Do not drop during S3/S4 when connected to native Intel and AMD Hosts</li>
</ul>
<p>This stable release fixes the following problems with USB 2.0:</p>
<ul>
<li>Do not drop from Apple USB 3.0 Host during S3/S4 and Device PnP</li>
</ul>
</description>
</release>
</releases>
</component>
<!-- VL811+
Latest=9091 NO PRODUCTS, right?
Latest=9095 USB3-HUB81X4, UD-3000
http://www.via-labs.com/product_show.php?id=40
-->
<component type="firmware">
<id>54f84d05-c917-4c50-8b35-44feabaaa323</id>
<name>VL811+ Firmware</name>
<summary>Firmware for VIA USB 3.0 hub</summary>
<developer_name>VIA</developer_name>
<url type="homepage">http://www.via.com.tw/</url>
<releases>
<release version="9095" timestamp="1400000000">
<description>
<p>This stable release fixes the following problems:</p>
<ul>
<li>WHAT WAS FIXED?</li>
</ul>
</description>
</release>
</releases>
</component>
<!-- VL812
Latest=8581
http://www.via-labs.com/product_show.php?id=41
-->
<component type="firmware">
<id>cd0314ec-b80f-4d1a-a24f-c409183a8b2d</id>
<name>VL812 Firmware</name>
<summary>Firmware for VIA USB 3.0 hub</summary>
<developer_name>VIA</developer_name>
<url type="homepage">http://www.via.com.tw/</url>
<releases>
<release version="8581" timestamp="1400000000">
<description>
<p>This stable release fixes the following problems:</p>
<ul>
<li>WHAT WAS FIXED?</li>
</ul>
</description>
</release>
</releases>
</component>
<!-- VL812 B2
Latest=9091 USB3-HUB7-81X, USB3-HUB7A, PSS-SDH1
Latest=9095 USB3-HUB10C2???????????
http://www.via-labs.com/product_show.php?id=41
-->
<component type="firmware">
<id>26470009-97a8-4028-867a-bbbac6ee7bf0</id>
<name>VL812 B2 Firmware</name>
<summary>Firmware for VIA USB 3.0 hub</summary>
<developer_name>VIA</developer_name>
<url type="homepage">http://www.via.com.tw/</url>
<releases>
<release version="9091" timestamp="1400000000">
<description>
<p>This stable release fixes the following problems:</p>
<ul>
<li>WHAT WAS FIXED?</li>
</ul>
</description>
</release>
</releases>
</component>
</components>

View File

@ -88,6 +88,8 @@ fwupd_SOURCES = \
fu-pending.h \
fu-provider.c \
fu-provider.h \
fu-provider-udev.c \
fu-provider-udev.h \
fu-provider-usb.c \
fu-provider-usb.h \
fu-resources.c \

View File

@ -40,6 +40,7 @@
#include "fu-keyring.h"
#include "fu-pending.h"
#include "fu-provider.h"
#include "fu-provider-udev.h"
#include "fu-provider-usb.h"
#include "fu-resources.h"
@ -1282,6 +1283,7 @@ main (int argc, char *argv[])
/* add providers */
priv->providers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
fu_main_add_provider (priv, fu_provider_udev_new ());
fu_main_add_provider (priv, fu_provider_usb_new ());
#ifdef HAVE_COLORHUG
fu_main_add_provider (priv, fu_provider_chug_new ());

256
src/fu-provider-udev.c Normal file
View File

@ -0,0 +1,256 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU General Public License Version 2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <fwupd.h>
#include <glib-object.h>
#include <gudev/gudev.h>
#include "fu-cleanup.h"
#include "fu-device.h"
#include "fu-provider-udev.h"
static void fu_provider_udev_finalize (GObject *object);
#define FU_PROVIDER_UDEV_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FU_TYPE_PROVIDER_UDEV, FuProviderUdevPrivate))
/**
* FuProviderUdevPrivate:
**/
struct _FuProviderUdevPrivate
{
GHashTable *devices;
GUdevClient *gudev_client;
};
G_DEFINE_TYPE (FuProviderUdev, fu_provider_udev, FU_TYPE_PROVIDER)
/**
* fu_provider_udev_get_name:
**/
static const gchar *
fu_provider_udev_get_name (FuProvider *provider)
{
return "Udev";
}
/**
* fu_provider_udev_get_id:
**/
static gchar *
fu_provider_udev_get_id (GUdevDevice *device)
{
gchar *id;
id = g_strdup_printf ("ro-%s", g_udev_device_get_sysfs_path (device));
g_strdelimit (id, "/:.-", '_');
return id;
}
/**
* fu_provider_udev_client_add:
**/
static void
fu_provider_udev_client_add (FuProviderUdev *provider_udev, GUdevDevice *device)
{
FuDevice *dev;
const gchar *display_name;
const gchar *guid;
const gchar *product;
const gchar *vendor;
_cleanup_free_ gchar *id = NULL;
_cleanup_strv_free_ gchar **split = NULL;
/* interesting device? */
guid = g_udev_device_get_property (device, "FWUPD_GUID");
if (guid == NULL)
return;
/* get data */
g_debug ("adding udev device: %s", g_udev_device_get_sysfs_path (device));
if (0) {
const gchar * const *keys;
guint i;
keys = g_udev_device_get_property_keys (device);
for (i = 0; keys[i] != NULL; i++)
g_debug ("KEY: %s=%s", keys[i],
g_udev_device_get_property (device, keys[i]));
keys = g_udev_device_get_sysfs_attr_keys (device);
for (i = 0; keys[i] != NULL; i++)
g_debug ("SYS: %s=%s", keys[i],
g_udev_device_get_sysfs_attr (device, keys[i]));
}
/* is already in database */
id = fu_provider_udev_get_id (device);
dev = g_hash_table_lookup (provider_udev->priv->devices, id);
if (dev != NULL) {
g_debug ("ignoring duplicate %s", id);
return;
}
/* get the FW version from the BCD device revision */
product = g_udev_device_get_property (device, "PRODUCT");
if (product != NULL) {
split = g_strsplit (product, "/", -1);
if (g_strv_length (split) != 3) {
g_warning ("env{PRODUCT} is invalid: %s", product);
return;
}
}
/* did we get enough data */
dev = fu_device_new ();
fu_device_set_id (dev, id);
fu_device_set_guid (dev, guid);
display_name = g_udev_device_get_property (device, "FWUPD_MODEL");
if (display_name != NULL)
fu_device_set_display_name (dev, display_name);
vendor = g_udev_device_get_property (device, "FWUPD_VENDOR");
if (vendor != NULL)
fu_device_set_metadata (dev, FU_DEVICE_KEY_VENDOR, vendor);
fu_device_set_metadata (dev, FU_DEVICE_KEY_VERSION, split[2]);
/* insert to hash */
g_hash_table_insert (provider_udev->priv->devices, g_strdup (id), dev);
fu_provider_device_add (FU_PROVIDER (provider_udev), dev);
}
/**
* fu_provider_udev_client_remove:
**/
static void
fu_provider_udev_client_remove (FuProviderUdev *provider_udev, GUdevDevice *device)
{
FuDevice *dev;
_cleanup_free_ gchar *id = NULL;
/* interesting device? */
if (g_udev_device_get_property (device, "FWUPD_GUID") == NULL)
return;
/* already in database */
id = fu_provider_udev_get_id (device);
dev = g_hash_table_lookup (provider_udev->priv->devices, id);
if (dev == NULL)
return;
fu_provider_device_remove (FU_PROVIDER (provider_udev), dev);
}
/**
* fu_provider_udev_client_uevent_cb:
**/
static void
fu_provider_udev_client_uevent_cb (GUdevClient *gudev_client,
const gchar *action,
GUdevDevice *udev_device,
FuProviderUdev *provider_udev)
{
if (g_strcmp0 (action, "remove") == 0) {
fu_provider_udev_client_remove (provider_udev, udev_device);
return;
}
if (g_strcmp0 (action, "add") == 0) {
fu_provider_udev_client_add (provider_udev, udev_device);
return;
}
}
/**
* fu_provider_udev_coldplug:
**/
static gboolean
fu_provider_udev_coldplug (FuProvider *provider, GError **error)
{
FuProviderUdev *provider_udev = FU_PROVIDER_UDEV (provider);
GList *devices;
GList *l;
GUdevDevice *udev_device;
/* get all usb devices */
devices = g_udev_client_query_by_subsystem (provider_udev->priv->gudev_client, "usb");
for (l = devices; l != NULL; l = l->next) {
udev_device = l->data;
fu_provider_udev_client_add (provider_udev, udev_device);
}
g_list_foreach (devices, (GFunc) g_object_unref, NULL);
g_list_free (devices);
return TRUE;
}
/**
* fu_provider_udev_class_init:
**/
static void
fu_provider_udev_class_init (FuProviderUdevClass *klass)
{
FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
provider_class->get_name = fu_provider_udev_get_name;
provider_class->coldplug = fu_provider_udev_coldplug;
object_class->finalize = fu_provider_udev_finalize;
g_type_class_add_private (klass, sizeof (FuProviderUdevPrivate));
}
/**
* fu_provider_udev_init:
**/
static void
fu_provider_udev_init (FuProviderUdev *provider_udev)
{
const gchar *subsystems[] = { NULL };
provider_udev->priv = FU_PROVIDER_UDEV_GET_PRIVATE (provider_udev);
provider_udev->priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) g_object_unref);
provider_udev->priv->gudev_client = g_udev_client_new (subsystems);
g_signal_connect (provider_udev->priv->gudev_client, "uevent",
G_CALLBACK (fu_provider_udev_client_uevent_cb), provider_udev);
}
/**
* fu_provider_udev_finalize:
**/
static void
fu_provider_udev_finalize (GObject *object)
{
FuProviderUdev *provider_udev = FU_PROVIDER_UDEV (object);
FuProviderUdevPrivate *priv = provider_udev->priv;
g_hash_table_unref (priv->devices);
g_object_unref (priv->gudev_client);
G_OBJECT_CLASS (fu_provider_udev_parent_class)->finalize (object);
}
/**
* fu_provider_udev_new:
**/
FuProvider *
fu_provider_udev_new (void)
{
FuProviderUdev *provider;
provider = g_object_new (FU_TYPE_PROVIDER_UDEV, NULL);
return FU_PROVIDER (provider);
}

56
src/fu-provider-udev.h Normal file
View File

@ -0,0 +1,56 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU General Public License Version 2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __FU_PROVIDER_UDEV_H
#define __FU_PROVIDER_UDEV_H
#include <glib-object.h>
#include "fu-device.h"
#include "fu-provider.h"
G_BEGIN_DECLS
#define FU_TYPE_PROVIDER_UDEV (fu_provider_udev_get_type ())
#define FU_PROVIDER_UDEV(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FU_TYPE_PROVIDER_UDEV, FuProviderUdev))
#define FU_IS_PROVIDER_UDEV(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FU_TYPE_PROVIDER_UDEV))
typedef struct _FuProviderUdevPrivate FuProviderUdevPrivate;
typedef struct _FuProviderUdev FuProviderUdev;
typedef struct _FuProviderUdevClass FuProviderUdevClass;
struct _FuProviderUdev
{
FuProvider parent;
FuProviderUdevPrivate *priv;
};
struct _FuProviderUdevClass
{
FuProviderClass parent_class;
};
GType fu_provider_udev_get_type (void);
FuProvider *fu_provider_udev_new (void);
G_END_DECLS
#endif /* __FU_PROVIDER_UDEV_H */