Add FuHidDevice abstraction

Quite a few plugins use HID commands to communicate with the hardware. At the
mement we have ~6 implementations of SET_REPORT and are soon to add one more.

Move this into common code.
This commit is contained in:
Richard Hughes 2020-03-19 12:03:03 +00:00
parent c134451aeb
commit c04f5a3e15
21 changed files with 567 additions and 590 deletions

View File

@ -0,0 +1,327 @@
/*
* Copyright (C) 2017-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuHidDevice"
#include "config.h"
#include "fu-hid-device.h"
#define FU_HID_REPORT_GET 0x01
#define FU_HID_REPORT_SET 0x09
#define FU_HID_REPORT_TYPE_INPUT 0x01
#define FU_HID_REPORT_TYPE_OUTPUT 0x02
#define FU_HID_REPORT_TYPE_FEATURE 0x03
/**
* SECTION:fu-hid-device
* @short_description: a HID device
*
* An object that represents a HID device.
*
* See also: #FuDevice
*/
typedef struct
{
FuUsbDevice *usb_device;
guint8 interface;
} FuHidDevicePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (FuHidDevice, fu_hid_device, FU_TYPE_USB_DEVICE)
enum {
PROP_0,
PROP_INTERFACE,
PROP_LAST
};
#define GET_PRIVATE(o) (fu_hid_device_get_instance_private (o))
static void
fu_hid_device_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
FuHidDevice *device = FU_HID_DEVICE (object);
FuHidDevicePrivate *priv = GET_PRIVATE (device);
switch (prop_id) {
case PROP_INTERFACE:
g_value_set_uint (value, priv->interface);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
fu_hid_device_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
FuHidDevice *device = FU_HID_DEVICE (object);
switch (prop_id) {
case PROP_INTERFACE:
fu_hid_device_set_interface (device, g_value_get_uint (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
fu_hid_device_open (FuUsbDevice *device, GError **error)
{
FuHidDevice *self = FU_HID_DEVICE (device);
FuHidDeviceClass *klass = FU_HID_DEVICE_GET_CLASS (device);
FuHidDevicePrivate *priv = GET_PRIVATE (self);
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* claim */
if (!g_usb_device_claim_interface (usb_device, priv->interface,
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to claim HID interface: ");
return FALSE;
}
/* subclassed */
if (klass->open != NULL) {
if (!klass->open (self, error))
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_hid_device_close (FuUsbDevice *device, GError **error)
{
FuHidDevice *self = FU_HID_DEVICE (device);
FuHidDeviceClass *klass = FU_HID_DEVICE_GET_CLASS (device);
FuHidDevicePrivate *priv = GET_PRIVATE (self);
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* subclassed */
if (klass->close != NULL) {
if (!klass->close (self, error))
return FALSE;
}
/* release */
if (!g_usb_device_release_interface (usb_device, priv->interface,
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to release HID interface: ");
return FALSE;
}
/* success */
return TRUE;
}
/**
* fu_hid_device_set_interface:
* @self: A #FuHidDevice
* @interface: An interface number, e.g. 0x03
*
* Sets the HID USB interface number.
*
* Since: 1.4.0
**/
void
fu_hid_device_set_interface (FuHidDevice *self, guint8 interface)
{
FuHidDevicePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_HID_DEVICE (self));
priv->interface = interface;
}
/**
* fu_hid_device_get_interface:
* @self: A #FuHidDevice
*
* Gets the HID USB interface number.
*
* Returns: integer
*
* Since: 1.4.0
**/
guint8
fu_hid_device_get_interface (FuHidDevice *self)
{
FuHidDevicePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_HID_DEVICE (self), 0xff);
return priv->interface;
}
/**
* fu_hid_device_set_report:
* @self: A #FuHidDevice
* @value: low byte of wValue
* @buf: (nullable): a mutable buffer of data to send
* @bufsz: Size of @buf
* @timeout: timeout in ms
* @flags: #FuHidDeviceFlags e.g. %FU_HID_DEVICE_FLAG_ALLOW_TRUNC
* @error: a #GError or %NULL
*
* Calls SetReport on the hardware.
*
* Returns: %TRUE for success
*
* Since: 1.4.0
**/
gboolean
fu_hid_device_set_report (FuHidDevice *self,
guint8 value,
guint8 *buf,
gsize bufsz,
guint timeout,
FuHidDeviceFlags flags,
GError **error)
{
FuHidDevicePrivate *priv = GET_PRIVATE (self);
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize actual_len = 0;
guint16 wvalue = (FU_HID_REPORT_TYPE_OUTPUT << 8) | value;
/* special case */
if (flags & FU_HID_DEVICE_FLAG_IS_FEATURE)
wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | value;
g_return_val_if_fail (FU_HID_DEVICE (self), FALSE);
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (bufsz != 0, FALSE);
if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "HID::SetReport", buf, bufsz);
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET,
wvalue, priv->interface,
buf, bufsz,
&actual_len,
timeout,
NULL, error)) {
g_prefix_error (error, "failed to SetReport: ");
return FALSE;
}
if ((flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != bufsz) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"only wrote %" G_GSIZE_FORMAT "bytes", actual_len);
return FALSE;
}
return TRUE;
}
/**
* fu_hid_device_get_report:
* @self: A #FuHidDevice
* @value: low byte of wValue
* @buf: (nullable): a mutable buffer of data to send
* @bufsz: Size of @buf
* @timeout: timeout in ms
* @flags: #FuHidDeviceFlags e.g. %FU_HID_DEVICE_FLAG_ALLOW_TRUNC
* @error: a #GError or %NULL
*
* Calls GetReport on the hardware.
*
* Returns: %TRUE for success
*
* Since: 1.4.0
**/
gboolean
fu_hid_device_get_report (FuHidDevice *self,
guint8 value,
guint8 *buf,
gsize bufsz,
guint timeout,
FuHidDeviceFlags flags,
GError **error)
{
FuHidDevicePrivate *priv = GET_PRIVATE (self);
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize actual_len = 0;
guint16 wvalue = (FU_HID_REPORT_TYPE_INPUT << 8) | value;
g_return_val_if_fail (FU_HID_DEVICE (self), FALSE);
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (bufsz != 0, FALSE);
/* special case */
if (flags & FU_HID_DEVICE_FLAG_IS_FEATURE)
wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | value;
if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", buf, actual_len);
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_GET,
wvalue, priv->interface,
buf, bufsz,
&actual_len, /* actual length */
timeout,
NULL, error)) {
g_prefix_error (error, "failed to GetReport: ");
return FALSE;
}
if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", buf, actual_len);
if ((flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != bufsz) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"only read %" G_GSIZE_FORMAT "bytes", actual_len);
return FALSE;
}
return TRUE;
}
static void
fu_hid_device_init (FuHidDevice *device)
{
}
/**
* fu_hid_device_new:
* @usb_device: A #GUsbDevice
*
* Creates a new #FuHidDevice.
*
* Returns: (transfer full): a #FuHidDevice
*
* Since: 1.4.0
**/
FuHidDevice *
fu_hid_device_new (GUsbDevice *usb_device)
{
FuHidDevice *device = g_object_new (FU_TYPE_HID_DEVICE, NULL);
fu_usb_device_set_dev (FU_USB_DEVICE (device), usb_device);
return FU_HID_DEVICE (device);
}
static void
fu_hid_device_class_init (FuHidDeviceClass *klass)
{
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
object_class->get_property = fu_hid_device_get_property;
object_class->set_property = fu_hid_device_set_property;
klass_usb_device->open = fu_hid_device_open;
klass_usb_device->close = fu_hid_device_close;
pspec = g_param_spec_uint ("interface", NULL, NULL,
0x00, 0xff, 0x00,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME);
g_object_class_install_property (object_class, PROP_INTERFACE, pspec);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2017-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <glib-object.h>
#include "fu-usb-device.h"
#define FU_TYPE_HID_DEVICE (fu_hid_device_get_type ())
G_DECLARE_DERIVABLE_TYPE (FuHidDevice, fu_hid_device, FU, HID_DEVICE, FuUsbDevice)
struct _FuHidDeviceClass
{
FuUsbDeviceClass parent_class;
gboolean (*open) (FuHidDevice *device,
GError **error);
gboolean (*close) (FuHidDevice *device,
GError **error);
gpointer __reserved[29];
};
/**
* FuHidDeviceFlags:
* @FU_HID_DEVICE_FLAG_NONE: No flags set
* @FU_HID_DEVICE_FLAG_ALLOW_TRUNC: Allow truncated reads and writes
* @FU_HID_DEVICE_FLAG_IS_FEATURE: Use %FU_HID_REPORT_TYPE_FEATURE for wValue
*
* Flags used when calling fu_hid_device_get_report() and fu_hid_device_set_report().
**/
typedef enum {
FU_HID_DEVICE_FLAG_NONE = 0,
FU_HID_DEVICE_FLAG_ALLOW_TRUNC = 1 << 0,
FU_HID_DEVICE_FLAG_IS_FEATURE = 1 << 1,
FU_HID_DEVICE_FLAG_LAST
} FuHidDeviceFlags;
FuHidDevice *fu_hid_device_new (GUsbDevice *usb_device);
void fu_hid_device_set_interface (FuHidDevice *self,
guint8 interface);
guint8 fu_hid_device_get_interface (FuHidDevice *self);
gboolean fu_hid_device_set_report (FuHidDevice *self,
guint8 value,
guint8 *buf,
gsize bufsz,
guint timeout,
FuHidDeviceFlags flags,
GError **error);
gboolean fu_hid_device_get_report (FuHidDevice *self,
guint8 value,
guint8 *buf,
gsize bufsz,
guint timeout,
FuHidDeviceFlags flags,
GError **error);

View File

@ -17,6 +17,7 @@
#include "fu-quirks.h"
#include "fu-hwids.h"
#include "fu-usb-device.h"
//#include "fu-hid-device.h"
#ifdef HAVE_GUDEV
#include "fu-udev-device.h"
#endif

View File

@ -15,16 +15,6 @@
#define FU_TYPE_USB_DEVICE (fu_usb_device_get_type ())
G_DECLARE_DERIVABLE_TYPE (FuUsbDevice, fu_usb_device, FU, USB_DEVICE, FuDevice)
/* HID */
#define FU_HID_REPORT_GET 0x01
#define FU_HID_REPORT_SET 0x09
#define FU_HID_REPORT_TYPE_INPUT 0x01
#define FU_HID_REPORT_TYPE_OUTPUT 0x02
#define FU_HID_REPORT_TYPE_FEATURE 0x03
#define FU_HID_FEATURE 0x0300
struct _FuUsbDeviceClass
{
FuDeviceClass parent_class;

View File

@ -556,6 +556,12 @@ LIBFWUPDPLUGIN_1.4.0 {
fu_efivar_secure_boot_enabled;
fu_efivar_set_data;
fu_efivar_supported;
fu_hid_device_get_interface;
fu_hid_device_get_report;
fu_hid_device_get_type;
fu_hid_device_new;
fu_hid_device_set_interface;
fu_hid_device_set_report;
fu_plugin_get_config_value_boolean;
fu_plugin_runner_device_created;
local: *;

View File

@ -22,6 +22,7 @@ fwupdplugin_src = [
'fu-efivar.c',
'fu-udev-device.c',
'fu-usb-device.c',
'fu-hid-device.c',
]
fwupdplugin_headers = [
@ -49,6 +50,7 @@ fwupdplugin_headers = [
'fu-efivar.h',
'fu-udev-device.h',
'fu-usb-device.h',
'fu-hid-device.h',
]
install_headers(
'fwupdplugin.h',

View File

@ -32,13 +32,13 @@ typedef enum {
struct _FuCsrDevice
{
FuUsbDevice parent_instance;
FuHidDevice parent_instance;
FuCsrDeviceQuirks quirks;
DfuState dfu_state;
guint32 dnload_timeout;
};
G_DEFINE_TYPE (FuCsrDevice, fu_csr_device, FU_TYPE_USB_DEVICE)
G_DEFINE_TYPE (FuCsrDevice, fu_csr_device, FU_TYPE_HID_DEVICE)
#define FU_CSR_REPORT_ID_COMMAND 0x01
#define FU_CSR_REPORT_ID_STATUS 0x02
@ -69,73 +69,36 @@ fu_csr_device_to_string (FuDevice *device, guint idt, GString *str)
static gboolean
fu_csr_device_attach (FuDevice *device, GError **error)
{
FuCsrDevice *self = FU_CSR_DEVICE (device);
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize sz = 0;
guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET };
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "Reset", buf, sz);
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET, /* bRequest */
FU_HID_FEATURE | FU_CSR_REPORT_ID_CONTROL, /* wValue */
0x0000, /* wIndex */
buf, sizeof(buf), &sz,
FU_CSR_DEVICE_TIMEOUT, /* timeout */
NULL, error)) {
g_prefix_error (error, "Failed to ClearStatus: ");
if (!fu_hid_device_set_report (FU_HID_DEVICE (device),
FU_CSR_REPORT_ID_CONTROL,
buf, sizeof(buf),
FU_CSR_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_IS_FEATURE,
error)) {
g_prefix_error (error, "failed to attach: ");
return FALSE;
}
/* check packet */
if (sz != FU_CSR_CONTROL_HEADER_SIZE) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Reset packet was %" G_GSIZE_FORMAT " expected %i",
sz, FU_CSR_CONTROL_HEADER_SIZE);
return FALSE;
}
return TRUE;
}
static gboolean
fu_csr_device_get_status (FuCsrDevice *self, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize sz = 0;
guint8 buf[64] = {0};
/* hit hardware */
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_GET, /* bRequest */
FU_HID_FEATURE | FU_CSR_REPORT_ID_STATUS, /* wValue */
0x0000, /* wIndex */
buf, sizeof(buf), &sz,
FU_CSR_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "Failed to GetStatus: ");
if (!fu_hid_device_get_report (FU_HID_DEVICE (self),
FU_CSR_REPORT_ID_STATUS,
buf, sizeof(buf),
FU_CSR_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_IS_FEATURE,
error)) {
g_prefix_error (error, "failed to GetStatus: ");
return FALSE;
}
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "GetStatus", buf, sz);
/* check packet */
if (sz != FU_CSR_STATUS_HEADER_SIZE) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"GetStatus packet was %" G_GSIZE_FORMAT " expected %i",
sz, FU_CSR_STATUS_HEADER_SIZE);
return FALSE;
}
if (buf[0] != FU_CSR_REPORT_ID_STATUS) {
g_set_error (error,
FWUPD_ERROR,
@ -157,8 +120,6 @@ fu_csr_device_get_status (FuCsrDevice *self, GError **error)
static gboolean
fu_csr_device_clear_status (FuCsrDevice *self, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize sz = 0;
guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL,
FU_CSR_CONTROL_CLEAR_STATUS };
@ -169,29 +130,13 @@ fu_csr_device_clear_status (FuCsrDevice *self, GError **error)
return TRUE;
/* hit hardware */
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "ClearStatus", buf, sz);
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET, /* bRequest */
FU_HID_FEATURE | FU_CSR_REPORT_ID_CONTROL, /* wValue */
0x0000, /* wIndex */
buf, sizeof(buf), &sz,
FU_CSR_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "Failed to ClearStatus: ");
return FALSE;
}
/* check packet */
if (sz != FU_CSR_CONTROL_HEADER_SIZE) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"ClearStatus packet was %" G_GSIZE_FORMAT " expected %i",
sz, FU_CSR_CONTROL_HEADER_SIZE);
if (!fu_hid_device_set_report (FU_HID_DEVICE (self),
FU_CSR_REPORT_ID_CONTROL,
buf, sizeof(buf),
FU_CSR_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_IS_FEATURE,
error)) {
g_prefix_error (error, "failed to ClearStatus: ");
return FALSE;
}
@ -202,35 +147,17 @@ fu_csr_device_clear_status (FuCsrDevice *self, GError **error)
static GBytes *
fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize sz = 0;
guint16 data_sz;
guint8 buf[64] = {0};
/* hit hardware */
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_GET, /* bRequest */
FU_HID_FEATURE | FU_CSR_REPORT_ID_COMMAND, /* wValue */
0x0000, /* wIndex */
buf, sizeof(buf), &sz,
FU_CSR_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "Failed to ReadFirmware: ");
return NULL;
}
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "ReadFirmware", buf, sz);
/* too small to parse */
if (sz < FU_CSR_COMMAND_HEADER_SIZE) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"ReadFirmware packet too small, got %" G_GSIZE_FORMAT,
sz);
if (!fu_hid_device_get_report (FU_HID_DEVICE (self),
FU_CSR_REPORT_ID_COMMAND,
buf, sizeof(buf),
FU_CSR_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_IS_FEATURE,
error)) {
g_prefix_error (error, "failed to ReadFirmware: ");
return NULL;
}
@ -245,7 +172,7 @@ fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error)
/* check the length */
data_sz = fu_common_read_uint16 (&buf[1], G_LITTLE_ENDIAN);
if (data_sz + FU_CSR_COMMAND_HEADER_SIZE != (guint16) sz) {
if (data_sz + FU_CSR_COMMAND_HEADER_SIZE != (guint16) sizeof(buf)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
@ -256,7 +183,7 @@ fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error)
/* return as bytes */
return g_bytes_new (buf + FU_CSR_COMMAND_HEADER_SIZE,
sz - FU_CSR_COMMAND_HEADER_SIZE);
sizeof(buf) - FU_CSR_COMMAND_HEADER_SIZE);
}
static FuFirmware *
@ -331,10 +258,8 @@ fu_csr_device_upload (FuDevice *device, GError **error)
static gboolean
fu_csr_device_download_chunk (FuCsrDevice *self, guint16 idx, GBytes *chunk, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
const guint8 *chunk_data;
gsize chunk_sz = 0;
gsize write_sz = 0;
guint8 buf[FU_CSR_PACKET_DATA_SIZE] = {0};
/* too large? */
@ -359,32 +284,13 @@ fu_csr_device_download_chunk (FuCsrDevice *self, guint16 idx, GBytes *chunk, GEr
return FALSE;
/* hit hardware */
if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "Upgrade", buf, sizeof(buf));
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET, /* bRequest */
FU_HID_FEATURE | FU_CSR_REPORT_ID_COMMAND, /* wValue */
0x0000, /* wIndex */
buf,
sizeof(buf),
&write_sz,
FU_CSR_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "Failed to Upgrade: ");
return FALSE;
}
/* check packet */
if (write_sz != sizeof(buf)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Not all packet written for upgrade got "
"%" G_GSIZE_FORMAT " expected %" G_GSIZE_FORMAT,
write_sz, sizeof(buf));
if (!fu_hid_device_set_report (FU_HID_DEVICE (self),
FU_CSR_REPORT_ID_COMMAND,
buf, sizeof(buf),
FU_CSR_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_IS_FEATURE,
error)) {
g_prefix_error (error, "failed to Upgrade: ");
return FALSE;
}
@ -501,23 +407,6 @@ fu_csr_device_probe (FuUsbDevice *device, GError **error)
return TRUE;
}
static gboolean
fu_csr_device_open (FuUsbDevice *device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* open device and clear status */
if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to claim HID interface: ");
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_csr_device_setup (FuDevice *device, GError **error)
{
@ -530,23 +419,6 @@ fu_csr_device_setup (FuDevice *device, GError **error)
return TRUE;
}
static gboolean
fu_csr_device_close (FuUsbDevice *device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* we're done here */
if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to release interface: ");
return FALSE;
}
/* success */
return TRUE;
}
static void
fu_csr_device_init (FuCsrDevice *self)
{
@ -564,7 +436,5 @@ fu_csr_device_class_init (FuCsrDeviceClass *klass)
klass_device->prepare_firmware = fu_csr_device_prepare_firmware;
klass_device->attach = fu_csr_device_attach;
klass_device->setup = fu_csr_device_setup;
klass_usb_device->open = fu_csr_device_open;
klass_usb_device->close = fu_csr_device_close;
klass_usb_device->probe = fu_csr_device_probe;
}

