Commit 822e134e authored by Richard Hughes's avatar Richard Hughes
Browse files

unifying: Split up the HID++2.0 and HID++1.0 functionality

parent 2a247e85
......@@ -123,6 +123,22 @@ fu_plugin_unifying_detach_cb (gpointer user_data)
return FALSE;
}
static gboolean
fu_plugin_unifying_attach_cb (gpointer user_data)
{
LuDevice *device = LU_DEVICE (user_data);
g_autoptr(GError) error = NULL;
/* ditch this device */
g_debug ("attaching");
if (!lu_device_attach (device, &error)) {
g_warning ("failed to detach: %s", error->message);
return FALSE;
}
return FALSE;
}
gboolean
fu_plugin_update_online (FuPlugin *plugin,
FuDevice *dev,
......@@ -143,10 +159,13 @@ fu_plugin_update_online (FuPlugin *plugin,
/* switch to bootloader */
data->ignore_replug = TRUE;
if (lu_device_has_flag (device, LU_DEVICE_FLAG_REQUIRES_DETACH)) {
if (!lu_device_detach (device, error))
return FALSE;
/* wait for device to come back */
if (lu_device_has_flag (device, LU_DEVICE_FLAG_DETACH_WILL_REPLUG)) {
g_debug ("doing detach in idle");
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
fu_plugin_unifying_detach_cb,
g_object_ref (device),
(GDestroyNotify) g_object_unref);
if (!lu_context_wait_for_replug (data->ctx,
device,
FU_DEVICE_TIMEOUT_REPLUG,
......@@ -158,6 +177,10 @@ fu_plugin_update_online (FuPlugin *plugin,
return FALSE;
if (!lu_device_open (device, error))
return FALSE;
} else {
g_debug ("doing detach in main thread");
if (!lu_device_detach (device, error))
return FALSE;
}
}
......@@ -168,23 +191,34 @@ fu_plugin_update_online (FuPlugin *plugin,
error))
return FALSE;
fu_plugin_set_status (plugin, FWUPD_STATUS_DEVICE_RESTART);
if (!lu_device_attach (device, error))
return FALSE;
/* wait for it to appear back in runtime mode */
if (!lu_context_wait_for_replug (data->ctx,
device,
FU_DEVICE_TIMEOUT_REPLUG,
error))
return FALSE;
g_object_unref (device);
if (lu_device_has_flag (device, LU_DEVICE_FLAG_REQUIRES_ATTACH)) {
if (lu_device_has_flag (device, LU_DEVICE_FLAG_ATTACH_WILL_REPLUG)) {
g_debug ("doing attach in idle");
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
fu_plugin_unifying_attach_cb,
g_object_ref (device),
(GDestroyNotify) g_object_unref);
if (!lu_context_wait_for_replug (data->ctx,
device,
FU_DEVICE_TIMEOUT_REPLUG,
error))
return FALSE;
g_object_unref (device);
device = fu_plugin_unifying_get_device (plugin, dev, error);
if (device == NULL)
return FALSE;
if (!lu_device_open (device, error))
return FALSE;
} else {
g_debug ("doing attach in main thread");
if (!lu_device_attach (device, error))
return FALSE;
}
}
/* get the new device version */
device = fu_plugin_unifying_get_device (plugin, dev, error);
if (device == NULL)
return FALSE;
if (!lu_device_open (device, error))
return FALSE;
/* set new version */
fu_device_set_version (dev, lu_device_get_version_fw (device));
/* success */
......
......@@ -181,6 +181,14 @@ lu_context_add_device (LuContext *ctx, LuDevice *device)
g_debug ("device %s added", lu_device_get_platform_id (device));
/* HID++1.0 devices have to sleep to allow Solaar to talk to the device
* first -- we can't use the SwID as this is a HID++2.0 feature */
if (ctx->done_coldplug &&
lu_device_get_hidpp_version (device) <= 1.f) {
g_debug ("waiting for device to settle...");
g_usleep (G_USEC_PER_SEC);
}
/* try to open */
if (!lu_device_open (device, &error)) {
if (g_error_matches (error,
......@@ -364,10 +372,6 @@ lu_context_wait_for_replug (LuContext *ctx,
g_return_val_if_fail (LU_IS_CONTEXT (ctx), FALSE);
g_return_val_if_fail (LU_IS_DEVICE (device), FALSE);
/* enforce the device is closed */
if (!lu_device_close (device, error))
return FALSE;
/* create a helper */
replug_helper = g_new0 (GUsbContextReplugHelper, 1);
replug_helper->device = g_object_ref (device);
......@@ -559,7 +563,9 @@ lu_context_usb_device_added_cb (GUsbContext *usb_ctx,
g_autoptr(LuDevice) device = NULL;
device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER_NORDIC,
"kind", LU_DEVICE_KIND_BOOTLOADER_NORDIC,
"flags", LU_DEVICE_FLAG_ACTIVE,
"flags", LU_DEVICE_FLAG_ACTIVE |
LU_DEVICE_FLAG_REQUIRES_ATTACH |
LU_DEVICE_FLAG_ATTACH_WILL_REPLUG,
"hidpp-id", HIDPP_DEVICE_ID_RECEIVER,
"usb-device", usb_device,
NULL);
......@@ -572,7 +578,9 @@ lu_context_usb_device_added_cb (GUsbContext *usb_ctx,
g_autoptr(LuDevice) device = NULL;
device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER_TEXAS,
"kind", LU_DEVICE_KIND_BOOTLOADER_TEXAS,
"flags", LU_DEVICE_FLAG_ACTIVE,
"flags", LU_DEVICE_FLAG_ACTIVE |
LU_DEVICE_FLAG_REQUIRES_ATTACH |
LU_DEVICE_FLAG_ATTACH_WILL_REPLUG,
"hidpp-id", HIDPP_DEVICE_ID_RECEIVER,
"usb-device", usb_device,
NULL);
......
......@@ -41,7 +41,7 @@ lu_device_peripheral_fetch_firmware_info (LuDevice *device, GError **error)
LuDevicePeripheral *self = LU_DEVICE_PERIPHERAL (device);
guint8 idx;
guint8 entity_count;
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* get the feature index */
idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_I_FIRMWARE_INFO);
......@@ -118,7 +118,7 @@ lu_device_peripheral_fetch_battery_level (LuDevice *device, GError **error)
guint8 idx;
idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_BATTERY_LEVEL_STATUS);
if (idx != 0x00) {
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
msg->report_id = HIDPP_REPORT_ID_SHORT;
msg->device_id = lu_device_get_hidpp_id (device);
msg->sub_id = idx;
......@@ -135,7 +135,7 @@ lu_device_peripheral_fetch_battery_level (LuDevice *device, GError **error)
/* try HID++1.0 battery mileage */
if (lu_device_get_hidpp_version (device) == 1.f) {
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
msg->report_id = HIDPP_REPORT_ID_SHORT;
msg->device_id = lu_device_get_hidpp_id (device);
msg->sub_id = HIDPP_SUBID_GET_REGISTER;
......@@ -180,7 +180,7 @@ lu_device_peripheral_ping (LuDevice *device, GError **error)
{
gdouble version;
g_autoptr(GError) error_local = NULL;
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* handle failure */
msg->report_id = HIDPP_REPORT_ID_SHORT;
......@@ -275,7 +275,7 @@ lu_device_peripheral_probe (LuDevice *device, GError **error)
idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU_CONTROL_SIGNED);
if (idx != 0x00) {
/* check the feature is available */
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
msg->report_id = HIDPP_REPORT_ID_SHORT;
msg->device_id = lu_device_get_hidpp_id (device);
msg->sub_id = idx;
......@@ -311,7 +311,7 @@ static gboolean
lu_device_peripheral_detach (LuDevice *device, GError **error)
{
guint8 idx;
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* this requires user action */
idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU_CONTROL);
......@@ -327,8 +327,8 @@ lu_device_peripheral_detach (LuDevice *device, GError **error)
msg->data[4] = 'D';
msg->data[5] = 'F';
msg->data[6] = 'U';
msg->flags = LU_DEVICE_HIDPP_MSG_FLAG_IGNORE_SWID |
LU_DEVICE_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
msg->flags = LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID |
LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
if (!lu_device_hidpp_transfer (device, msg, error)) {
g_prefix_error (error, "failed to put device into DFU mode: ");
return FALSE;
......@@ -351,7 +351,7 @@ lu_device_peripheral_detach (LuDevice *device, GError **error)
msg->data[4] = 'D';
msg->data[5] = 'F';
msg->data[6] = 'U';
msg->flags = LU_DEVICE_HIDPP_MSG_FLAG_IGNORE_SWID;
msg->flags = LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID;
if (!lu_device_hidpp_transfer (device, msg, error)) {
g_prefix_error (error, "failed to put device into DFU mode: ");
return FALSE;
......@@ -523,7 +523,7 @@ lu_device_peripheral_write_firmware_pkt (LuDevice *device,
GError **error)
{
guint32 packet_cnt_be;
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
g_autoptr(GError) error_local = NULL;
/* send firmware data */
......@@ -557,12 +557,11 @@ lu_device_peripheral_write_firmware_pkt (LuDevice *device,
/* wait for the HID++ notification */
g_debug ("ignoring: %s", error_local->message);
for (guint retry = 0; retry < 10; retry++) {
g_autoptr(LuDeviceHidppMsg) msg2 = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg2 = lu_hidpp_msg_new ();
msg2->flags = LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID;
if (!lu_device_hidpp_receive (device, msg2, 15000, error))
return FALSE;
if (msg2->report_id == msg->report_id &&
msg2->device_id == msg->device_id &&
msg2->sub_id == msg->sub_id) {
if (lu_hidpp_msg_is_reply (msg, msg2)) {
g_autoptr(GError) error2 = NULL;
if (!lu_device_peripheral_check_status (msg2->data[4], &error2)) {
g_debug ("got %s, waiting a bit longer", error2->message);
......@@ -637,7 +636,7 @@ lu_device_peripheral_attach (LuDevice *device, GError **error)
{
LuDevicePeripheral *self = LU_DEVICE_PERIPHERAL (device);
guint8 idx;
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* if we're in bootloader mode, we should be able to get this feature */
idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU);
......@@ -655,8 +654,9 @@ lu_device_peripheral_attach (LuDevice *device, GError **error)
msg->sub_id = idx;
msg->function_id = 0x05 << 4; /* restart */
msg->data[0] = self->cached_fw_entity; /* fwEntity */
msg->flags = LU_DEVICE_HIDPP_MSG_FLAG_IGNORE_SWID |
LU_DEVICE_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
msg->flags = LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID |
LU_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred?
LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
if (!lu_device_hidpp_transfer (device, msg, error)) {
g_prefix_error (error, "failed to restart device: ");
return FALSE;
......@@ -670,6 +670,35 @@ lu_device_peripheral_attach (LuDevice *device, GError **error)
return TRUE;
}
static gboolean
lu_device_peripheral_poll (LuDevice *device, GError **error)
{
const guint timeout = 1; /* ms */
g_autoptr(GError) error_local = NULL;
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* flush pending data */
if (!lu_device_hidpp_receive (device, msg, timeout, &error_local)) {
if (!g_error_matches (error_local,
G_IO_ERROR,
G_IO_ERROR_TIMED_OUT)) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to get pending read: %s",
error_local->message);
return FALSE;
}
}
/* just ping */
if (lu_device_has_flag (device, LU_DEVICE_FLAG_ACTIVE))
return lu_device_peripheral_ping (device, error);
/* probe, which also involves a ping first */
return lu_device_probe (device, error);
}
static void
lu_device_peripheral_finalize (GObject *object)
{
......@@ -684,7 +713,7 @@ lu_device_peripheral_class_init (LuDevicePeripheralClass *klass)
object_class->finalize = lu_device_peripheral_finalize;
klass_device->probe = lu_device_peripheral_probe;
klass_device->poll = lu_device_peripheral_ping;
klass_device->poll = lu_device_peripheral_poll;
klass_device->write_firmware = lu_device_peripheral_write_firmware;
klass_device->attach = lu_device_peripheral_attach;
klass_device->detach = lu_device_peripheral_detach;
......
......@@ -39,7 +39,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
static gboolean
lu_device_runtime_enable_notifications (LuDevice *device, GError **error)
{
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
msg->report_id = HIDPP_REPORT_ID_SHORT;
msg->device_id = lu_device_get_hidpp_id (device);
msg->sub_id = HIDPP_SUBID_SET_REGISTER;
......@@ -110,7 +110,7 @@ lu_device_runtime_open (LuDevice *device, GError **error)
/* read all 10 bytes of the version register */
memset (config, 0x00, sizeof (config));
for (guint i = 0x01; i < 0x05; i++) {
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* workaround a bug in the 12.01 firmware, which fails with
* INVALID_VALUE when reading MCU1_HW_VERSION */
......@@ -173,7 +173,7 @@ lu_device_runtime_open (LuDevice *device, GError **error)
static gboolean
lu_device_runtime_detach (LuDevice *device, GError **error)
{
g_autoptr(LuDeviceHidppMsg) msg = lu_device_hidpp_new ();
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
msg->report_id = HIDPP_REPORT_ID_SHORT;
msg->device_id = lu_device_get_hidpp_id (device);
msg->sub_id = HIDPP_SUBID_SET_REGISTER;
......@@ -181,7 +181,7 @@ lu_device_runtime_detach (LuDevice *device, GError **error)
msg->data[0] = 'I';
msg->data[1] = 'C';
msg->data[2] = 'P';
msg->flags = LU_DEVICE_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
msg->flags = LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
if (!lu_device_hidpp_send (device, msg, LU_DEVICE_TIMEOUT_MS, error)) {
g_prefix_error (error, "failed to detach to bootloader: ");
return FALSE;
......@@ -189,11 +189,60 @@ lu_device_runtime_detach (LuDevice *device, GError **error)
return TRUE;
}
static gboolean
lu_device_runtime_poll (LuDevice *device, GError **error)
{
const guint timeout = 1; /* ms */
g_autoptr(GError) error_local = NULL;
g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new ();
/* is there any pending data to read */
if (!lu_device_hidpp_receive (device, msg, timeout, &error_local)) {
if (g_error_matches (error_local,
G_IO_ERROR,
G_IO_ERROR_TIMED_OUT)) {
return TRUE;
}
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"failed to get pending read: %s",
error_local->message);
return FALSE;
}
/* HID++1.0 error */
if (!lu_hidpp_msg_is_error (msg, error))
return FALSE;
/* unifying receiver notification */
if (msg->report_id == HIDPP_REPORT_ID_SHORT) {
switch (msg->sub_id) {
case HIDPP_SUBID_DEVICE_CONNECTION:
case HIDPP_SUBID_DEVICE_DISCONNECTION:
case HIDPP_SUBID_DEVICE_LOCKING_CHANGED:
g_debug ("device connection event, do something");
break;
case HIDPP_SUBID_LINK_QUALITY:
g_debug ("ignoring link quality message");
break;
case HIDPP_SUBID_ERROR_MSG:
g_debug ("ignoring link quality message");
break;
default:
g_warning ("unknown SubID %02x", msg->sub_id);
break;
}
}
return TRUE;
}
static void
lu_device_runtime_class_init (LuDeviceRuntimeClass *klass)
{
LuDeviceClass *klass_device = LU_DEVICE_CLASS (klass);
klass_device->open = lu_device_runtime_open;
klass_device->poll = lu_device_runtime_poll;
klass_device->detach = lu_device_runtime_detach;
}
......
......@@ -101,7 +101,7 @@ lu_device_kind_to_string (LuDeviceKind kind)
}
static const gchar *
lu_hidpp_feature_to_string (guint feature)
lu_hidpp_feature_to_string (guint16 feature)
{
if (feature == HIDPP_FEATURE_ROOT)
return "Root";
......@@ -118,18 +118,6 @@ lu_hidpp_feature_to_string (guint feature)
return NULL;
}
LuDeviceHidppMsg *
lu_device_hidpp_new (void)
{
return g_new0 (LuDeviceHidppMsg, 1);
}
#define HIDPP_REPORT_NOTIFICATION 0x01
#define HIDPP_REPORT_02 0x02
#define HIDPP_REPORT_03 0x03
#define HIDPP_REPORT_04 0x04
#define HIDPP_REPORT_20 0x20
static gchar *
lu_device_flags_to_string (LuDeviceFlags flags)
{
......@@ -225,7 +213,7 @@ lu_device_hidpp_feature_get_idx (LuDevice *device, guint16 feature)
return 0x00;
}
static guint16
guint16
lu_device_hidpp_feature_find_by_idx (LuDevice *device, guint8 idx)
{
LuDevicePrivate *priv = GET_PRIVATE (device);
......@@ -237,27 +225,6 @@ lu_device_hidpp_feature_find_by_idx (LuDevice *device, guint8 idx)
return 0x0000;
}
static gsize
lu_device_hidpp_msg_length (LuDeviceHidppMsg *msg)
{
if (msg->report_id == HIDPP_REPORT_ID_SHORT)
return 0x07;
if (msg->report_id == HIDPP_REPORT_ID_LONG)
return 0x14;
if (msg->report_id == HIDPP_REPORT_NOTIFICATION)
return 0x08;
if (msg->report_id == HIDPP_REPORT_02)
return 0x08;
if (msg->report_id == HIDPP_REPORT_03)
return 0x05;
if (msg->report_id == HIDPP_REPORT_04)
return 0x02;
if (msg->report_id == HIDPP_REPORT_20)
return 0x0f;
g_warning ("report 0x%02x unknown length", msg->report_id);
return 0x08;
}
static void
lu_device_hidpp_dump (LuDevice *device, const gchar *title, const guint8 *data, gsize len)
{
......@@ -272,21 +239,147 @@ lu_device_hidpp_dump (LuDevice *device, const gchar *title, const guint8 *data,
lu_dump_raw (title_prefixed, data, len);
}
static const gchar *
lu_device_hidpp20_function_to_string (guint16 feature, guint8 function_id)
{
if (feature == HIDPP_FEATURE_ROOT) {
if (function_id == 0x00)
return "getFeature";
if (function_id == 0x01)
return "ping";
return NULL;
}
if (feature == HIDPP_FEATURE_I_FIRMWARE_INFO) {
if (function_id == 0x00)
return "getCount";
if (function_id == 0x01)
return "getInfo";
return NULL;
}
if (feature == HIDPP_FEATURE_BATTERY_LEVEL_STATUS) {
if (function_id == 0x00)
return "GetBatteryLevelStatus";
return NULL;
}
if (feature == HIDPP_FEATURE_DFU_CONTROL) {
if (function_id == 0x00)
return "getDfuControl";
if (function_id == 0x01)
return "setDfuControl";
return NULL;
}
if (feature == HIDPP_FEATURE_DFU_CONTROL_SIGNED) {
if (function_id == 0x00)
return "getDfuStatus";
if (function_id == 0x01)
return "startDfu";
return NULL;
}
if (feature == HIDPP_FEATURE_DFU) {
if (function_id == 0x00)
return "dfuCmdData0";
if (function_id == 0x01)
return "dfuCmdData1";
if (function_id == 0x02)
return "dfuCmdData2";
if (function_id == 0x03)
return "dfuCmdData3";
if (function_id == 0x04)
return "dfuStart";
if (function_id == 0x05)
return "restart";
return NULL;
}
return NULL;
}
static gchar *
lu_device_hidpp_msg_to_string (LuDevice *device, LuHidppMsg *msg)
{
GString *str = g_string_new (NULL);
LuDevicePrivate *priv = GET_PRIVATE (device);
const gchar *tmp;
const gchar *kind_str = lu_device_kind_to_string (priv->kind);
g_autoptr(GError) error = NULL;
g_autoptr(GString) flags_str = g_string_new (NULL);
g_return_val_if_fail (msg != NULL, NULL);
g_string_append_printf (str, "device-kind: %s\n", kind_str);
if (msg->flags == LU_HIDPP_MSG_FLAG_NONE) {
g_string_append (flags_str, "none");
} else {
if (msg->flags & LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT)
g_string_append (flags_str, "longer-timeout,");
if (msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID)
g_string_append (flags_str, "ignore-sub-id,");
if (msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID)
g_string_append (flags_str, "ignore-fnct-id,");
if (msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_SWID)
g_string_append (flags_str, "ignore-swid,");
if (str->len > 0)
g_string_truncate (str, str->len - 1);
}
g_string_append_printf (str, "flags: %02x [%s]\n",
msg->flags,
flags_str->str);
g_string_append_printf (str, "report-id: %02x [%s]\n",
msg->report_id,
lu_hidpp_msg_rpt_id_to_string (msg));
tmp = lu_hidpp_msg_dev_id_to_string (msg);
if (tmp == NULL && msg->device_id == priv->hidpp_id)
tmp = priv->product;
g_string_append_printf (str, "device-id: %02x [%s]\n",
msg->device_id, tmp );
if (priv->hidpp_version >= 2.f) {
guint16 feature = lu_device_hidpp_feature_find_by_idx (device, msg->sub_id);
guint8 sw_id = msg->function_id & 0x0f;
guint8 function_id = (msg->function_id & 0xf0) >> 4;
g_string_append_printf (str, "feature: %04x [%s]\n",
feature,
lu_hidpp_feature_to_string (feature));
g_string_append_printf (str, "function-id: %02x [%s]\n",
function_id,
lu_device_hidpp20_function_to_string (feature, function_id));
g_string_append_printf (str, "sw-id: %02x [%s]\n",
sw_id,
sw_id == LU_HIDPP_MSG_SW_ID ? "fwupd" : "???");
} else {
g_string_append_printf (str, "sub-id: %02x [%s]\n",
msg->sub_id,
lu_hidpp_msg_sub_id_to_string (msg));
g_string_append_printf (str, "function-id: %02x [%s]\n",
msg->function_id,
lu_hidpp_msg_fcn_id_to_string (msg));
}
if (!lu_hidpp_msg_is_error (msg, &error)) {
g_string_append_printf (str, "error: %s\n",
error->message);
}
return g_string_free (str, FALSE);
}
gboolean
lu_device_hidpp_send (LuDevice *device,
LuDeviceHidppMsg *msg,
LuHidppMsg *msg,
guint timeout,
GError **error)
{
LuDevicePrivate *priv = GET_PRIVATE (device);
gsize len = lu_device_hidpp_msg_length (msg);
gsize len = lu_hidpp_msg_get_payload_length (msg);
/* only for HID++2.0 */
if (lu_device_get_hidpp_version (device) >= 2.f)
msg->function_id |= FU_DEVICE_UNIFYING_SW_ID;
msg->function_id |= LU_HIDPP_MSG_SW_ID;
lu_device_hidpp_dump (device, "host->device", (guint8 *) msg, len);
/* detailed debugging */
if (g_getenv ("UNIFYING_HW_DEBUG") != NULL) {
g_autofree gchar *str = lu_device_hidpp_msg_to_string (device, msg);
g_print ("%s", str);
}