Пример #1
0
int
hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
{
	struct ratbag_device *device = dev->ratbag_device;
	struct ratbag *ratbag = device->ratbag;
	union hidpp10_message read_buffer;
	union hidpp10_message expected_header;
	union hidpp10_message expected_error_dev = ERROR_MSG(msg, msg->msg.device_idx);
	int ret;
	uint8_t hidpp_err = 0;

	/* create the expected header */
	expected_header = *msg;
	switch (msg->msg.sub_id) {
	case SET_REGISTER_REQ:
		expected_header.msg.report_id = REPORT_ID_SHORT;
		break;
	case GET_REGISTER_REQ:
		expected_header.msg.report_id = REPORT_ID_SHORT;
		break;
	case SET_LONG_REGISTER_REQ:
		expected_header.msg.report_id = REPORT_ID_LONG;
		break;
	case GET_LONG_REGISTER_REQ:
		expected_header.msg.report_id = REPORT_ID_LONG;
		break;
	}

	log_buf_raw(ratbag, "sending: ", msg->data, SHORT_MESSAGE_LENGTH);
	log_buf_raw(ratbag, "  expected_header:	", expected_header.data, SHORT_MESSAGE_LENGTH);
	log_buf_raw(ratbag, "  expected_error_dev:	", expected_error_dev.data, SHORT_MESSAGE_LENGTH);

	/* Send the message to the Device */
	ret = hidpp10_write_command(dev, msg->data, SHORT_MESSAGE_LENGTH);
	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);

		/* Overwrite the return device index with ours. The kernel
		 * sets our device index on write, but gives us the real
		 * device index on reply. Overwrite it with our index so the
		 * messages are easier to check and compare.
		 */
		read_buffer.msg.device_idx = msg->msg.device_idx;

		log_buf_raw(ratbag, " *** received: ", read_buffer.data, ret);


		/* actual answer */
		if (!memcmp(read_buffer.data, expected_header.data, 4))
			break;

		/* error */
		if (!memcmp(read_buffer.data, expected_error_dev.data, 5)) {
			hidpp_err = read_buffer.msg.parameters[1];
			log_raw(ratbag,
				"    HID++ error from the %s (%d): %s (%02x)\n",
				read_buffer.msg.device_idx == RECEIVER_IDX ? "receiver" : "device",
				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) {
		log_buf_raw(ratbag, "    received: ", read_buffer.data, ret);
		/* copy the answer for the caller */
		*msg = read_buffer;
	}

	ret = hidpp_err;

out_err:
	return ret;
}
Пример #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;
}
Пример #3
0
int
hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_profile *profile_return)
{
	struct ratbag *ratbag = dev->ratbag_device->ratbag;
	union _hidpp10_profile_data data;
	struct _hidpp10_profile *p = &data.profile;
	size_t i;
	int res;
	struct hidpp10_profile profile;

	/* FIXME: profile offset appears to be 3, 1 and 2 are garbage */
	number += 3;

	log_raw(dev->ratbag_device->ratbag, "Fetching profile %d\n", number);

	for (i = 0; i < sizeof(data); i += 16) {
		res = hidpp10_read_memory(dev, number, i,  &data.data[i]);
		if (res)
			return res;
	}

	profile.angle_correction = p->angle_correction;
	profile.default_dpi_mode = p->default_dpi_mode;
	profile.refresh_rate = p->usb_refresh_rate ? 1000/p->usb_refresh_rate : 0;

	profile.num_dpi_modes = PROFILE_NUM_DPI_MODES;
	for (i = 0; i < PROFILE_NUM_DPI_MODES; i++) {
		uint8_t *be; /* in big endian */
		struct _hidpp10_dpi_mode *dpi = &p->dpi_modes[i];

		be = (uint8_t*)&dpi->xres;
		profile.dpi_modes[i].xres = hidpp10_get_unaligned_u16(be) * 50;
		be = (uint8_t*)&dpi->yres;
		profile.dpi_modes[i].yres = hidpp10_get_unaligned_u16(be) * 50;

		profile.dpi_modes[i].led[0] = dpi->led1 == 0x2;
		profile.dpi_modes[i].led[1] = dpi->led2 == 0x2;
		profile.dpi_modes[i].led[2] = dpi->led3 == 0x2;
		profile.dpi_modes[i].led[3] = dpi->led4 == 0x2;
	}

	profile.num_buttons = PROFILE_NUM_BUTTONS;
	for (i = 0; i < PROFILE_NUM_BUTTONS; i++) {
		union _hidpp10_button_binding *b = &p->buttons[i];
		union hidpp10_button *button = &profile.buttons[i];

		button->any.type = b->any.type;

		switch (b->any.type) {
		case PROFILE_BUTTON_TYPE_BUTTON:
			button->button.button =
				ffs(hidpp10_get_unaligned_u16le(&b->button.button_flags_lsb));
			break;
		case PROFILE_BUTTON_TYPE_KEYS:
			button->keys.modifier_flags = b->keyboard_keys.modifier_flags;
			button->keys.key = b->keyboard_keys.key;
			break;
		case PROFILE_BUTTON_TYPE_SPECIAL:
			button->special.special = ffs(hidpp10_get_unaligned_u16le(&b->special.flags1));
			break;
		case PROFILE_BUTTON_TYPE_CONSUMER_CONTROL:
			button->consumer_control.consumer_control =
				  hidpp10_get_unaligned_u16(&b->consumer_control.consumer_control1);
			break;
		case PROFILE_BUTTON_TYPE_DISABLED:
			break;
		}

	}

	log_buf_raw(ratbag,
		    "+++++++++++++++++++ Profile data: +++++++++++++++++ \n",
		    data.data, 78);

	log_raw(ratbag, "Profile %d:\n", number);
	for (i = 0; i < 5; i++) {
		log_raw(ratbag,
			"DPI mode: %dx%d dpi\n",
			profile.dpi_modes[i].xres,
			profile.dpi_modes[i].yres);
	        log_raw(ratbag,
			"LED status: 1:%s 2:%s 3:%s 4:%s\n",
			(p->dpi_modes[i].led1 & 0x2) ? "on" : "off",
			(p->dpi_modes[i].led2 & 0x2) ? "on" : "off",
			(p->dpi_modes[i].led3 & 0x2) ? "on" : "off",
			(p->dpi_modes[i].led4 & 0x2) ? "on" : "off");
	}
	log_raw(ratbag, "Angle correction: %d\n", profile.angle_correction);
	log_raw(ratbag, "Default DPI mode: %d\n", profile.default_dpi_mode);
	log_raw(ratbag, "Refresh rate: %d\n", profile.refresh_rate);
	for (i = 0; i < 13; i++) {
		union _hidpp10_button_binding *button = &p->buttons[i];
		switch (button->any.type) {
		case 0x81:
			log_raw(ratbag,
				"Button %d: button %d\n",
				i,
				ffs(hidpp10_get_unaligned_u16le(&button->button.button_flags_lsb)));
			break;
		case 0x82:
			log_raw(ratbag,
				"Button %d: key %d modifier %x\n",
				i,
				button->keyboard_keys.key,
				button->keyboard_keys.modifier_flags);
			break;
		case 0x83:
			log_raw(ratbag,
				"Button %d: special %x\n",
				i,
				ffs(hidpp10_get_unaligned_u16le(&button->special.flags1)));
			break;
		case 0x84:
			log_raw(ratbag,
				"Button %d: consumer: %x\n",
				i,
				hidpp10_get_unaligned_u16(&button->consumer_control.consumer_control1));
			break;
		case 0x8F:
			log_raw(ratbag, "Button %d: disabled\n", i);
			break;
		default:
			/* FIXME: this is the page number for the macro,
			 * followed by a 1-byte offset */
			break ;
		}
	}

	*profile_return = profile;

	return 0;
}