View File

@ -6,7 +6,8 @@
#pragma once
#include "fu-hid-device.h"
#include "fu-plugin.h"
#define FU_TYPE_CSR_DEVICE (fu_csr_device_get_type ())
G_DECLARE_FINAL_TYPE (FuCsrDevice, fu_csr_device, FU, CSR_DEVICE, FuUsbDevice)
G_DECLARE_FINAL_TYPE (FuCsrDevice, fu_csr_device, FU, CSR_DEVICE, FuHidDevice)

View File

@ -19,7 +19,7 @@
#include <string.h>
#include <errno.h>
#include "fu-usb-device.h"
#include "fu-hid-device.h"
#include "fwupd-error.h"
#include "fu-dell-dock-hid.h"
@ -81,17 +81,14 @@ fu_dell_dock_hid_set_report (FuDevice *self,
guint8 *outbuffer,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gboolean ret;
gsize actual_len = 0;
for (gint i = 1; i <= HID_MAX_RETRIES; i++) {
g_autoptr(GError) error_local = NULL;
ret = g_usb_device_control_transfer (
usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE, FU_HID_REPORT_SET, 0x0200,
0x0000, outbuffer, 192, &actual_len,
HIDI2C_TRANSACTION_TIMEOUT, NULL, &error_local);
ret = fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0,
outbuffer, 192,
HIDI2C_TRANSACTION_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
&error_local);
if (ret)
break;
if (i == HID_MAX_RETRIES ||
@ -107,11 +104,6 @@ fu_dell_dock_hid_set_report (FuDevice *self,
g_usleep (G_USEC_PER_SEC);
}
}
if (actual_len != 192) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"only wrote %" G_GSIZE_FORMAT "bytes", actual_len);
return FALSE;
}
return TRUE;
}
@ -121,17 +113,14 @@ fu_dell_dock_hid_get_report (FuDevice *self,
guint8 *inbuffer,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gboolean ret;
gsize actual_len = 0;
for (gint i = 1; i <= HID_MAX_RETRIES; i++) {
g_autoptr(GError) error_local = NULL;
ret = g_usb_device_control_transfer (
usb_device, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE, FU_HID_REPORT_GET, 0x0100,
0x0000, inbuffer, 192, &actual_len,
HIDI2C_TRANSACTION_TIMEOUT, NULL, &error_local);
ret = fu_hid_device_get_report (FU_HID_DEVICE (self), 0x0,
inbuffer, 192,
HIDI2C_TRANSACTION_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
&error_local);
if (ret)
break;
if (i == HID_MAX_RETRIES ||
@ -146,11 +135,6 @@ fu_dell_dock_hid_get_report (FuDevice *self,
error_local->message);
}
}
if (actual_len != 192) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"only read %" G_GSIZE_FORMAT "bytes", actual_len);
return FALSE;
}
return TRUE;
}

