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 <benjamin.tissoires@gmail.com>
This commit is contained in:
Benjamin Tissoires
2017-09-12 10:08:35 +02:00
parent 0f8031c201
commit 77fa6a1e65
2 changed files with 51 additions and 18 deletions

View File

@@ -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;
}

View File

@@ -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;