<commit_before>/*
 * Copyright (C) 2017-2018 <NAME> <<EMAIL>>
 *
 * SPDX-License-Identifier: LGPL-2.1+
 */

#include "config.h"

#include <string.h>

#include "fu-chunk.h"
#include "fu-csr-device.h"
#include "fu-dfu-firmware.h"

#include "dfu-common.h"

/**
 * FU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY:
 *
 * Respect the write timeout value when performing actions. This is sometimes
 * set to a huge amount of time, and so is not used by default.
 *
 * Since: 1.0.3
 */
#define FU_CSR_DEVICE_FLAG_REQUIRE_DELAY	"require-delay"

typedef enum {
	FU_CSR_DEVICE_QUIRK_NONE		= 0,
	FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY	= (1 << 0),
	FU_CSR_DEVICE_QUIRK_LAST
} FuCsrDeviceQuirks;

struct _FuCsrDevice
{
	FuHidDevice		 parent_instance;
	FuCsrDeviceQuirks	 quirks;
	DfuState		 dfu_state;
	guint32			 dnload_timeout;
};

G_DEFINE_TYPE (FuCsrDevice, fu_csr_device, FU_TYPE_HID_DEVICE)

#define FU_CSR_REPORT_ID_COMMAND		0x01
#define FU_CSR_REPORT_ID_STATUS			0x02
#define FU_CSR_REPORT_ID_CONTROL		0x03

#define FU_CSR_COMMAND_HEADER_SIZE		6	/* bytes */
#define FU_CSR_COMMAND_UPGRADE			0x01

#define FU_CSR_STATUS_HEADER_SIZE		7

#define FU_CSR_CONTROL_HEADER_SIZE		2	/* bytes */
#define FU_CSR_CONTROL_CLEAR_STATUS		0x04
#define FU_CSR_CONTROL_RESET			0xff

/* maximum firmware packet, including the command header */
#define FU_CSR_PACKET_DATA_SIZE			1023	/* bytes */

#define FU_CSR_DEVICE_TIMEOUT			5000	/* ms */

static void
fu_csr_device_to_string (FuDevice *device, guint idt, GString *str)
{
	FuCsrDevice *self = FU_CSR_DEVICE (device);
	fu_common_string_append_kv (str, idt, "State", dfu_state_to_string (self->dfu_state));
	fu_common_string_append_ku (str, idt, "DownloadTimeout", self->dnload_timeout);
}

static gboolean
fu_csr_device_attach (FuDevice *device, GError **error)
{
	guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET };
	if (!fu_hid_device_set_report (FU_HID_DEVICE (device),
				       FU_CSR_REPORT_ID_CONTROL,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to attach: ");
		return FALSE;
	}
	return TRUE;
}

static gboolean
fu_csr_device_get_status (FuCsrDevice *self, GError **error)
{
	guint8 buf[64] = {0};

	/* hit hardware */
	if (!fu_hid_device_get_report (FU_HID_DEVICE (self),
				       FU_CSR_REPORT_ID_STATUS,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to GetStatus: ");
		return FALSE;
	}

	/* check packet */
	if (buf[0] != FU_CSR_REPORT_ID_STATUS) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INTERNAL,
			     "GetStatus packet-id was %i expected %i",
			     buf[0], FU_CSR_REPORT_ID_STATUS);
		return FALSE;
	}

	self->dfu_state = buf[5];
	self->dnload_timeout = buf[2] + (((guint32) buf[3]) << 8) + (((guint32) buf[4]) << 16);
	g_debug ("timeout=%" G_GUINT32_FORMAT, self->dnload_timeout);
	g_debug ("state=%s", dfu_state_to_string (self->dfu_state));
	g_debug ("status=%s", dfu_status_to_string (buf[6]));
	return TRUE;
}


static gboolean
fu_csr_device_clear_status (FuCsrDevice *self, GError **error)
{
	guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL,
			 FU_CSR_CONTROL_CLEAR_STATUS };

	/* only clear the status if the state is error */
	if (!fu_csr_device_get_status (self, error))
		return FALSE;
	if (self->dfu_state != DFU_STATE_DFU_ERROR)
		return TRUE;

	/* hit hardware */
	if (!fu_hid_device_set_report (FU_HID_DEVICE (self),
				       FU_CSR_REPORT_ID_CONTROL,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to ClearStatus: ");
		return FALSE;
	}

	/* check the hardware again */
	return fu_csr_device_get_status (self, error);
}

