<commit_before>/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2016-2017 <NAME> <<EMAIL>>
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include "config.h"

#include <string.h>

#include "lu-common.h"
#include "lu-device-bootloader.h"
#include "lu-hidpp.h"

typedef struct
{
	guint16			 flash_addr_lo;
	guint16			 flash_addr_hi;
	guint16			 flash_blocksize;
} LuDeviceBootloaderPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (LuDeviceBootloader, lu_device_bootloader, LU_TYPE_DEVICE)

#define GET_PRIVATE(o) (lu_device_bootloader_get_instance_private (o))

LuDeviceBootloaderRequest *
lu_device_bootloader_request_new (void)
{
	LuDeviceBootloaderRequest *req = g_new0 (LuDeviceBootloaderRequest, 1);
	return req;
}

GPtrArray *
lu_device_bootloader_parse_requests (GBytes *fw, GError **error)
{
	const gchar *tmp;
	g_auto(GStrv) lines = NULL;
	g_autoptr(GPtrArray) reqs = NULL;

	reqs = g_ptr_array_new_with_free_func (g_free);
	tmp = g_bytes_get_data (fw, NULL);
	lines = g_strsplit_set (tmp, "\n\r", -1);
	for (guint i = 0; lines[i] != NULL; i++) {
		LuDeviceBootloaderRequest *payload;

		/* skip empty lines */
		tmp = lines[i];
		if (strlen (tmp) < 5)
			continue;

		payload = lu_device_bootloader_request_new ();
		payload->len = lu_buffer_read_uint8 (tmp + 0x01);
		if (payload->len > 28) {
			g_set_error (error,
				     G_IO_ERROR,
				     G_IO_ERROR_INVALID_DATA,
				     "firmware data invalid: too large %u bytes",
				     payload->len);
			return NULL;
		}
		payload->addr = ((guint16) lu_buffer_read_uint8 (tmp + 0x03)) << 8;
		payload->addr |= lu_buffer_read_uint8 (tmp + 0x05);

		/* read the data, but skip the checksum byte */
		for (guint j = 0; j < payload->len; j++) {
			const gchar *ptr = tmp + 0x09 + (j * 2);
			if (ptr[0] == '\0') {
				g_set_error (error,
					     G_IO_ERROR,
					     G_IO_ERROR_INVALID_DATA,
					     "firmware data invalid: expected %u bytes",
					     payload->len);
				return NULL;
			}
			payload->data[j] = lu_buffer_read_uint8 (ptr);
		}
		g_ptr_array_add (reqs, payload);
	}
	return g_steal_pointer (&reqs);
}

guint16
lu_device_bootloader_get_addr_lo (LuDevice *device)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000);
	return priv->flash_addr_lo;
}

guint16
lu_device_bootloader_get_addr_hi (LuDevice *device)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000);
	return priv->flash_addr_hi;
}

guint16
lu_device_bootloader_get_blocksize (LuDevice *device)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000);
	return priv->flash_blocksize;
}

static gboolean
lu_device_bootloader_attach (LuDevice *device, GError **error)
{
	g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new ();
	req->cmd = LU_DEVICE_BOOTLOADER_CMD_REBOOT;
	if (!lu_device_bootloader_request (device, req, error)) {
		g_prefix_error (error, "failed to attach back to runtime: ");
		return FALSE;
	}
	return TRUE;
}

static guint16
cd_buffer_read_uint16_be (const guint8 *buffer)
{
	guint16 tmp;
	memcpy (&tmp, buffer, sizeof(tmp));
	return GUINT16_FROM_BE (tmp);
}

static gboolean
lu_device_bootloader_open (LuDevice *device, GError **error)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_autofree gchar *name = NULL;
	g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new ();

	/* generate name */
	name = g_strdup_printf ("Unifying [%s]",
				lu_device_kind_to_string (lu_device_get_kind (device)));
	lu_device_set_product (device, name);

	/* we can flash this */
	lu_device_add_flag (device, LU_DEVICE_FLAG_CAN_FLASH);

	/* get memory map */
	req->cmd = LU_DEVICE_BOOTLOADER_CMD_GET_MEMINFO;
	if (!lu_device_bootloader_request (device, req, error)) {
		g_prefix_error (error, "failed to init fw transfer: ");
		return FALSE;
	}
	if (req->len != 0x06) {
		g_set_error (error,
			     G_IO_ERROR,
			     G_IO_ERROR_FAILED,
			     "failed to get meminfo: invalid size %02x",
			     req->len);
		return FALSE;
	}

	/* parse values */
	priv->flash_addr_lo = cd_buffer_read_uint16_be (req->data + 0);
	priv->flash_addr_hi = cd_buffer_read_uint16_be (req->data + 2);
	priv->flash_blocksize = cd_buffer_read_uint16_be (req->data + 4);
	return TRUE;
}