View File

@ -21,13 +21,13 @@
#include "fu-dell-dock-common.h"
struct _FuDellDockHub {
FuUsbDevice parent_instance;
FuHidDevice parent_instance;
guint8 unlock_target;
guint64 blob_major_offset;
guint64 blob_minor_offset;
};
G_DEFINE_TYPE (FuDellDockHub, fu_dell_dock_hub, FU_TYPE_USB_DEVICE)
G_DEFINE_TYPE (FuDellDockHub, fu_dell_dock_hub, FU_TYPE_HID_DEVICE)
static gboolean
fu_dell_dock_hub_probe (FuDevice *device, GError **error)
@ -155,37 +155,6 @@ fu_dell_dock_hub_set_quirk_kv (FuDevice *device,
return FALSE;
}
static gboolean
fu_dell_dock_hub_open (FuUsbDevice *fu_usb_device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (fu_usb_device);
/* open device and clear status */
if (!g_usb_device_claim_interface (
usb_device, 0, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) {
g_prefix_error (error, "failed to claim HID interface: ");
return FALSE;
}
return TRUE;
}
static gboolean
fu_dell_dock_hub_close (FuUsbDevice *fu_usb_device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (fu_usb_device);
if (!g_usb_device_release_interface (
usb_device, 0, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) {
g_prefix_error (error, "failed to release interface: ");
return FALSE;
}
return TRUE;
}
static void
fu_dell_dock_hub_finalize (GObject *object)
{
@ -202,10 +171,7 @@ fu_dell_dock_hub_class_init (FuDellDockHubClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
object_class->finalize = fu_dell_dock_hub_finalize;
klass_usb_device->open = fu_dell_dock_hub_open;
klass_usb_device->close = fu_dell_dock_hub_close;
klass_device->setup = fu_dell_dock_hid_get_hub_version;
klass_device->probe = fu_dell_dock_hub_probe;
klass_device->write_firmware = fu_dell_dock_hub_write_fw;

View File

@ -17,9 +17,9 @@
#include "config.h"
#include "fu-usb-device.h"
#include "fu-hid-device.h"
#define FU_TYPE_DELL_DOCK_HUB (fu_dell_dock_hub_get_type ())
G_DECLARE_FINAL_TYPE (FuDellDockHub, fu_dell_dock_hub, FU, DELL_DOCK_HUB, FuUsbDevice)
G_DECLARE_FINAL_TYPE (FuDellDockHub, fu_dell_dock_hub, FU, DELL_DOCK_HUB, FuHidDevice)
FuDellDockHub *fu_dell_dock_hub_new (FuUsbDevice *device);

View File

@ -9,6 +9,7 @@
#include <string.h>
#include "fu-firmware-common.h"
#include "fu-hid-device.h"
#include "fu-logitech-hidpp-common.h"
#include "fu-logitech-hidpp-bootloader.h"
#include "fu-logitech-hidpp-hidpp.h"
@ -23,7 +24,7 @@ typedef struct
#define FU_UNIFYING_DEVICE_EP1 0x81
#define FU_UNIFYING_DEVICE_EP3 0x83
G_DEFINE_TYPE_WITH_PRIVATE (FuLogitechHidPpBootloader, fu_logitech_hidpp_bootloader, FU_TYPE_USB_DEVICE)
G_DEFINE_TYPE_WITH_PRIVATE (FuLogitechHidPpBootloader, fu_logitech_hidpp_bootloader, FU_TYPE_HID_DEVICE)
#define GET_PRIVATE(o) (fu_logitech_hidpp_bootloader_get_instance_private (o))
@ -342,18 +343,11 @@ fu_logitech_hidpp_bootloader_request (FuLogitechHidPpBootloader *self,
buf_request, sizeof (buf_request));
}
if (usb_device != NULL) {
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET,
0x0200, 0x0000,
buf_request,
sizeof (buf_request),
&actual_length,
FU_UNIFYING_DEVICE_TIMEOUT_MS,
NULL,
error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0,
buf_request, sizeof(buf_request),
FU_UNIFYING_DEVICE_TIMEOUT_MS,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to send data: ");
return FALSE;
}

View File

@ -6,14 +6,14 @@
#pragma once
#include "fu-usb-device.h"
#include "fu-hid-device.h"
#define FU_TYPE_UNIFYING_BOOTLOADER (fu_logitech_hidpp_bootloader_get_type ())
G_DECLARE_DERIVABLE_TYPE (FuLogitechHidPpBootloader, fu_logitech_hidpp_bootloader, FU, UNIFYING_BOOTLOADER, FuUsbDevice)
G_DECLARE_DERIVABLE_TYPE (FuLogitechHidPpBootloader, fu_logitech_hidpp_bootloader, FU, UNIFYING_BOOTLOADER, FuHidDevice)
struct _FuLogitechHidPpBootloaderClass
{
FuUsbDeviceClass parent_class;
FuHidDeviceClass parent_class;
gboolean (*setup) (FuLogitechHidPpBootloader *self,
GError **error);
};

View File

@ -13,14 +13,12 @@
#include "fu-rts54hid-device.h"
struct _FuRts54HidDevice {
FuUsbDevice parent_instance;
FuHidDevice parent_instance;
gboolean fw_auth;
gboolean dual_bank;
};
G_DEFINE_TYPE (FuRts54HidDevice, fu_rts54hid_device, FU_TYPE_USB_DEVICE)
#define FU_RTS54HID_DEVICE_TIMEOUT 1000 /* ms */
G_DEFINE_TYPE (FuRts54HidDevice, fu_rts54hid_device, FU_TYPE_HID_DEVICE)
static void
fu_rts54hid_device_to_string (FuDevice *device, guint idt, GString *str)
@ -30,62 +28,6 @@ fu_rts54hid_device_to_string (FuDevice *device, guint idt, GString *str)
fu_common_string_append_kb (str, idt, "DualBank", self->dual_bank);
}
gboolean
fu_rts54hid_device_set_report (FuRts54HidDevice *self,
guint8 *buf, gsize buf_sz,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize actual_len = 0;
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET,
0x0200, 0x0000,
buf, buf_sz,
&actual_len,
FU_RTS54HID_DEVICE_TIMEOUT * 2,
NULL, error)) {
g_prefix_error (error, "failed to SetReport: ");
return FALSE;
}
if (actual_len != buf_sz) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"only wrote %" G_GSIZE_FORMAT "bytes", actual_len);
return FALSE;
}
return TRUE;
}
gboolean
fu_rts54hid_device_get_report (FuRts54HidDevice *self,
guint8 *buf, gsize buf_sz,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize actual_len = 0;
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_GET,
0x0100, 0x0000,
buf, buf_sz,
&actual_len, /* actual length */
FU_RTS54HID_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "failed to GetReport: ");
return FALSE;
}
if (actual_len != buf_sz) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"only read %" G_GSIZE_FORMAT "bytes", actual_len);
return FALSE;
}
return TRUE;
}
static gboolean
fu_rts54hid_device_set_clock_mode (FuRts54HidDevice *self, gboolean enable, GError **error)
{
@ -101,7 +43,10 @@ fu_rts54hid_device_set_clock_mode (FuRts54HidDevice *self, gboolean enable, GErr
};
guint8 buf[FU_RTS54FU_HID_REPORT_LENGTH] = { 0 };
memcpy (buf, &cmd_buffer, sizeof(cmd_buffer));
if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to set clock-mode=%i: ", enable);
return FALSE;
}
@ -120,7 +65,10 @@ fu_rts54hid_device_reset_to_flash (FuRts54HidDevice *self, GError **error)
};
guint8 buf[FU_RTS54FU_HID_REPORT_LENGTH] = { 0 };
memcpy (buf, &cmd_buffer, sizeof(cmd_buffer));
if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to soft reset: ");
return FALSE;
}
@ -152,7 +100,10 @@ fu_rts54hid_device_write_flash (FuRts54HidDevice *self,
data, data_sz, 0x0, /* src */
data_sz, error))
return FALSE;
if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to write flash @%08x: ", (guint) addr);
return FALSE;
}
@ -176,10 +127,16 @@ fu_rts54hid_device_verify_update_fw (FuRts54HidDevice *self, GError **error)
/* set then get */
memcpy (buf, &cmd_buffer, sizeof(cmd_buffer));
if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error))
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
g_usleep (4 * G_USEC_PER_SEC);
if (!fu_rts54hid_device_get_report (self, buf, sizeof(buf), error))
if (!fu_hid_device_get_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
/* check device status */
@ -210,7 +167,10 @@ fu_rts54hid_device_erase_spare_bank (FuRts54HidDevice *self, GError **error)
};
guint8 buf[FU_RTS54FU_HID_REPORT_LENGTH] = { 0 };
memcpy (buf, &cmd_buffer, sizeof(cmd_buffer));
if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to erase spare bank: ");
return FALSE;
}
@ -235,9 +195,15 @@ fu_rts54hid_device_ensure_status (FuRts54HidDevice *self, GError **error)
/* set then get */
memcpy (buf, &cmd_buffer, sizeof(cmd_buffer));
if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error))
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
if (!fu_rts54hid_device_get_report (self, buf, sizeof(buf), error))
if (!fu_hid_device_get_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
/* check the hardware capabilities */
@ -250,25 +216,6 @@ fu_rts54hid_device_ensure_status (FuRts54HidDevice *self, GError **error)
return TRUE;
}
static gboolean
fu_rts54hid_device_open (FuUsbDevice *device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* disconnect, set config, reattach kernel driver */
if (!g_usb_device_set_configuration (usb_device, 0x00, error))
return FALSE;
if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to claim interface: ");
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_rts54hid_device_setup (FuDevice *device, GError **error)
{
@ -294,25 +241,12 @@ fu_rts54hid_device_setup (FuDevice *device, GError **error)
}
static gboolean
fu_rts54hid_device_close (FuUsbDevice *device, GError **error)
fu_rts54hid_device_close (FuHidDevice *device, GError **error)
{
FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device);
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* set MCU to normal clock rate */
if (!fu_rts54hid_device_set_clock_mode (self, FALSE, error))
return FALSE;
/* we're done here */
if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to release interface: ");
return FALSE;
}
/* success */
return TRUE;
return fu_rts54hid_device_set_clock_mode (self, FALSE, error);
}
static gboolean
@ -385,10 +319,9 @@ static void
fu_rts54hid_device_class_init (FuRts54HidDeviceClass *klass)
{
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
FuHidDeviceClass *klass_hid_device = FU_HID_DEVICE_CLASS (klass);
klass_device->write_firmware = fu_rts54hid_device_write_firmware;
klass_device->to_string = fu_rts54hid_device_to_string;
klass_device->setup = fu_rts54hid_device_setup;
klass_usb_device->open = fu_rts54hid_device_open;
klass_usb_device->close = fu_rts54hid_device_close;
klass_hid_device->close = fu_rts54hid_device_close;
}

