static inline bool ratbag_sanity_check_device(struct ratbag_device *device) { struct ratbag *ratbag = device->ratbag; struct ratbag_profile *profile = NULL; bool has_active = false; unsigned int nres; bool rc = false; /* arbitrary number: max 16 profiles, does any mouse have more? but * since we have num_profiles unsigned, it also checks for * accidental negative */ if (device->num_profiles == 0 || device->num_profiles > 16) { log_bug_libratbag(ratbag, "%s: invalid number of profiles (%d)\n", device->name, device->num_profiles); goto out; } ratbag_device_for_each_profile(device, profile) { struct ratbag_resolution *resolution; /* Allow max 1 active profile */ if (profile->is_active) { if (has_active) { log_bug_libratbag(ratbag, "%s: multiple active profiles\n", device->name); goto out; } has_active = true; } nres = ratbag_profile_get_num_resolutions(profile); if (nres == 0 || nres > 16) { log_bug_libratbag(ratbag, "%s: invalid number of resolutions (%d)\n", device->name, nres); goto out; } ratbag_profile_for_each_resolution(profile, resolution) { unsigned int vals[300]; unsigned int nvals = ARRAY_LENGTH(vals); if (!ratbag_device_has_capability(device, RATBAG_DEVICE_CAP_RESOLUTION)) break; nvals = ratbag_resolution_get_dpi_list(resolution, vals, nvals); if (nvals == 0) { log_bug_libratbag(ratbag, "%s: invalid dpi list\n", device->name); goto out; } nvals = ratbag_resolution_get_report_rate_list(resolution, vals, nvals); if (nvals == 0) { log_bug_libratbag(ratbag, "%s: invalid report rate list\n", device->name); goto out; } } }
static int hidpp20_request_command_allow_error(struct ratbag_device *device, union hidpp20_message *msg, bool allow_error) { struct ratbag *ratbag = device->ratbag; union hidpp20_message read_buffer; int ret; uint8_t hidpp_err = 0; size_t msg_len; /* msg->address is 4 MSB: subcommand, 4 LSB: 4-bit SW identifier so * the device knows who to respond to. kernel uses 0x1 */ const int DEVICE_SW_ID = 0x8; if (msg->msg.address & 0xf) { log_bug_libratbag(ratbag, "hidpp20 error: sw address is already set\n"); return -EINVAL; } msg->msg.address |= DEVICE_SW_ID; msg_len = msg->msg.report_id == REPORT_ID_SHORT ? SHORT_MESSAGE_LENGTH : LONG_MESSAGE_LENGTH; log_buf_raw(ratbag, "sending: ", msg->data, msg_len); /* Send the message to the Device */ ret = hidpp20_write_command(device, msg->data, msg_len); if (ret) goto out_err; /* * Now read the answers from the device: * loop until we get the actual answer or an error code. */ do { ret = ratbag_hidraw_read_input_report(device, read_buffer.data, LONG_MESSAGE_LENGTH); /* Wait and retry if the USB timed out */ if (ret == -ETIMEDOUT) { msleep(10); ret = ratbag_hidraw_read_input_report(device, read_buffer.data, LONG_MESSAGE_LENGTH); } log_buf_raw(ratbag, " *** received: ", read_buffer.data, ret > 0 ? ret : 0); if (read_buffer.msg.report_id != REPORT_ID_SHORT && read_buffer.msg.report_id != REPORT_ID_LONG) continue; /* actual answer */ if (read_buffer.msg.sub_id == msg->msg.sub_id && read_buffer.msg.address == msg->msg.address) break; /* error */ if ((read_buffer.msg.sub_id == __ERROR_MSG || read_buffer.msg.sub_id == 0xff) && read_buffer.msg.address == msg->msg.sub_id && read_buffer.msg.parameters[0] == msg->msg.address) { hidpp_err = read_buffer.msg.parameters[1]; if (allow_error) log_debug(ratbag, " HID++ error from the device (%d): %s (%02x)\n", read_buffer.msg.device_idx, hidpp_errors[hidpp_err] ? hidpp_errors[hidpp_err] : "Undocumented error code", hidpp_err); else log_error(ratbag, " HID++ error from the device (%d): %s (%02x)\n", read_buffer.msg.device_idx, hidpp_errors[hidpp_err] ? hidpp_errors[hidpp_err] : "Undocumented error code", hidpp_err); break; } } while (ret > 0); if (ret < 0) { log_error(ratbag, " USB error: %s (%d)\n", strerror(-ret), -ret); perror("write"); goto out_err; } if (!hidpp_err) { /* copy the answer for the caller */ *msg = read_buffer; } ret = hidpp_err; out_err: return ret; }