예제 #1
0
파일: hidpp10.c 프로젝트: ogay/uLogitech
int hidpp10_request_command(int fd, union hidpp10_message *msg) {
	union hidpp10_message read_buffer;
	union hidpp10_message expected_header;
	union hidpp10_message expected_error_recv = ERROR_MSG(msg, RECEIVER_IDX);
	union hidpp10_message expected_error_dev = ERROR_MSG(msg, msg->msg.device_idx);
	int ret;
	__u8 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;
	}

	pr_dbg("sending: "); pr_buffer(msg->data, SHORT_MESSAGE_LENGTH);
#if DEBUG_LVL > 1
	pr_dbg("  expected_header:	"); pr_buffer(expected_header.data, SHORT_MESSAGE_LENGTH);
	pr_dbg("  expected_error_recv:	"); pr_buffer(expected_error_recv.data, SHORT_MESSAGE_LENGTH);
	pr_dbg("  expected_error_dev:	"); pr_buffer(expected_error_dev.data, SHORT_MESSAGE_LENGTH);
#endif

	/* Send the message to the Device */
	ret = hidpp10_write_command(fd, 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 = read(fd, read_buffer.data, LONG_MESSAGE_LENGTH);
#if DEBUG_LVL > 2
		printf(" *** received: "); pr_buffer(read_buffer.data, ret);
#endif
		/* actual answer */
		if (!memcmp(read_buffer.data, expected_header.data, 4))
			break;

		/* error */
		if (!memcmp(read_buffer.data, expected_error_recv.data, 5) ||
		    !memcmp(read_buffer.data, expected_error_dev.data, 5)) {
			hidpp_err = read_buffer.msg.parameters[1];
			pr_dbg("    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) {
		printf("    USB error: %d\n", errno);
		perror("write");
		goto out_err;
	}

	if (!hidpp_err) {
		pr_dbg("    received: "); pr_buffer(read_buffer.data, ret);
		/* copy the answer for the caller */
		*msg = read_buffer;
	}

	ret = hidpp_err;

out_err:
	return ret;
}
예제 #2
0
static void usb_rx_complete(struct urb *urb)
{
	struct if_usb_devdata *pipe_data = urb->context;
	struct usb_link_device *usb_ld = usb_get_intfdata(pipe_data->data_intf);
	struct io_device *iod;
	int iod_format = IPC_FMT;
	int ret;

	usb_mark_last_busy(urb->dev);

	switch (urb->status) {
	case 0:
	case -ENOENT:
		if (!urb->actual_length)
			goto re_submit;
		/* call iod recv */
		/* how we can distinguish boot ch with fmt ch ?? */
		switch (pipe_data->format) {
		case IF_USB_FMT_EP:
			iod_format = IPC_FMT;
			pr_buffer("rx", (char *)urb->transfer_buffer,
					(size_t)urb->actual_length, 16);
			break;
		case IF_USB_RAW_EP:
			iod_format = IPC_MULTI_RAW;
			break;
		case IF_USB_RFS_EP:
			iod_format = IPC_RFS;
			break;
		default:
			break;
		}

		/* during boot stage fmt end point */
		/* shared with boot io device */
		/* when we use fmt device only, at boot and ipc exchange
			it can be reduced to 1 device */
		if (iod_format == IPC_FMT &&
			usb_ld->ld.com_state == COM_BOOT)
			iod_format = IPC_BOOT;
		if (iod_format == IPC_FMT &&
			usb_ld->ld.com_state == COM_CRASH)
			iod_format = IPC_RAMDUMP;

		iod = link_get_iod_with_format(&usb_ld->ld, iod_format);
		if (iod) {
			ret = iod->recv(iod,
					&usb_ld->ld,
					(char *)urb->transfer_buffer,
					urb->actual_length);
			if (ret < 0)
				mif_err("io device recv error :%d\n", ret);
		}
re_submit:
		if (urb->status || atomic_read(&usb_ld->suspend_count))
			break;

		usb_mark_last_busy(urb->dev);
		usb_rx_submit(pipe_data, urb, GFP_ATOMIC);
		return;
	case -ESHUTDOWN:
	case -EPROTO:
		break;
	case -EOVERFLOW:
		mif_err("RX overflow\n");
		break;
	default:
		mif_err("RX complete Status (%d)\n", urb->status);
		break;
	}

	usb_anchor_urb(urb, &pipe_data->urbs);
}