View File

@ -6,16 +6,9 @@
#pragma once
#include "fu-plugin.h"
#include "fu-hid-device.h"
#define FU_TYPE_RTS54HID_DEVICE (fu_rts54hid_device_get_type ())
G_DECLARE_FINAL_TYPE (FuRts54HidDevice, fu_rts54hid_device, FU, RTS54HID_DEVICE, FuUsbDevice)
G_DECLARE_FINAL_TYPE (FuRts54HidDevice, fu_rts54hid_device, FU, RTS54HID_DEVICE, FuHidDevice)
gboolean fu_rts54hid_device_set_report (FuRts54HidDevice *self,
guint8 *buf,
gsize buf_sz,
GError **error);
gboolean fu_rts54hid_device_get_report (FuRts54HidDevice *self,
guint8 *buf,
gsize buf_sz,
GError **error);
#define FU_RTS54HID_DEVICE_TIMEOUT 1000 /* ms */

View File

@ -9,6 +9,8 @@
#include <string.h>
#include "fu-chunk.h"
#include "fu-hid-device.h"
#include "fu-rts54hid-common.h"
#include "fu-rts54hid-module.h"
#include "fu-rts54hid-device.h"
@ -77,7 +79,10 @@ fu_rts54hid_module_i2c_write (FuRts54HidModule *self,
data, data_sz, 0x0, /* src */
data_sz, error))
return FALSE;
if (!fu_rts54hid_device_set_report (parent, buf, sizeof(buf), error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (parent), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr);
return FALSE;
}
@ -114,11 +119,17 @@ fu_rts54hid_module_i2c_read (FuRts54HidModule *self,
/* read from module */
memcpy (buf, &cmd_buffer, sizeof(cmd_buffer));
if (!fu_rts54hid_device_set_report (parent, buf, sizeof(buf), error)) {
if (!fu_hid_device_set_report (FU_HID_DEVICE (parent), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT * 2,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr);
return FALSE;
}
if (!fu_rts54hid_device_get_report (parent, buf, sizeof(buf), error))
if (!fu_hid_device_get_report (FU_HID_DEVICE (parent), 0x0, buf, sizeof(buf),
FU_RTS54HID_DEVICE_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
return fu_memcpy_safe (data, data_sz, 0x0,
buf, sizeof(buf), FU_RTS54HID_CMD_BUFFER_OFFSET_DATA,

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2005-2019 Synaptics Incorporated
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2019-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@ -18,7 +18,7 @@
struct _FuSynapticsCxaudioDevice
{
FuUsbDevice parent_instance;
FuHidDevice parent_instance;
guint32 chip_id_base;
guint32 chip_id;
gboolean serial_number_set;
@ -32,7 +32,7 @@ struct _FuSynapticsCxaudioDevice
guint8 patch_level;
};
G_DEFINE_TYPE (FuSynapticsCxaudioDevice, fu_synaptics_cxaudio_device, FU_TYPE_USB_DEVICE)
G_DEFINE_TYPE (FuSynapticsCxaudioDevice, fu_synaptics_cxaudio_device, FU_TYPE_HID_DEVICE)
static void
fu_synaptics_cxaudio_device_to_string (FuDevice *device, guint idt, GString *str)
@ -48,38 +48,14 @@ fu_synaptics_cxaudio_device_to_string (FuDevice *device, guint idt, GString *str
fu_common_string_append_kb (str, idt, "SerialNumberSet", self->serial_number_set);
}
static gboolean
fu_synaptics_cxaudio_device_open (FuUsbDevice *device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* get firmware version */
if (!g_usb_device_claim_interface (usb_device, FU_SYNAPTICS_CXAUDIO_HID_INTERFACE,
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to claim interface: ");
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_synaptics_cxaudio_device_output_report (FuSynapticsCxaudioDevice *self,
guint8 *buf,
guint16 bufsz,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
guint16 report_number = buf[0];
gsize actual_length = 0;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (bufsz != 0, FALSE);
/* weird */
if (report_number == 0x0) {
if (buf[0] == 0x0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
@ -88,30 +64,11 @@ fu_synaptics_cxaudio_device_output_report (FuSynapticsCxaudioDevice *self,
}
/* to device */
if (g_getenv ("FWUPD_SYNAPTICS_CXAUDIO_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "HID::WRITE", buf, bufsz);
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET,
(FU_HID_REPORT_TYPE_OUTPUT << 8) | report_number,
FU_SYNAPTICS_CXAUDIO_HID_INTERFACE,
buf, bufsz, &actual_length,
FU_SYNAPTICS_CXAUDIO_USB_TIMEOUT, NULL, error)) {
return FALSE;
}
if (bufsz != actual_length) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"wrote 0x%x bytes of 0x%x",
(guint) actual_length, bufsz);
return FALSE;
}
/* success */
return TRUE;
return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0],
buf, bufsz,
FU_SYNAPTICS_CXAUDIO_USB_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
error);
}
static gboolean
@ -121,37 +78,11 @@ fu_synaptics_cxaudio_device_input_report (FuSynapticsCxaudioDevice *self,
guint16 bufsz,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize actual_length = 0;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (bufsz != 0, FALSE);
/* from device */
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_GET,
(FU_HID_REPORT_TYPE_INPUT << 8) | ReportID,
FU_SYNAPTICS_CXAUDIO_HID_INTERFACE,
buf, bufsz, &actual_length,
FU_SYNAPTICS_CXAUDIO_USB_TIMEOUT, NULL, error)) {
return FALSE;
}
if (g_getenv ("FWUPD_SYNAPTICS_CXAUDIO_VERBOSE") != NULL)
fu_common_dump_raw (G_LOG_DOMAIN, "HID::READ", buf, bufsz);
if (bufsz != actual_length) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"read 0x%x bytes of expected 0x%x",
(guint) actual_length, bufsz);
return FALSE;
}
/* success */
return TRUE;
return fu_hid_device_get_report (FU_HID_DEVICE (self), ReportID,
buf, bufsz,
FU_SYNAPTICS_CXAUDIO_USB_TIMEOUT,
FU_HID_DEVICE_FLAG_NONE,
error);
}
typedef enum {
@ -643,23 +574,6 @@ fu_synaptics_cxaudio_device_setup (FuDevice *device, GError **error)
return TRUE;
}
static gboolean
fu_synaptics_cxaudio_device_close (FuUsbDevice *device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* we're done here */
if (!g_usb_device_release_interface (usb_device, FU_SYNAPTICS_CXAUDIO_HID_INTERFACE,
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to release interface: ");
return FALSE;
}
/* success */
return TRUE;
}
static FuFirmware *
fu_synaptics_cxaudio_device_prepare_firmware (FuDevice *device,
GBytes *fw,
@ -854,18 +768,16 @@ fu_synaptics_cxaudio_device_init (FuSynapticsCxaudioDevice *self)
fu_device_set_install_duration (FU_DEVICE (self), 3); /* seconds */
fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.cxaudio");
fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
fu_hid_device_set_interface (FU_HID_DEVICE (self), FU_SYNAPTICS_CXAUDIO_HID_INTERFACE);
}
static void
fu_synaptics_cxaudio_device_class_init (FuSynapticsCxaudioDeviceClass *klass)
{
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
klass_device->to_string = fu_synaptics_cxaudio_device_to_string;
klass_device->set_quirk_kv = fu_synaptics_cxaudio_device_set_quirk_kv;
klass_device->setup = fu_synaptics_cxaudio_device_setup;
klass_device->write_firmware = fu_synaptics_cxaudio_device_write_firmware;
klass_device->prepare_firmware = fu_synaptics_cxaudio_device_prepare_firmware;
klass_usb_device->open = fu_synaptics_cxaudio_device_open;
klass_usb_device->close = fu_synaptics_cxaudio_device_close;
}

View File

@ -6,12 +6,13 @@
#pragma once
#include "fu-hid-device.h"
#include "fu-plugin.h"
#define FU_TYPE_SYNAPTICS_CXAUDIO_DEVICE (fu_synaptics_cxaudio_device_get_type ())
G_DECLARE_FINAL_TYPE (FuSynapticsCxaudioDevice, fu_synaptics_cxaudio_device, FU, SYNAPTICS_CXAUDIO_DEVICE, FuUsbDevice)
G_DECLARE_FINAL_TYPE (FuSynapticsCxaudioDevice, fu_synaptics_cxaudio_device, FU, SYNAPTICS_CXAUDIO_DEVICE, FuHidDevice)
struct _FuSynapticsCxaudioDeviceClass
{
FuUsbDeviceClass parent_class;
FuHidDeviceClass parent_class;
};

View File

@ -35,7 +35,7 @@ typedef enum {
struct _FuWacDevice
{
FuUsbDevice parent_instance;
FuHidDevice parent_instance;
GPtrArray *flash_descriptors;
GArray *checksums;
guint32 status_word;
@ -48,7 +48,7 @@ struct _FuWacDevice
guint16 configuration;
};
G_DEFINE_TYPE (FuWacDevice, fu_wac_device, FU_TYPE_USB_DEVICE)
G_DEFINE_TYPE (FuWacDevice, fu_wac_device, FU_TYPE_HID_DEVICE)
static GString *
fu_wac_device_status_to_string (guint32 status_word)
@ -135,42 +135,20 @@ fu_wac_device_to_string (FuDevice *device, guint idt, GString *str)
gboolean
fu_wac_device_get_feature_report (FuWacDevice *self,
guint8 *buf, gsize bufsz,
FuWacDeviceFeatureFlags flags,
FuHidDeviceFlags flags,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize sz = 0;
guint8 cmd = buf[0];
/* hit hardware */
if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG) == 0)
fu_wac_buffer_dump ("GET", cmd, buf, bufsz);
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_GET, /* bRequest */
FU_HID_FEATURE | cmd, /* wValue */
0x0000, /* wIndex */
buf, bufsz, &sz,
FU_WAC_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "Failed to get feature report: ");
if (!fu_hid_device_get_report (FU_HID_DEVICE (self), cmd,
buf, bufsz,
FU_WAC_DEVICE_TIMEOUT,
flags | FU_HID_DEVICE_FLAG_IS_FEATURE,
error))
return FALSE;
}
if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG) == 0)
fu_wac_buffer_dump ("GE2", cmd, buf, sz);
/* check packet */
if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"packet get bytes %" G_GSIZE_FORMAT
" expected %" G_GSIZE_FORMAT,
sz, bufsz);
return FALSE;
}
if (buf[0] != cmd) {
g_set_error (error,
FWUPD_ERROR,
@ -185,42 +163,17 @@ fu_wac_device_get_feature_report (FuWacDevice *self,
gboolean
fu_wac_device_set_feature_report (FuWacDevice *self,
guint8 *buf, gsize bufsz,
FuWacDeviceFeatureFlags flags,
FuHidDeviceFlags flags,
GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
gsize sz = 0;
guint8 cmd = buf[0];
/* hit hardware */
fu_wac_buffer_dump ("SET", cmd, buf, bufsz);
if (g_getenv ("FWUPD_WAC_EMULATE") != NULL)
return TRUE;
if (!g_usb_device_control_transfer (usb_device,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_CLASS,
G_USB_DEVICE_RECIPIENT_INTERFACE,
FU_HID_REPORT_SET, /* bRequest */
FU_HID_FEATURE | cmd, /* wValue */
0x0000, /* wIndex */
buf, bufsz, &sz,
FU_WAC_DEVICE_TIMEOUT,
NULL, error)) {
g_prefix_error (error, "Failed to set feature report: ");
return FALSE;
}
/* check packet */
if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"packet sent bytes %" G_GSIZE_FORMAT
" expected %" G_GSIZE_FORMAT,
sz, bufsz);
return FALSE;
}
return TRUE;
return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0],
buf, bufsz,
FU_WAC_DEVICE_TIMEOUT,
flags | FU_HID_DEVICE_FLAG_IS_FEATURE,
error);
}
static gboolean
@ -238,7 +191,7 @@ fu_wac_device_ensure_flash_descriptors (FuWacDevice *self, GError **error)
memset (buf, 0xff, sz);
buf[0] = FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR;
if (!fu_wac_device_get_feature_report (self, buf, sz,
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
@ -265,7 +218,7 @@ fu_wac_device_ensure_status (FuWacDevice *self, GError **error)
/* hit hardware */
buf[0] = FU_WAC_REPORT_ID_GET_STATUS;
if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
@ -287,7 +240,7 @@ fu_wac_device_ensure_checksums (FuWacDevice *self, GError **error)
memset (buf, 0xff, sz);
buf[0] = FU_WAC_REPORT_ID_GET_CHECKSUMS;
if (!fu_wac_device_get_feature_report (self, buf, sz,
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
@ -316,7 +269,7 @@ fu_wac_device_ensure_firmware_index (FuWacDevice *self, GError **error)
/* hit hardware */
if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
@ -333,7 +286,7 @@ fu_wac_device_ensure_parameters (FuWacDevice *self, GError **error)
/* hit hardware */
if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error))
return FALSE;
@ -383,7 +336,7 @@ fu_wac_device_write_block (FuWacDevice *self,
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, bufsz,
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -398,7 +351,7 @@ fu_wac_device_erase_block (FuWacDevice *self, guint32 addr, GError **error)
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -410,7 +363,7 @@ fu_wac_device_update_reset (FuWacDevice *self, GError **error)
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -429,7 +382,7 @@ fu_wac_device_set_checksum_of_block (FuWacDevice *self,
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -446,7 +399,7 @@ fu_wac_device_calculate_checksum_of_block (FuWacDevice *self,
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -458,7 +411,7 @@ fu_wac_device_write_checksum_table (FuWacDevice *self, GError **error)
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -471,7 +424,7 @@ fu_wac_device_switch_to_flash_loader (FuWacDevice *self, GError **error)
/* hit hardware */
return fu_wac_device_set_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error);
}
@ -676,7 +629,7 @@ fu_wac_device_add_modules_bluetooth (FuWacDevice *self, GError **error)
buf[0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH;
if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "Failed to get GetFirmwareVersionBluetooth: ");
return FALSE;
@ -714,7 +667,7 @@ fu_wac_device_add_modules (FuWacDevice *self, GError **error)
[1 ... 31] = 0xff };
if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_NONE,
FU_HID_DEVICE_FLAG_NONE,
error)) {
g_prefix_error (error, "Failed to get DeviceFirmwareDescriptor: ");
return FALSE;
@ -780,23 +733,6 @@ fu_wac_device_add_modules (FuWacDevice *self, GError **error)
return TRUE;
}
static gboolean
fu_wac_device_open (FuUsbDevice *device, GError **error)
{
GUsbDevice *usb_device = fu_usb_device_get_dev (device);
/* open device */
if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */
G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
error)) {
g_prefix_error (error, "failed to claim HID interface: ");
return FALSE;
}
/* success */
return TRUE;
}
static gboolean
fu_wac_device_setup (FuDevice *device, GError **error)
{
@ -879,6 +815,5 @@ fu_wac_device_class_init (FuWacDeviceClass *klass)
klass_device->write_firmware = fu_wac_device_write_firmware;
klass_device->to_string = fu_wac_device_to_string;
klass_device->setup = fu_wac_device_setup;
klass_usb_device->open = fu_wac_device_open;
klass_usb_device->close = fu_wac_device_close;
}

