mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-29 23:26:55 +00:00
Add initial ColorHug support
This may be useful; more people have ColorHug devices than UEFI firmware that supports system capsule updates.
This commit is contained in:
parent
81e8d799f7
commit
72dff812c0
@ -87,6 +87,7 @@ dnl - Check library dependencies
|
||||
dnl ---------------------------------------------------------------------------
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.36.0 gobject-2.0 gthread-2.0 gio-2.0 >= 2.25.9 gio-unix-2.0)
|
||||
PKG_CHECK_MODULES(GUDEV, gudev-1.0)
|
||||
PKG_CHECK_MODULES(COLORHUG, colorhug >= 1.2.9 gusb >= 0.2.2)
|
||||
PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= 0.103)
|
||||
PKG_CHECK_MODULES(GCAB, libgcab-1.0)
|
||||
PKG_CHECK_MODULES(APPSTREAM_GLIB, appstream-glib)
|
||||
|
@ -13,6 +13,7 @@ BuildRequires: gettext
|
||||
BuildRequires: glib2-devel
|
||||
BuildRequires: intltool
|
||||
BuildRequires: libgudev1-devel
|
||||
BuildRequires: colord-devel >= 1.0.0
|
||||
BuildRequires: polkit-devel >= 0.103
|
||||
BuildRequires: libgcab1-devel
|
||||
BuildRequires: libappstream-devel
|
||||
|
@ -6,6 +6,7 @@ AM_CPPFLAGS = \
|
||||
$(APPSTREAM_GLIB_CFLAGS) \
|
||||
$(PIE_CFLAGS) \
|
||||
$(GCAB_CFLAGS) \
|
||||
$(COLORHUG_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(POLKIT_CFLAGS) \
|
||||
$(GUDEV_CFLAGS) \
|
||||
@ -67,6 +68,8 @@ fwupd_SOURCES = \
|
||||
fu-device.h \
|
||||
fu-provider.c \
|
||||
fu-provider.h \
|
||||
fu-provider-chug.c \
|
||||
fu-provider-chug.h \
|
||||
fu-provider-uefi.c \
|
||||
fu-provider-uefi.h \
|
||||
fu-resources.c \
|
||||
@ -75,6 +78,7 @@ fwupd_SOURCES = \
|
||||
|
||||
fwupd_LDADD = \
|
||||
$(APPSTREAM_GLIB_LIBS) \
|
||||
$(COLORHUG_LIBS) \
|
||||
$(POLKIT_LIBS) \
|
||||
$(GUDEV_LIBS) \
|
||||
$(GCAB_LIBS) \
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "fu-common.h"
|
||||
#include "fu-debug.h"
|
||||
#include "fu-device.h"
|
||||
#include "fu-provider-colorhug.h"
|
||||
#include "fu-provider-uefi.h"
|
||||
#include "fu-resources.h"
|
||||
|
||||
@ -729,6 +730,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_chug_new ());
|
||||
fu_main_add_provider (priv, fu_provider_uefi_new ());
|
||||
|
||||
/* load introspection from file */
|
||||
|
522
src/fu-provider-chug.c
Normal file
522
src/fu-provider-chug.c
Normal file
@ -0,0 +1,522 @@
|
||||
/* -*- 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 <colorhug.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
#include <glib-object.h>
|
||||
#include <gusb.h>
|
||||
|
||||
#include "fu-cleanup.h"
|
||||
#include "fu-common.h"
|
||||
#include "fu-device.h"
|
||||
#include "fu-provider-colorhug.h"
|
||||
|
||||
static void fu_provider_chug_finalize (GObject *object);
|
||||
|
||||
#define FU_PROVIDER_CHUG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FU_TYPE_PROVIDER_CHUG, FuProviderChugPrivate))
|
||||
|
||||
#define FU_PROVIDER_CHUG_POLL_REOPEN 5 /* seconds */
|
||||
#define FU_PROVIDER_CHUG_FIRMWARE_MAX (64 * 1024) /* bytes */
|
||||
|
||||
/**
|
||||
* FuProviderChugPrivate:
|
||||
**/
|
||||
struct _FuProviderChugPrivate
|
||||
{
|
||||
GHashTable *devices;
|
||||
GUsbContext *usb_ctx;
|
||||
ChDeviceQueue *device_queue;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ChDeviceMode mode;
|
||||
FuDevice *device;
|
||||
FuProviderChug *provider_chug;
|
||||
GMainLoop *loop;
|
||||
GUsbDevice *usb_device;
|
||||
gboolean got_version;
|
||||
gboolean is_bootloader;
|
||||
guint timeout_open_id;
|
||||
guint reconnect_id;
|
||||
GBytes *fw_bin;
|
||||
} FuProviderChugItem;
|
||||
|
||||
G_DEFINE_TYPE (FuProviderChug, fu_provider_chug, FU_TYPE_PROVIDER)
|
||||
|
||||
/**
|
||||
* fu_provider_chug_device_free:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_device_free (FuProviderChugItem *item)
|
||||
{
|
||||
g_main_loop_unref (item->loop);
|
||||
g_object_unref (item->device);
|
||||
g_object_unref (item->provider_chug);
|
||||
g_object_unref (item->usb_device);
|
||||
if (item->fw_bin != NULL)
|
||||
g_bytes_unref (item->fw_bin);
|
||||
if (item->timeout_open_id != 0)
|
||||
g_source_remove (item->timeout_open_id);
|
||||
if (item->reconnect_id != 0)
|
||||
g_source_remove (item->reconnect_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_reconnect_timeout_cb:
|
||||
**/
|
||||
static gboolean
|
||||
fu_provider_chug_reconnect_timeout_cb (gpointer user_data)
|
||||
{
|
||||
FuProviderChugItem *item = (FuProviderChugItem *) user_data;
|
||||
item->reconnect_id = 0;
|
||||
g_main_loop_quit (item->loop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_wait_for_connect:
|
||||
**/
|
||||
static gboolean
|
||||
fu_provider_chug_wait_for_connect (FuProviderChugItem *item, GError **error)
|
||||
{
|
||||
_cleanup_error_free_ GError *error_local = NULL;
|
||||
item->reconnect_id = g_timeout_add (CH_DEVICE_USB_TIMEOUT,
|
||||
fu_provider_chug_reconnect_timeout_cb, item);
|
||||
g_main_loop_run (item->loop);
|
||||
if (item->reconnect_id == 0) {
|
||||
g_set_error_literal (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"request timed out");
|
||||
return FALSE;
|
||||
}
|
||||
g_source_remove (item->reconnect_id);
|
||||
item->reconnect_id = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fu_provider_chug_open:
|
||||
**/
|
||||
static gboolean
|
||||
fu_provider_chug_open (FuProviderChugItem *item, GError **error)
|
||||
{
|
||||
_cleanup_error_free_ GError *error_local = NULL;
|
||||
if (!ch_device_open (item->usb_device, &error_local)) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"failed to open %s device: %s",
|
||||
fu_device_get_id (item->device),
|
||||
error_local->message);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_get_id:
|
||||
**/
|
||||
static gchar *
|
||||
fu_provider_chug_get_id (GUsbDevice *device)
|
||||
{
|
||||
/* this identifies the *port* the device is plugged into */
|
||||
return g_strdup_printf ("CHug-%s", g_usb_device_get_platform_id (device));
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_get_firmware_version:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_get_firmware_version (FuProviderChugItem *item)
|
||||
{
|
||||
FuProviderChugPrivate *priv = item->provider_chug->priv;
|
||||
guint16 major;
|
||||
guint16 micro;
|
||||
guint16 minor;
|
||||
_cleanup_error_free_ GError *error = NULL;
|
||||
_cleanup_free_ gchar *version = NULL;
|
||||
|
||||
/* attempt to open the device and get the serial number */
|
||||
if (!ch_device_open (item->usb_device, &error)) {
|
||||
g_debug ("Failed to open, polling: %s", error->message);
|
||||
return;
|
||||
}
|
||||
ch_device_queue_get_firmware_ver (priv->device_queue, item->usb_device,
|
||||
&major, &minor, µ);
|
||||
if (!ch_device_queue_process (priv->device_queue,
|
||||
CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE,
|
||||
NULL, &error)) {
|
||||
g_warning ("Failed to get serial: %s", error->message);
|
||||
} else {
|
||||
item->got_version = TRUE;
|
||||
version = g_strdup_printf ("%i.%i.%i", major, minor, micro);
|
||||
fu_device_set_metadata (item->device, FU_DEVICE_KEY_VERSION, version);
|
||||
}
|
||||
|
||||
/* we're done here */
|
||||
if (!g_usb_device_close (item->usb_device, &error))
|
||||
g_debug ("Failed to close: %s", error->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_update:
|
||||
**/
|
||||
static gboolean
|
||||
fu_provider_chug_update (FuProvider *provider,
|
||||
FuDevice *device,
|
||||
gint fd,
|
||||
FuProviderFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider);
|
||||
FuProviderChugPrivate *priv = provider_chug->priv;
|
||||
FuProviderChugItem *item;
|
||||
_cleanup_object_unref_ GInputStream *stream = NULL;
|
||||
_cleanup_error_free_ GError *error_local = NULL;
|
||||
|
||||
/* find item */
|
||||
item = g_hash_table_lookup (provider_chug->priv->devices,
|
||||
fu_device_get_id (device));
|
||||
if (item == NULL) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"cannot find: %s",
|
||||
fu_device_get_id (device));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* this file is so small, just slurp it all in one go */
|
||||
stream = g_unix_input_stream_new (fd, TRUE);
|
||||
item->fw_bin = g_input_stream_read_bytes (stream,
|
||||
FU_PROVIDER_CHUG_FIRMWARE_MAX,
|
||||
NULL, error);
|
||||
if (item->fw_bin == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* switch to bootloader mode */
|
||||
if (!item->is_bootloader) {
|
||||
g_debug ("ColorHug: Switching to bootloader mode");
|
||||
if (!fu_provider_chug_open (item, error))
|
||||
return FALSE;
|
||||
ch_device_queue_reset (priv->device_queue, item->usb_device);
|
||||
if (!ch_device_queue_process (priv->device_queue,
|
||||
CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE,
|
||||
NULL, &error_local)) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"failed to reset device: %s",
|
||||
error_local->message);
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* this device has just gone away, no error possible */
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
|
||||
/* wait for reconnection */
|
||||
if (!fu_provider_chug_wait_for_connect (item, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* open the device, which is now in bootloader mode */
|
||||
if (!fu_provider_chug_open (item, error))
|
||||
return FALSE;
|
||||
|
||||
/* write and verify firmware */
|
||||
g_debug ("ColorHug: Writing firmware");
|
||||
ch_device_queue_write_firmware (priv->device_queue, item->usb_device,
|
||||
g_bytes_get_data (item->fw_bin, NULL),
|
||||
g_bytes_get_size (item->fw_bin));
|
||||
ch_device_queue_verify_firmware (priv->device_queue, item->usb_device,
|
||||
g_bytes_get_data (item->fw_bin, NULL),
|
||||
g_bytes_get_size (item->fw_bin));
|
||||
if (!ch_device_queue_process (priv->device_queue,
|
||||
CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE,
|
||||
NULL, &error_local)) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"failed to write firmware: %s",
|
||||
error_local->message);
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* boot into the new firmware */
|
||||
g_debug ("ColorHug: Booting new firmware");
|
||||
ch_device_queue_boot_flash (priv->device_queue, item->usb_device);
|
||||
if (!ch_device_queue_process (priv->device_queue,
|
||||
CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE,
|
||||
NULL, &error_local)) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"failed to boot flash: %s",
|
||||
error_local->message);
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* this device has just gone away, no error possible */
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
|
||||
/* wait for firmware mode */
|
||||
if (!fu_provider_chug_wait_for_connect (item, error))
|
||||
return FALSE;
|
||||
if (!fu_provider_chug_open (item, error))
|
||||
return FALSE;
|
||||
|
||||
/* set flash success */
|
||||
g_debug ("ColorHug: Setting flash success");
|
||||
ch_device_queue_set_flash_success (priv->device_queue, item->usb_device, 1);
|
||||
if (!ch_device_queue_process (priv->device_queue,
|
||||
CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE,
|
||||
NULL, &error_local)) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"failed to set flash success: %s",
|
||||
error_local->message);
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* close, orderly */
|
||||
if (!g_usb_device_close (item->usb_device, &error_local)) {
|
||||
g_set_error (error,
|
||||
FU_ERROR,
|
||||
FU_ERROR_INTERNAL,
|
||||
"failed to close device: %s",
|
||||
error_local->message);
|
||||
g_usb_device_close (item->usb_device, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* close stream */
|
||||
if (!g_input_stream_close (stream, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
/* get the new firmware version */
|
||||
g_debug ("ColorHug: Getting new firmware version");
|
||||
item->got_version = FALSE;
|
||||
fu_provider_chug_get_firmware_version (item);
|
||||
|
||||
if (item->got_version)
|
||||
g_debug ("ColorHug: DONE!");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_open_cb:
|
||||
**/
|
||||
static gboolean
|
||||
fu_provider_chug_open_cb (gpointer user_data)
|
||||
{
|
||||
FuProviderChugItem *item = (FuProviderChugItem *) user_data;
|
||||
|
||||
g_debug ("attempt to open %s",
|
||||
g_usb_device_get_platform_id (item->usb_device));
|
||||
fu_provider_chug_get_firmware_version (item);
|
||||
|
||||
/* success! */
|
||||
if (item->got_version) {
|
||||
item->timeout_open_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* keep trying */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_device_added_cb:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_device_added_cb (GUsbContext *ctx,
|
||||
GUsbDevice *device,
|
||||
FuProviderChug *provider_chug)
|
||||
{
|
||||
FuProviderChugItem *item;
|
||||
ChDeviceMode mode;
|
||||
_cleanup_free_ gchar *id = NULL;
|
||||
|
||||
/* ignore */
|
||||
mode = ch_device_get_mode (device);
|
||||
if (mode == CH_DEVICE_MODE_UNKNOWN)
|
||||
return;
|
||||
|
||||
/* is already in database */
|
||||
id = fu_provider_chug_get_id (device);
|
||||
item = g_hash_table_lookup (provider_chug->priv->devices, id);
|
||||
if (item == NULL) {
|
||||
item = g_new0 (FuProviderChugItem, 1);
|
||||
item->loop = g_main_loop_new (NULL, FALSE);
|
||||
item->provider_chug = g_object_ref (provider_chug);
|
||||
item->usb_device = g_object_ref (device);
|
||||
item->device = fu_device_new ();
|
||||
item->mode = mode;
|
||||
fu_device_set_id (item->device, id);
|
||||
fu_device_set_metadata (item->device, FU_DEVICE_KEY_PROVIDER,
|
||||
"ColorHug");
|
||||
fu_device_set_metadata (item->device, FU_DEVICE_KEY_GUID,
|
||||
ch_device_get_guid (device));
|
||||
|
||||
/* try to get the serial number -- if opening failed then
|
||||
* poll until the device is not busy */
|
||||
fu_provider_chug_get_firmware_version (item);
|
||||
if (!item->got_version && item->timeout_open_id == 0) {
|
||||
item->timeout_open_id = g_timeout_add_seconds (FU_PROVIDER_CHUG_POLL_REOPEN,
|
||||
fu_provider_chug_open_cb, item);
|
||||
}
|
||||
|
||||
/* insert to hash */
|
||||
g_hash_table_insert (provider_chug->priv->devices,
|
||||
g_strdup (id), item);
|
||||
} else {
|
||||
/* update the device */
|
||||
g_object_unref (item->usb_device);
|
||||
item->usb_device = g_object_ref (device);
|
||||
}
|
||||
|
||||
/* is the device in bootloader mode */
|
||||
switch (mode) {
|
||||
case CH_DEVICE_MODE_BOOTLOADER:
|
||||
case CH_DEVICE_MODE_BOOTLOADER2:
|
||||
case CH_DEVICE_MODE_BOOTLOADER_PLUS:
|
||||
case CH_DEVICE_MODE_BOOTLOADER_ALS:
|
||||
item->is_bootloader = TRUE;
|
||||
break;
|
||||
default:
|
||||
item->is_bootloader = FALSE;
|
||||
break;
|
||||
}
|
||||
fu_provider_emit_added (FU_PROVIDER (provider_chug), item->device);
|
||||
|
||||
/* are we waiting for the device to show up */
|
||||
if (g_main_loop_is_running (item->loop))
|
||||
g_main_loop_quit (item->loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_device_removed_cb:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_device_removed_cb (GUsbContext *ctx,
|
||||
GUsbDevice *device,
|
||||
FuProviderChug *provider_chug)
|
||||
{
|
||||
FuProviderChugItem *item;
|
||||
_cleanup_free_ gchar *id = NULL;
|
||||
|
||||
/* already in database */
|
||||
id = fu_provider_chug_get_id (device);
|
||||
item = g_hash_table_lookup (provider_chug->priv->devices, id);
|
||||
if (item == NULL)
|
||||
return;
|
||||
|
||||
/* no more polling for open */
|
||||
if (item->timeout_open_id != 0) {
|
||||
g_source_remove (item->timeout_open_id);
|
||||
item->timeout_open_id = 0;
|
||||
}
|
||||
fu_provider_emit_removed (FU_PROVIDER (provider_chug), item->device);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_coldplug:
|
||||
**/
|
||||
static gboolean
|
||||
fu_provider_chug_coldplug (FuProvider *provider, GError **error)
|
||||
{
|
||||
FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider);
|
||||
g_usb_context_enumerate (provider_chug->priv->usb_ctx);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_class_init:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_class_init (FuProviderChugClass *klass)
|
||||
{
|
||||
FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
provider_class->coldplug = fu_provider_chug_coldplug;
|
||||
provider_class->update = fu_provider_chug_update;
|
||||
object_class->finalize = fu_provider_chug_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (FuProviderChugPrivate));
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_init:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_init (FuProviderChug *provider_chug)
|
||||
{
|
||||
provider_chug->priv = FU_PROVIDER_CHUG_GET_PRIVATE (provider_chug);
|
||||
provider_chug->priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) fu_provider_chug_device_free);
|
||||
provider_chug->priv->usb_ctx = g_usb_context_new (NULL);
|
||||
provider_chug->priv->device_queue = ch_device_queue_new ();
|
||||
g_signal_connect (provider_chug->priv->usb_ctx, "device-added",
|
||||
G_CALLBACK (fu_provider_chug_device_added_cb),
|
||||
provider_chug);
|
||||
g_signal_connect (provider_chug->priv->usb_ctx, "device-removed",
|
||||
G_CALLBACK (fu_provider_chug_device_removed_cb),
|
||||
provider_chug);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_finalize:
|
||||
**/
|
||||
static void
|
||||
fu_provider_chug_finalize (GObject *object)
|
||||
{
|
||||
FuProviderChug *provider_chug = FU_PROVIDER_CHUG (object);
|
||||
FuProviderChugPrivate *priv = provider_chug->priv;
|
||||
|
||||
g_hash_table_unref (priv->devices);
|
||||
g_object_unref (priv->usb_ctx);
|
||||
g_object_unref (priv->device_queue);
|
||||
|
||||
G_OBJECT_CLASS (fu_provider_chug_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_provider_chug_new:
|
||||
**/
|
||||
FuProvider *
|
||||
fu_provider_chug_new (void)
|
||||
{
|
||||
FuProviderChug *provider;
|
||||
provider = g_object_new (FU_TYPE_PROVIDER_CHUG, NULL);
|
||||
return FU_PROVIDER (provider);
|
||||
}
|
56
src/fu-provider-chug.h
Normal file
56
src/fu-provider-chug.h
Normal 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_CHUG_H
|
||||
#define __FU_PROVIDER_CHUG_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "fu-device.h"
|
||||
#include "fu-provider.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FU_TYPE_PROVIDER_CHUG (fu_provider_chug_get_type ())
|
||||
#define FU_PROVIDER_CHUG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FU_TYPE_PROVIDER_CHUG, FuProviderChug))
|
||||
#define FU_IS_PROVIDER_CHUG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FU_TYPE_PROVIDER_CHUG))
|
||||
|
||||
typedef struct _FuProviderChugPrivate FuProviderChugPrivate;
|
||||
typedef struct _FuProviderChug FuProviderChug;
|
||||
typedef struct _FuProviderChugClass FuProviderChugClass;
|
||||
|
||||
struct _FuProviderChug
|
||||
{
|
||||
FuProvider parent;
|
||||
FuProviderChugPrivate *priv;
|
||||
};
|
||||
|
||||
struct _FuProviderChugClass
|
||||
{
|
||||
FuProviderClass parent_class;
|
||||
};
|
||||
|
||||
GType fu_provider_chug_get_type (void);
|
||||
FuProvider *fu_provider_chug_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __FU_PROVIDER_CHUG_H */
|
Loading…
Reference in New Issue
Block a user