static GBytes *
fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error)
{
	guint16 data_sz;
	guint8 buf[64] = {0};

	/* hit hardware */
	if (!fu_hid_device_get_report (FU_HID_DEVICE (self),
				       FU_CSR_REPORT_ID_COMMAND,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to ReadFirmware: ");
		return NULL;
	}

	/* check command byte */
	if (buf[0] != FU_CSR_REPORT_ID_COMMAND) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INTERNAL,<commit_msg>csr: Allow truncated HID reads<commit_after>/*
 * Copyright (C) 2017-2018 <NAME> <<EMAIL>>
 *
 * SPDX-License-Identifier: LGPL-2.1+
 */

#include "config.h"

#include <string.h>

#include "fu-chunk.h"
#include "fu-csr-device.h"
#include "fu-dfu-firmware.h"

#include "dfu-common.h"

/**
 * FU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY:
 *
 * Respect the write timeout value when performing actions. This is sometimes
 * set to a huge amount of time, and so is not used by default.
 *
 * Since: 1.0.3
 */
#define FU_CSR_DEVICE_FLAG_REQUIRE_DELAY	"require-delay"

typedef enum {
	FU_CSR_DEVICE_QUIRK_NONE		= 0,
	FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY	= (1 << 0),
	FU_CSR_DEVICE_QUIRK_LAST
} FuCsrDeviceQuirks;

struct _FuCsrDevice
{
	FuHidDevice		 parent_instance;
	FuCsrDeviceQuirks	 quirks;
	DfuState		 dfu_state;
	guint32			 dnload_timeout;
};

G_DEFINE_TYPE (FuCsrDevice, fu_csr_device, FU_TYPE_HID_DEVICE)

#define FU_CSR_REPORT_ID_COMMAND		0x01
#define FU_CSR_REPORT_ID_STATUS			0x02
#define FU_CSR_REPORT_ID_CONTROL		0x03

#define FU_CSR_COMMAND_HEADER_SIZE		6	/* bytes */
#define FU_CSR_COMMAND_UPGRADE			0x01

#define FU_CSR_STATUS_HEADER_SIZE		7

#define FU_CSR_CONTROL_HEADER_SIZE		2	/* bytes */
#define FU_CSR_CONTROL_CLEAR_STATUS		0x04
#define FU_CSR_CONTROL_RESET			0xff

/* maximum firmware packet, including the command header */
#define FU_CSR_PACKET_DATA_SIZE			1023	/* bytes */

#define FU_CSR_DEVICE_TIMEOUT			5000	/* ms */

static void
fu_csr_device_to_string (FuDevice *device, guint idt, GString *str)
{
	FuCsrDevice *self = FU_CSR_DEVICE (device);
	fu_common_string_append_kv (str, idt, "State", dfu_state_to_string (self->dfu_state));
	fu_common_string_append_ku (str, idt, "DownloadTimeout", self->dnload_timeout);
}

static gboolean
fu_csr_device_attach (FuDevice *device, GError **error)
{
	guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET };
	if (!fu_hid_device_set_report (FU_HID_DEVICE (device),
				       FU_CSR_REPORT_ID_CONTROL,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to attach: ");
		return FALSE;
	}
	return TRUE;
}

static gboolean
fu_csr_device_get_status (FuCsrDevice *self, GError **error)
{
	guint8 buf[64] = {0};

	/* hit hardware */
	if (!fu_hid_device_get_report (FU_HID_DEVICE (self),
				       FU_CSR_REPORT_ID_STATUS,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_ALLOW_TRUNC |
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to GetStatus: ");
		return FALSE;
	}

	/* check packet */
	if (buf[0] != FU_CSR_REPORT_ID_STATUS) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INTERNAL,
			     "GetStatus packet-id was %i expected %i",
			     buf[0], FU_CSR_REPORT_ID_STATUS);
		return FALSE;
	}

	self->dfu_state = buf[5];
	self->dnload_timeout = buf[2] + (((guint32) buf[3]) << 8) + (((guint32) buf[4]) << 16);
	g_debug ("timeout=%" G_GUINT32_FORMAT, self->dnload_timeout);
	g_debug ("state=%s", dfu_state_to_string (self->dfu_state));
	g_debug ("status=%s", dfu_status_to_string (buf[6]));
	return TRUE;
}


static gboolean
fu_csr_device_clear_status (FuCsrDevice *self, GError **error)
{
	guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL,
			 FU_CSR_CONTROL_CLEAR_STATUS };

	/* only clear the status if the state is error */
	if (!fu_csr_device_get_status (self, error))
		return FALSE;
	if (self->dfu_state != DFU_STATE_DFU_ERROR)
		return TRUE;

	/* hit hardware */
	if (!fu_hid_device_set_report (FU_HID_DEVICE (self),
				       FU_CSR_REPORT_ID_CONTROL,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to ClearStatus: ");
		return FALSE;
	}

	/* check the hardware again */
	return fu_csr_device_get_status (self, error);
}

static GBytes *
fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error)
{
	guint16 data_sz;
	guint8 buf[64] = {0};

	/* hit hardware */
	if (!fu_hid_device_get_report (FU_HID_DEVICE (self),
				       FU_CSR_REPORT_ID_COMMAND,
				       buf, sizeof(buf),
				       FU_CSR_DEVICE_TIMEOUT,
				       FU_HID_DEVICE_FLAG_ALLOW_TRUNC |
				       FU_HID_DEVICE_FLAG_IS_FEATURE,
				       error)) {
		g_prefix_error (error, "failed to ReadFirmware: ");
		return NULL;
	}

	/* check command byte */
	if (buf[0] != FU_CSR_REPORT_ID_COMMAND) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INTERNAL,
{'fraction_non_alphanumeric': 0.10647786821273275, 'fraction_numerical': 0.016501282194224552, 'mean_word_length': 3.9476006618863764, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1976517', 'n_tokens_mistral': 3979, 'n_tokens_neox': 3601, 'n_words': 691}