View File

@ -7,26 +7,20 @@
#pragma once
#include "fu-plugin.h"
#include "fu-hid-device.h"
#define FU_TYPE_WAC_DEVICE (fu_wac_device_get_type ())
G_DECLARE_FINAL_TYPE (FuWacDevice, fu_wac_device, FU, WAC_DEVICE, FuUsbDevice)
typedef enum {
FU_WAC_DEVICE_FEATURE_FLAG_NONE = 0,
FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC = 1 << 0,
FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG = 1 << 1,
FU_WAC_DEVICE_FEATURE_FLAG_LAST
} FuWacDeviceFeatureFlags;
G_DECLARE_FINAL_TYPE (FuWacDevice, fu_wac_device, FU, WAC_DEVICE, FuHidDevice)
gboolean fu_wac_device_update_reset (FuWacDevice *self,
GError **error);
gboolean fu_wac_device_get_feature_report (FuWacDevice *self,
guint8 *buf,
gsize bufsz,
FuWacDeviceFeatureFlags flags,
FuHidDeviceFlags flags,
GError **error);
gboolean fu_wac_device_set_feature_report (FuWacDevice *self,
guint8 *buf,
gsize bufsz,
FuWacDeviceFeatureFlags flags,
FuHidDeviceFlags flags,
GError **error);

View File

@ -130,8 +130,7 @@ fu_wac_module_refresh (FuWacModule *self, GError **error)
/* get from hardware */
if (!fu_wac_device_get_feature_report (parent_device, buf, sizeof(buf),
FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC |
FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG,
FU_HID_DEVICE_FLAG_ALLOW_TRUNC,
error)) {
g_prefix_error (error, "failed to refresh status: ");
return FALSE;
@ -211,7 +210,7 @@ fu_wac_module_set_feature (FuWacModule *self,
/* send to hardware */
if (!fu_wac_device_set_feature_report (parent_device, buf, len + 3,
FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC,
FU_HID_DEVICE_FLAG_ALLOW_TRUNC,
error)) {
g_prefix_error (error, "failed to set module feature: ");
return FALSE;