示例#1
0
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;
			}
		}
	}
示例#2
0
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;
}