mirror of
https://git.proxmox.com/git/fwupd
synced 2025-07-27 09:46:25 +00:00
logitech-bulkcontroller: Explicitly set to device mode
Explicitly set to device mode when required.
This commit is contained in:
parent
49c08f436f
commit
baf4279f70
@ -31,11 +31,10 @@ proto_manager_generate_get_device_info_request(void)
|
||||
Logi__Device__Proto__Header header_msg = LOGI__DEVICE__PROTO__HEADER__INIT;
|
||||
Logi__Device__Proto__GetDeviceInfoRequest get_deviceinfo_msg =
|
||||
LOGI__DEVICE__PROTO__GET_DEVICE_INFO_REQUEST__INIT;
|
||||
Logi__Device__Proto__Request request_msg = {
|
||||
PROTOBUF_C_MESSAGE_INIT(&logi__device__proto__request__descriptor),
|
||||
LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_GET_DEVICE_INFO_REQUEST,
|
||||
{&get_deviceinfo_msg}};
|
||||
Logi__Device__Proto__UsbMsg usb_msg = LOGI__DEVICE__PROTO__USB_MSG__INIT;
|
||||
Logi__Device__Proto__Request request_msg = LOGI__DEVICE__PROTO__REQUEST__INIT;
|
||||
request_msg.payload_case = LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_GET_DEVICE_INFO_REQUEST;
|
||||
request_msg.get_device_info_request = &get_deviceinfo_msg;
|
||||
|
||||
proto_manager_set_header(&header_msg);
|
||||
usb_msg.header = &header_msg;
|
||||
@ -54,11 +53,11 @@ proto_manager_generate_transition_to_device_mode_request(void)
|
||||
Logi__Device__Proto__Header header_msg = LOGI__DEVICE__PROTO__HEADER__INIT;
|
||||
Logi__Device__Proto__TransitionToDeviceModeRequest transition_to_device_mode_msg =
|
||||
LOGI__DEVICE__PROTO__TRANSITION_TO_DEVICE_MODE_REQUEST__INIT;
|
||||
Logi__Device__Proto__Request request_msg = {
|
||||
PROTOBUF_C_MESSAGE_INIT(&logi__device__proto__request__descriptor),
|
||||
LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_TRANSITION_TO_DEVICEMODE_REQUEST,
|
||||
{(Logi__Device__Proto__GetDeviceInfoRequest *)&transition_to_device_mode_msg}};
|
||||
Logi__Device__Proto__UsbMsg usb_msg = LOGI__DEVICE__PROTO__USB_MSG__INIT;
|
||||
Logi__Device__Proto__Request request_msg = LOGI__DEVICE__PROTO__REQUEST__INIT;
|
||||
request_msg.payload_case =
|
||||
LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_TRANSITION_TO_DEVICEMODE_REQUEST;
|
||||
request_msg.transition_to_devicemode_request = &transition_to_device_mode_msg;
|
||||
|
||||
proto_manager_set_header(&header_msg);
|
||||
usb_msg.header = &header_msg;
|
||||
@ -77,7 +76,8 @@ proto_manager_decode_message(const guint8 *data,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GByteArray) buf_decoded = g_byte_array_new();
|
||||
|
||||
guint32 success = 0;
|
||||
guint32 error_code = 0;
|
||||
Logi__Device__Proto__UsbMsg *usb_msg =
|
||||
logi__device__proto__usb_msg__unpack(NULL, len, (const unsigned char *)data);
|
||||
if (usb_msg == NULL) {
|
||||
@ -115,9 +115,16 @@ proto_manager_decode_message(const guint8 *data,
|
||||
case LOGI__DEVICE__PROTO__RESPONSE__PAYLOAD_TRANSITION_TO_DEVICEMODE_RESPONSE:
|
||||
if (usb_msg->response->transition_to_devicemode_response) {
|
||||
*proto_id = kProtoId_TransitionToDeviceModeResponse;
|
||||
fu_byte_array_append_uint8(
|
||||
buf_decoded,
|
||||
usb_msg->response->transition_to_devicemode_response->success);
|
||||
success =
|
||||
usb_msg->response->transition_to_devicemode_response->success
|
||||
? 1
|
||||
: 0;
|
||||
error_code =
|
||||
usb_msg->response->transition_to_devicemode_response->error;
|
||||
fu_byte_array_append_uint32(buf_decoded, success, G_LITTLE_ENDIAN);
|
||||
fu_byte_array_append_uint32(buf_decoded,
|
||||
error_code,
|
||||
G_LITTLE_ENDIAN);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -234,7 +234,7 @@ fu_logitech_bulkcontroller_device_send_upd_cmd(FuLogitechBulkcontrollerDevice *s
|
||||
/* receiving INIT ACK */
|
||||
fu_byte_array_set_size(buf_ack, MAX_DATA_SIZE);
|
||||
|
||||
/* Extending the bulk transfer timeout value, as android device takes some time to
|
||||
/* extending the bulk transfer timeout value, as android device takes some time to
|
||||
calculate Hash and respond */
|
||||
if (CMD_END_TRANSFER == cmd)
|
||||
timeout = HASH_TIMEOUT;
|
||||
@ -423,6 +423,148 @@ fu_logitech_bulkcontroller_device_compute_hash(GBytes *data)
|
||||
return g_base64_encode(md5buf, sizeof(md5buf));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_logitech_bulkcontroller_device_json_parser(FuDevice *device,
|
||||
GByteArray *decoded_pkt,
|
||||
GError **error)
|
||||
{
|
||||
FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device);
|
||||
JsonArray *json_devices;
|
||||
JsonNode *json_root;
|
||||
JsonObject *json_device;
|
||||
JsonObject *json_object;
|
||||
JsonObject *json_payload;
|
||||
g_autoptr(JsonParser) json_parser = json_parser_new();
|
||||
|
||||
/* parse JSON reply */
|
||||
if (!json_parser_load_from_data(json_parser,
|
||||
(const gchar *)decoded_pkt->data,
|
||||
decoded_pkt->len,
|
||||
error)) {
|
||||
g_prefix_error(error, "failed to parse json data: ");
|
||||
return FALSE;
|
||||
}
|
||||
json_root = json_parser_get_root(json_parser);
|
||||
if (json_root == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON root");
|
||||
return FALSE;
|
||||
}
|
||||
json_object = json_node_get_object(json_root);
|
||||
json_payload = json_object_get_object_member(json_object, "payload");
|
||||
if (json_payload == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON payload");
|
||||
return FALSE;
|
||||
}
|
||||
json_devices = json_object_get_array_member(json_payload, "devices");
|
||||
if (json_devices == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON devices");
|
||||
return FALSE;
|
||||
}
|
||||
json_device = json_array_get_object_element(json_devices, 0);
|
||||
if (json_device == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON device");
|
||||
return FALSE;
|
||||
}
|
||||
if (json_object_has_member(json_device, "name"))
|
||||
fu_device_set_name(device, json_object_get_string_member(json_device, "name"));
|
||||
if (json_object_has_member(json_device, "sw"))
|
||||
fu_device_set_version(device, json_object_get_string_member(json_device, "sw"));
|
||||
if (json_object_has_member(json_device, "type"))
|
||||
fu_device_add_instance_id(device,
|
||||
json_object_get_string_member(json_device, "type"));
|
||||
if (json_object_has_member(json_device, "status"))
|
||||
self->status = json_object_get_int_member(json_device, "status");
|
||||
if (json_object_has_member(json_device, "updateStatus"))
|
||||
self->update_status = json_object_get_int_member(json_device, "updateStatus");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_logitech_bulkcontroller_device_get_data(FuDevice *device, GError **error)
|
||||
{
|
||||
FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device);
|
||||
g_autoptr(GByteArray) device_request = g_byte_array_new();
|
||||
g_autoptr(GByteArray) decoded_pkt = g_byte_array_new();
|
||||
g_autoptr(GByteArray) device_response = g_byte_array_new();
|
||||
FuLogitechBulkcontrollerProtoId proto_id = kProtoId_UnknownId;
|
||||
|
||||
/* sending GetDeviceInfoRequest. Device reports quite a few matrix, including status,
|
||||
* progress etc */
|
||||
device_request = proto_manager_generate_get_device_info_request();
|
||||
if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self,
|
||||
CMD_BUFFER_WRITE,
|
||||
device_request,
|
||||
error)) {
|
||||
g_prefix_error(error,
|
||||
"failed to send write buffer packet for device info request: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* wait for the GetDeviceInfoResponse */
|
||||
if (!fu_logitech_bulkcontroller_device_recv_sync_cmd(self,
|
||||
CMD_BUFFER_READ,
|
||||
device_response,
|
||||
error)) {
|
||||
g_prefix_error(error, "failed to read buffer packet for device info request: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_logitech_bulkcontroller_device_recv_sync_cmd(self,
|
||||
CMD_UNINIT_BUFFER,
|
||||
NULL,
|
||||
error)) {
|
||||
g_prefix_error(error,
|
||||
"failed to read uninit buffer packet for device info request: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self,
|
||||
CMD_UNINIT_BUFFER,
|
||||
NULL,
|
||||
error)) {
|
||||
g_prefix_error(
|
||||
error,
|
||||
"failed to send buffer uninitialize packet for device info request: ");
|
||||
return FALSE;
|
||||
}
|
||||
decoded_pkt = proto_manager_decode_message(device_response->data,
|
||||
device_response->len,
|
||||
&proto_id,
|
||||
error);
|
||||
if (decoded_pkt == NULL) {
|
||||
g_prefix_error(error, "failed to unpack packet for device info request: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (g_getenv("FWUPD_LOGITECH_BULKCONTROLLER_VERBOSE") != NULL) {
|
||||
g_autofree gchar *strsafe =
|
||||
fu_common_strsafe((const gchar *)decoded_pkt->data, decoded_pkt->len);
|
||||
g_debug("Received device response: %s", strsafe);
|
||||
}
|
||||
if (proto_id != kProtoId_GetDeviceInfoResponse) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"incorrect response for device info request");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_logitech_bulkcontroller_device_json_parser(device, decoded_pkt, error))
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device,
|
||||
FuFirmware *firmware,
|
||||
@ -449,9 +591,9 @@ fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device,
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Sending INIT */
|
||||
/* sending INIT */
|
||||
if (!fu_logitech_bulkcontroller_device_send_upd_cmd(self, CMD_INIT, NULL, error)) {
|
||||
g_prefix_error(error, "error in writing init transfer packet: ");
|
||||
g_prefix_error(error, "failed to write init transfer packet: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -461,7 +603,7 @@ fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device,
|
||||
CMD_START_TRANSFER,
|
||||
start_pkt,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in writing start transfer packet: ");
|
||||
g_prefix_error(error, "failed to write start transfer packet: ");
|
||||
return FALSE;
|
||||
}
|
||||
fu_progress_step_done(progress);
|
||||
@ -495,13 +637,13 @@ fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device,
|
||||
CMD_END_TRANSFER,
|
||||
end_pkt,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in writing end transfer transfer packet: ");
|
||||
g_prefix_error(error, "failed to write end transfer transfer packet: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* send uninit */
|
||||
if (!fu_logitech_bulkcontroller_device_send_upd_cmd(self, CMD_UNINIT, NULL, error)) {
|
||||
g_prefix_error(error, "error in writing finish transfer packet: ");
|
||||
g_prefix_error(error, "failed to write finish transfer packet: ");
|
||||
return FALSE;
|
||||
}
|
||||
fu_progress_step_done(progress);
|
||||
@ -566,104 +708,43 @@ fu_logitech_bulkcontroller_device_close(FuDevice *device, GError **error)
|
||||
->close(device, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_logitech_bulkcontroller_device_json_parser(FuDevice *device,
|
||||
GByteArray *decoded_pkt,
|
||||
GError **error)
|
||||
{
|
||||
FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device);
|
||||
JsonArray *json_devices;
|
||||
JsonNode *json_root;
|
||||
JsonObject *json_device;
|
||||
JsonObject *json_object;
|
||||
JsonObject *json_payload;
|
||||
g_autoptr(JsonParser) json_parser = json_parser_new();
|
||||
|
||||
/* parse JSON reply */
|
||||
if (!json_parser_load_from_data(json_parser,
|
||||
(const gchar *)decoded_pkt->data,
|
||||
decoded_pkt->len,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in parsing json data: ");
|
||||
return FALSE;
|
||||
}
|
||||
json_root = json_parser_get_root(json_parser);
|
||||
if (json_root == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON root");
|
||||
return FALSE;
|
||||
}
|
||||
json_object = json_node_get_object(json_root);
|
||||
json_payload = json_object_get_object_member(json_object, "payload");
|
||||
if (json_payload == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON payload");
|
||||
return FALSE;
|
||||
}
|
||||
json_devices = json_object_get_array_member(json_payload, "devices");
|
||||
if (json_devices == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON devices");
|
||||
return FALSE;
|
||||
}
|
||||
json_device = json_array_get_object_element(json_devices, 0);
|
||||
if (json_device == NULL) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get JSON device");
|
||||
return FALSE;
|
||||
}
|
||||
if (json_object_has_member(json_device, "name"))
|
||||
fu_device_set_name(device, json_object_get_string_member(json_device, "name"));
|
||||
if (json_object_has_member(json_device, "sw"))
|
||||
fu_device_set_version(device, json_object_get_string_member(json_device, "sw"));
|
||||
if (json_object_has_member(json_device, "type"))
|
||||
fu_device_add_instance_id(device,
|
||||
json_object_get_string_member(json_device, "type"));
|
||||
if (json_object_has_member(json_device, "status"))
|
||||
self->status = json_object_get_int_member(json_device, "status");
|
||||
if (json_object_has_member(json_device, "updateStatus"))
|
||||
self->update_status = json_object_get_int_member(json_device, "updateStatus");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_logitech_bulkcontroller_device_setup(FuDevice *device, GError **error)
|
||||
{
|
||||
FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device);
|
||||
g_autoptr(GByteArray) device_info_request = g_byte_array_new();
|
||||
g_autoptr(GByteArray) device_request = g_byte_array_new();
|
||||
g_autoptr(GByteArray) decoded_pkt = g_byte_array_new();
|
||||
g_autoptr(GByteArray) device_info_response = g_byte_array_new();
|
||||
g_autoptr(GByteArray) device_response = g_byte_array_new();
|
||||
FuLogitechBulkcontrollerProtoId proto_id = kProtoId_UnknownId;
|
||||
guint32 success = 0;
|
||||
guint32 error_code = 0;
|
||||
|
||||
/* FuUsbDevice->setup */
|
||||
if (!FU_DEVICE_CLASS(fu_logitech_bulkcontroller_device_parent_class)->setup(device, error))
|
||||
return FALSE;
|
||||
|
||||
/* sending GetDeviceInfoRequest */
|
||||
device_info_request = proto_manager_generate_get_device_info_request();
|
||||
/*
|
||||
* device supports USB_Device mode, Appliance mode and BYOD mode.
|
||||
* Only USB_Device mode is supported here.
|
||||
* Ensure it is running in USB_Device mode
|
||||
* Response has two data: Request succeeded or failed, and error code in case of failure
|
||||
*/
|
||||
device_request = proto_manager_generate_transition_to_device_mode_request();
|
||||
if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self,
|
||||
CMD_BUFFER_WRITE,
|
||||
device_info_request,
|
||||
device_request,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in sending buffer write packet: ");
|
||||
g_prefix_error(error,
|
||||
"failed to send buffer write packet for transition mode request: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* wait for the GetDeviceInfoResponse */
|
||||
/* wait for the TransitionToDeviceModeResponse */
|
||||
if (!fu_logitech_bulkcontroller_device_recv_sync_cmd(self,
|
||||
CMD_BUFFER_READ,
|
||||
device_info_response,
|
||||
device_response,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in buffer read packet: ");
|
||||
g_prefix_error(error, "failed to read buffer packet for transition mode request: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -671,32 +752,63 @@ fu_logitech_bulkcontroller_device_setup(FuDevice *device, GError **error)
|
||||
CMD_UNINIT_BUFFER,
|
||||
NULL,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in buffer read packet: ");
|
||||
g_prefix_error(error,
|
||||
"failed to read uninit buffer packet for transition mode request: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self,
|
||||
CMD_UNINIT_BUFFER,
|
||||
NULL,
|
||||
error)) {
|
||||
g_prefix_error(error, "error in sending buffer uninitialize packet: ");
|
||||
g_prefix_error(
|
||||
error,
|
||||
"failed to send buffer uninitialize packet for transition mode request: ");
|
||||
return FALSE;
|
||||
}
|
||||
decoded_pkt = proto_manager_decode_message(device_info_response->data,
|
||||
device_info_response->len,
|
||||
decoded_pkt = proto_manager_decode_message(device_response->data,
|
||||
device_response->len,
|
||||
&proto_id,
|
||||
error);
|
||||
if (decoded_pkt == NULL) {
|
||||
g_prefix_error(error, "error in unpacking packet: ");
|
||||
g_prefix_error(error, "failed to unpack packet for transition mode request: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (proto_id != kProtoId_GetDeviceInfoResponse) {
|
||||
if (proto_id != kProtoId_TransitionToDeviceModeResponse) {
|
||||
g_set_error_literal(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"did not get kProtoId_GetDeviceInfoResponse");
|
||||
"incorrect response for transition mode request");
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_logitech_bulkcontroller_device_json_parser(device, decoded_pkt, error))
|
||||
if (!fu_common_read_uint32_safe(decoded_pkt->data,
|
||||
decoded_pkt->len,
|
||||
COMMAND_OFFSET,
|
||||
&success,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
if (!fu_common_read_uint32_safe(decoded_pkt->data,
|
||||
decoded_pkt->len,
|
||||
LENGTH_OFFSET,
|
||||
&error_code,
|
||||
G_LITTLE_ENDIAN,
|
||||
error))
|
||||
return FALSE;
|
||||
if (g_getenv("FWUPD_LOGITECH_BULKCONTROLLER_VERBOSE") != NULL)
|
||||
g_debug("Received transition mode response. Success: %u, Error: %u",
|
||||
success,
|
||||
error_code);
|
||||
if (!success) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"transition mode request failed. error: %u",
|
||||
error_code);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* load current device data */
|
||||
if (!fu_logitech_bulkcontroller_device_get_data(device, error))
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
|
Loading…
Reference in New Issue
Block a user