From 77fa6a1e65dd274283df9606fc488fc293384c6f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 12 Sep 2017 10:08:35 +0200 Subject: [PATCH] hidpp20: fill in all profiles, even if they are not there If a profile is either wrong or not there, we rely on the ROM to get a correct profile. Fixes #280 Signed-off-by: Benjamin Tissoires --- src/hidpp20.c | 67 ++++++++++++++++++++++++++++++++++++++------------- src/hidpp20.h | 2 +- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/hidpp20.c b/src/hidpp20.c index ee808f48..388d01c3 100644 --- a/src/hidpp20.c +++ b/src/hidpp20.c @@ -1907,7 +1907,7 @@ hidpp20_onboard_profiles_parse_profile(struct hidpp20_device *device, { union hidpp20_internal_profile *pdata; struct hidpp20_profile *profile = &profiles_list->profiles[index]; - uint16_t sector = index + 1; + uint16_t sector = profile->address; _cleanup_free_ uint8_t *data = NULL; unsigned i; int rc; @@ -1970,9 +1970,10 @@ hidpp20_onboard_profiles_parse(struct hidpp20_device *device, _cleanup_free_ uint8_t *data = NULL; int rc; unsigned i; + bool crc_valid; for (i = 0; i < profiles->num_profiles; i++) { - profiles->profiles[i].index = 0; + profiles->profiles[i].address = 0; profiles->profiles[i].enabled = 0; } @@ -1985,30 +1986,62 @@ hidpp20_onboard_profiles_parse(struct hidpp20_device *device, if (rc < 0) return rc; - if (check_crc) { - if (!hidpp20_onboard_profiles_is_sector_valid(device, - profiles->sector_size, - data)) { - return -EAGAIN; + crc_valid = hidpp20_onboard_profiles_is_sector_valid(device, + profiles->sector_size, + data); + if (crc_valid || !check_crc) { + for (i = 0; i < profiles->num_profiles; i++) { + uint8_t *d = data + 4 * i; + + if (d[0] == 0xFF && d[1] == 0xFF) + break; + + profiles->profiles[i].address = hidpp_get_unaligned_be_u16(d); + if (profiles->profiles[i].address != (dict_address | (i + 1))) + hidpp_log_info(&device->base, + "profile %d: error in the address: 0x%04x instead of 0x%04x\n", + i + 1, + profiles->profiles[i].address, + dict_address | (i + 1)); + profiles->profiles[i].enabled = !!d[2]; } } - for (i = 0; i < profiles->num_profiles; i++) { - uint8_t *d = data + 4 * i; - - if (d[0] == 0xFF && d[1] == 0xFF) - break; - - profiles->profiles[i].index = d[1]; - profiles->profiles[i].enabled = !!d[2]; + /* + * Even if the crc is wrong, we still fetch all the profiles, so as + * to have the current stored values if some profiles are legitimate. + */ + for (i = 0; i < profiles->num_profiles; i++) { + if (profiles->profiles[i].address == 0x0000) { + switch (dict_address) { + case 0x0000: + profiles->profiles[i].address = i + 1; + break; + case 0x0100: + if (i >= profiles->num_rom_profiles) { + profiles->profiles[i].address = dict_address | profiles->num_rom_profiles; + } else { + profiles->profiles[i].address = dict_address | (i + 1); + } + break; + default: + hidpp_log_error(&device->base, + "this should never happen: dict address is 0x%04x\n", + dict_address); + return -EINVAL; + } + } rc = hidpp20_onboard_profiles_parse_profile(device, profiles, i, check_crc); - if (rc < 0) - return rc; + if (rc == -EAGAIN) + crc_valid = false; } + if (check_crc && !crc_valid) + return -EAGAIN; + return 0; } diff --git a/src/hidpp20.h b/src/hidpp20.h index d57a24b7..db816ede 100644 --- a/src/hidpp20.h +++ b/src/hidpp20.h @@ -467,7 +467,7 @@ union hidpp20_macro_data { _Static_assert(sizeof(union hidpp20_macro_data) == 3, "Invalid size"); struct hidpp20_profile { - uint8_t index; + uint16_t address; uint8_t enabled; char name[16 * 3]; unsigned report_rate;