static gboolean
lu_device_bootloader_close (LuDevice *device, GError **error)
{
	GUsbDevice *usb_device = lu_device_get_usb_device (device);
	if (usb_device != NULL) {
		if (!g_usb_device_release_interface (usb_device, 0x00,
						     G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
						     error)) {
			return FALSE;
		}
	}<commit_msg>trivial: Fix up an error message in the unifying code<commit_after>/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2016-2017 <NAME> <<EMAIL>>
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include "config.h"

#include <string.h>

#include "lu-common.h"
#include "lu-device-bootloader.h"
#include "lu-hidpp.h"

typedef struct
{
	guint16			 flash_addr_lo;
	guint16			 flash_addr_hi;
	guint16			 flash_blocksize;
} LuDeviceBootloaderPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (LuDeviceBootloader, lu_device_bootloader, LU_TYPE_DEVICE)

#define GET_PRIVATE(o) (lu_device_bootloader_get_instance_private (o))

LuDeviceBootloaderRequest *
lu_device_bootloader_request_new (void)
{
	LuDeviceBootloaderRequest *req = g_new0 (LuDeviceBootloaderRequest, 1);
	return req;
}

GPtrArray *
lu_device_bootloader_parse_requests (GBytes *fw, GError **error)
{
	const gchar *tmp;
	g_auto(GStrv) lines = NULL;
	g_autoptr(GPtrArray) reqs = NULL;

	reqs = g_ptr_array_new_with_free_func (g_free);
	tmp = g_bytes_get_data (fw, NULL);
	lines = g_strsplit_set (tmp, "\n\r", -1);
	for (guint i = 0; lines[i] != NULL; i++) {
		LuDeviceBootloaderRequest *payload;

		/* skip empty lines */
		tmp = lines[i];
		if (strlen (tmp) < 5)
			continue;

		payload = lu_device_bootloader_request_new ();
		payload->len = lu_buffer_read_uint8 (tmp + 0x01);
		if (payload->len > 28) {
			g_set_error (error,
				     G_IO_ERROR,
				     G_IO_ERROR_INVALID_DATA,
				     "firmware data invalid: too large %u bytes",
				     payload->len);
			return NULL;
		}
		payload->addr = ((guint16) lu_buffer_read_uint8 (tmp + 0x03)) << 8;
		payload->addr |= lu_buffer_read_uint8 (tmp + 0x05);

		/* read the data, but skip the checksum byte */
		for (guint j = 0; j < payload->len; j++) {
			const gchar *ptr = tmp + 0x09 + (j * 2);
			if (ptr[0] == '\0') {
				g_set_error (error,
					     G_IO_ERROR,
					     G_IO_ERROR_INVALID_DATA,
					     "firmware data invalid: expected %u bytes",
					     payload->len);
				return NULL;
			}
			payload->data[j] = lu_buffer_read_uint8 (ptr);
		}
		g_ptr_array_add (reqs, payload);
	}
	return g_steal_pointer (&reqs);
}

guint16
lu_device_bootloader_get_addr_lo (LuDevice *device)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000);
	return priv->flash_addr_lo;
}

guint16
lu_device_bootloader_get_addr_hi (LuDevice *device)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000);
	return priv->flash_addr_hi;
}

guint16
lu_device_bootloader_get_blocksize (LuDevice *device)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000);
	return priv->flash_blocksize;
}

static gboolean
lu_device_bootloader_attach (LuDevice *device, GError **error)
{
	g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new ();
	req->cmd = LU_DEVICE_BOOTLOADER_CMD_REBOOT;
	if (!lu_device_bootloader_request (device, req, error)) {
		g_prefix_error (error, "failed to attach back to runtime: ");
		return FALSE;
	}
	return TRUE;
}

static guint16
cd_buffer_read_uint16_be (const guint8 *buffer)
{
	guint16 tmp;
	memcpy (&tmp, buffer, sizeof(tmp));
	return GUINT16_FROM_BE (tmp);
}

static gboolean
lu_device_bootloader_open (LuDevice *device, GError **error)
{
	LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device);
	LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader);
	g_autofree gchar *name = NULL;
	g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new ();

	/* generate name */
	name = g_strdup_printf ("Unifying [%s]",
				lu_device_kind_to_string (lu_device_get_kind (device)));
	lu_device_set_product (device, name);

	/* we can flash this */
	lu_device_add_flag (device, LU_DEVICE_FLAG_CAN_FLASH);

	/* get memory map */
	req->cmd = LU_DEVICE_BOOTLOADER_CMD_GET_MEMINFO;
	if (!lu_device_bootloader_request (device, req, error)) {
		g_prefix_error (error, "failed to get meminfo: ");
		return FALSE;
	}
	if (req->len != 0x06) {
		g_set_error (error,
			     G_IO_ERROR,
			     G_IO_ERROR_FAILED,
			     "failed to get meminfo: invalid size %02x",
			     req->len);
		return FALSE;
	}

	/* parse values */
	priv->flash_addr_lo = cd_buffer_read_uint16_be (req->data + 0);
	priv->flash_addr_hi = cd_buffer_read_uint16_be (req->data + 2);
	priv->flash_blocksize = cd_buffer_read_uint16_be (req->data + 4);
	return TRUE;
}

static gboolean
lu_device_bootloader_close (LuDevice *device, GError **error)
{
	GUsbDevice *usb_device = lu_device_get_usb_device (device);
	if (usb_device != NULL) {
		if (!g_usb_device_release_interface (usb_device, 0x00,
						     G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
						     error)) {
			return FALSE;
		}
	}
{'fraction_non_alphanumeric': 0.10362561069683723, 'fraction_numerical': 0.01851375674980715, 'mean_word_length': 4.650363196125908, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6526461', 'n_tokens_mistral': 4514, 'n_tokens_neox': 4103, 'n_words': 1040}