/** * 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; }
/** * 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; }