Exemplo n.º 1
0
/**
 * dtp94_device_send_data:
 *
 * Since: 0.1.29
 **/
gboolean
dtp94_device_send_data (GUsbDevice *device,
			const guint8 *request,
			gsize request_len,
			guint8 *reply,
			gsize reply_len,
			gsize *reply_read,
			GError **error)
{
	gboolean ret;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (request != NULL, FALSE);
	g_return_val_if_fail (request_len != 0, FALSE);
	g_return_val_if_fail (reply != NULL, FALSE);
	g_return_val_if_fail (reply_len != 0, FALSE);
	g_return_val_if_fail (reply_read != NULL, FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* request data from device */
	cd_buffer_debug (CD_BUFFER_KIND_REQUEST,
			 request, request_len);
	ret = g_usb_device_interrupt_transfer (device,
					       0x2,
					       (guint8 *) request,
					       request_len,
					       NULL,
					       DTP94_CONTROL_MESSAGE_TIMEOUT,
					       NULL,
					       error);
	if (!ret)
		return FALSE;

	/* get sync response */
	ret = g_usb_device_interrupt_transfer (device,
					       0x81,
					       (guint8 *) reply,
					       reply_len,
					       reply_read,
					       DTP94_CONTROL_MESSAGE_TIMEOUT,
					       NULL,
					       error);
	if (!ret)
		return FALSE;
	if (reply_read == 0) {
		g_set_error_literal (error,
				     DTP94_DEVICE_ERROR,
				     DTP94_DEVICE_ERROR_INTERNAL,
				     "failed to get data from device");
		return FALSE;
	}
	cd_buffer_debug (CD_BUFFER_KIND_RESPONSE,
			 reply, *reply_read);
	return TRUE;
}
Exemplo n.º 2
0
/**
 * osp_device_query:
 *
 * Since: 1.2.11
 **/
static gboolean
osp_device_query (GUsbDevice *device, OspCmd cmd,
		  const guint8 *data_in, gsize data_in_length,
		  guint8 **data_out, gsize *data_out_length,
		  GError **error)
{
	OspProtocolFooter *ftr;
	OspProtocolHeader *hdr;
	gsize actual_length;
	gsize checksum_length = 16; /* always for MD5 */
	gsize payload_length = 0;
	gsize offset_rd = 0;
	gsize offset_wr = 0;
	guint i;
	g_autoptr(GChecksum) csum = NULL;
	g_autofree guint8 *buffer_in = NULL;
	g_autofree guint8 *buffer_out = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
	g_return_val_if_fail (data_in_length <= 16, FALSE); //FIXME
	g_assert (sizeof(OspProtocolHeader) + sizeof(OspProtocolFooter) == 64);

	/* write header to buffer */
	buffer_in = g_new0 (guint8, OSP_DEVICE_MAX_MSG_LENGTH);
	hdr = (OspProtocolHeader *) buffer_in;
	hdr->start_bytes = GUINT16_TO_BE (0xc1c0);
	hdr->protocol_version = 0x1000;
	hdr->checksum_type = OSP_HEADER_CHECKSUM_KIND_MD5;
	hdr->message_type = cmd;
	hdr->bytes_remaining = sizeof(OspProtocolFooter);
	if (data_out == NULL)
		hdr->flags = OSP_HEADER_FLAG_ACK_REQUIRED;
	if (data_in_length > 0) {
		if (data_in_length <= 16) {
			/* avoid another USB packet if we can */
			hdr->immediate_data_length = data_in_length;
			memcpy (hdr->immediate_data, data_in, data_in_length);
		} else {
			payload_length = data_in_length;
		}
	}
	offset_wr += sizeof(OspProtocolHeader);
	hdr->bytes_remaining = sizeof(OspProtocolFooter) + payload_length;

	/* write payload to buffer, if any */
	if (payload_length > 0) {
		memcpy (buffer_in + offset_wr, data_in, data_in_length);
		offset_wr += payload_length;
	}

	/* write footer to buffer */
	ftr = (OspProtocolFooter *) (buffer_in + offset_wr);
	ftr->end_bytes = GUINT32_TO_BE (0xc5c4c3c2);
	csum = g_checksum_new (G_CHECKSUM_MD5);
	g_checksum_update (csum, (const guchar *) buffer_in, offset_wr);
	g_checksum_get_digest (csum, ftr->checksum, &checksum_length);
	offset_wr += sizeof(OspProtocolFooter);

	/* send data */
	if (g_getenv ("SPARK_PROTOCOL_DEBUG") != NULL)
		cd_buffer_debug (CD_BUFFER_KIND_REQUEST, buffer_in, offset_wr);
	if (!g_usb_device_bulk_transfer (device, 0x01,
					 buffer_in, offset_wr,
					 &actual_length,
					 OSP_USB_TIMEOUT_MS, NULL, error))
		return FALSE;

	/* get reply */
	buffer_out = g_new0 (guint8, 64);
	if (!g_usb_device_bulk_transfer (device, 0x81,
					 buffer_out, OSP_DEVICE_EP_SIZE,
					 &actual_length,
					 OSP_USB_TIMEOUT_MS, NULL, error))
		return FALSE;
	if (g_getenv ("SPARK_PROTOCOL_DEBUG") != NULL)
		cd_buffer_debug (CD_BUFFER_KIND_RESPONSE, buffer_out, actual_length);

	/* check the error code */
	hdr = (OspProtocolHeader *) buffer_out;
	switch (hdr->error_code) {
	case OSP_ERROR_CODE_SUCCESS:
		break;
	case OSP_ERROR_CODE_MESSAGE_TOO_LARGE:
	case OSP_ERROR_CODE_UNKNOWN_CHECKSUM_TYPE:
	case OSP_ERROR_CODE_UNSUPPORTED_PROTOCOL:
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_NO_SUPPORT,
			     "Failed to %s",
			     osp_cmd_to_string (cmd));
		return FALSE;
		break;
	case OSP_ERROR_CODE_COMMAND_DATA_MISSING:
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_NO_DATA,
			     "Failed to %s",
			     osp_cmd_to_string (cmd));
		return FALSE;
		break;
	default:
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Failed to %s: %s",
			     osp_cmd_to_string (cmd),
			     osp_error_code_to_string (hdr->error_code));
		return FALSE;
		break;
	}

	/* copy out the data */
	offset_rd = sizeof(OspProtocolHeader);
	if (data_out != NULL && data_out_length != NULL) {
		if (hdr->immediate_data_length > 0) {
			*data_out_length = hdr->immediate_data_length;
			*data_out = g_memdup (hdr->immediate_data,
					      hdr->immediate_data_length);
		} else if (hdr->bytes_remaining >= sizeof(OspProtocolFooter)) {
			*data_out_length = hdr->bytes_remaining - sizeof(OspProtocolFooter);
			*data_out = g_new0 (guint8, hdr->bytes_remaining);

			/* copy the first chunk of data */
			offset_wr = 64 - offset_rd;
			memcpy (*data_out, buffer_out + offset_rd, offset_wr);
		} else {
			g_assert_not_reached ();
		}
	}

	/* read the rest of the payload */
	payload_length = hdr->bytes_remaining - sizeof(OspProtocolFooter);
	for (i = 0; i < payload_length / 64; i++) {
		if (!g_usb_device_bulk_transfer (device, 0x81,
						 buffer_out, OSP_DEVICE_EP_SIZE,
						 &actual_length,
						 OSP_USB_TIMEOUT_MS, NULL, error))
			return FALSE;
		if (data_out != NULL) {
			memcpy (*data_out + offset_wr,
				buffer_out, OSP_DEVICE_EP_SIZE);
		}
		if (g_getenv ("SPARK_PROTOCOL_DEBUG") != NULL)
			cd_buffer_debug (CD_BUFFER_KIND_RESPONSE, buffer_out, OSP_DEVICE_EP_SIZE);
		offset_wr += 64;
	}
	offset_rd += payload_length;

	/* verify the footer is intact */
	ftr = (OspProtocolFooter *) (buffer_out + OSP_DEVICE_EP_SIZE - sizeof(OspProtocolFooter));
	if (ftr->end_bytes != GUINT32_TO_BE (0xc5c4c3c2)) {
		g_set_error_literal (error,
				     OSP_DEVICE_ERROR,
				     OSP_DEVICE_ERROR_INTERNAL,
				     "Footer invalid");
		return FALSE;
	}

	return TRUE;
}