mirror of
https://git.proxmox.com/git/fwupd
synced 2026-01-08 19:37:27 +00:00
hailuck: Add an plugin for the Pinebook Pro laptop
This is not complete enough for LVFS-usage, but good enough to use with commands such as fwupdtool. It's likely newer kbd and tp firmware will be required to integrate with the fwupd in all required ways.
This commit is contained in:
parent
fa11ceae9c
commit
db4894e863
@ -408,6 +408,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_ep963x.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_hailuck.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_iommu.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so
|
||||
%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_lockdown.so
|
||||
|
||||
35
plugins/hailuck/README.md
Normal file
35
plugins/hailuck/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
Hailuck Support
|
||||
===============
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Hailuck produce the firmware used on the keyboard and trackpad used in the
|
||||
Pinebook Pro laptops.
|
||||
|
||||
Firmware Format
|
||||
---------------
|
||||
|
||||
The daemon will decompress the cabinet archive and extract a firmware blob in
|
||||
a packed binary file format.
|
||||
|
||||
This plugin supports the following protocol ID:
|
||||
|
||||
* com.hailuck.kbd
|
||||
* com.hailuck.tp
|
||||
|
||||
GUID Generation
|
||||
---------------
|
||||
|
||||
These devices use the standard USB DeviceInstanceId values, e.g.
|
||||
|
||||
* `USB\VID_0603&PID_1020`
|
||||
|
||||
Vendor ID Security
|
||||
------------------
|
||||
|
||||
The vendor ID is set from the USB vendor, in this instance set to `USB:0x0603`
|
||||
|
||||
External interface access
|
||||
-------------------------
|
||||
This plugin requires read/write access to `/dev/bus/usb`.
|
||||
47
plugins/hailuck/data/lspci-bl.txt
Normal file
47
plugins/hailuck/data/lspci-bl.txt
Normal file
@ -0,0 +1,47 @@
|
||||
Bus 003 Device 003: ID 0603:1020 Novatek Microelectronics Corp.
|
||||
Device Descriptor:
|
||||
bLength 18
|
||||
bDescriptorType 1
|
||||
bcdUSB 1.10
|
||||
bDeviceClass 0
|
||||
bDeviceSubClass 0
|
||||
bDeviceProtocol 0
|
||||
bMaxPacketSize0 8
|
||||
idVendor 0x0603 Novatek Microelectronics Corp.
|
||||
idProduct 0x1020
|
||||
bcdDevice 3.01
|
||||
iManufacturer 0
|
||||
iProduct 0
|
||||
iSerial 0
|
||||
bNumConfigurations 1
|
||||
Configuration Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 2
|
||||
wTotalLength 0x0022
|
||||
bNumInterfaces 1
|
||||
bConfigurationValue 1
|
||||
iConfiguration 0
|
||||
bmAttributes 0xa0
|
||||
(Bus Powered)
|
||||
Remote Wakeup
|
||||
MaxPower 100mA
|
||||
Interface Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 4
|
||||
bInterfaceNumber 0
|
||||
bAlternateSetting 0
|
||||
bNumEndpoints 1
|
||||
bInterfaceClass 3 Human Interface Device
|
||||
bInterfaceSubClass 1 Boot Interface Subclass
|
||||
bInterfaceProtocol 1 Keyboard
|
||||
iInterface 0
|
||||
Endpoint Descriptor:
|
||||
bLength 7
|
||||
bDescriptorType 5
|
||||
bEndpointAddress 0x81 EP 1 IN
|
||||
bmAttributes 3
|
||||
Transfer Type Interrupt
|
||||
Synch Type None
|
||||
Usage Type Data
|
||||
wMaxPacketSize 0x0008 1x 8 bytes
|
||||
bInterval 10
|
||||
89
plugins/hailuck/data/lspci.txt
Normal file
89
plugins/hailuck/data/lspci.txt
Normal file
@ -0,0 +1,89 @@
|
||||
Bus 003 Device 008: ID 258a:001e HAILUCK CO.,LTD USB KEYBOARD
|
||||
Device Descriptor:
|
||||
bLength 18
|
||||
bDescriptorType 1
|
||||
bcdUSB 1.10
|
||||
bDeviceClass 0
|
||||
bDeviceSubClass 0
|
||||
bDeviceProtocol 0
|
||||
bMaxPacketSize0 8
|
||||
idVendor 0x258a
|
||||
idProduct 0x001e
|
||||
bcdDevice 1.00
|
||||
iManufacturer 1 HAILUCK CO.,LTD
|
||||
iProduct 2 USB KEYBOARD
|
||||
iSerial 0
|
||||
bNumConfigurations 1
|
||||
Configuration Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 2
|
||||
wTotalLength 0x003b
|
||||
bNumInterfaces 2
|
||||
bConfigurationValue 1
|
||||
iConfiguration 0
|
||||
bmAttributes 0xa0
|
||||
(Bus Powered)
|
||||
Remote Wakeup
|
||||
MaxPower 100mA
|
||||
Interface Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 4
|
||||
bInterfaceNumber 0
|
||||
bAlternateSetting 0
|
||||
bNumEndpoints 1
|
||||
bInterfaceClass 3 Human Interface Device
|
||||
bInterfaceSubClass 1 Boot Interface Subclass
|
||||
bInterfaceProtocol 1 Keyboard
|
||||
iInterface 0
|
||||
HID Device Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 33
|
||||
bcdHID 1.10
|
||||
bCountryCode 0 Not supported
|
||||
bNumDescriptors 1
|
||||
bDescriptorType 34 Report
|
||||
wDescriptorLength 65
|
||||
Report Descriptors:
|
||||
** UNAVAILABLE **
|
||||
Endpoint Descriptor:
|
||||
bLength 7
|
||||
bDescriptorType 5
|
||||
bEndpointAddress 0x81 EP 1 IN
|
||||
bmAttributes 3
|
||||
Transfer Type Interrupt
|
||||
Synch Type None
|
||||
Usage Type Data
|
||||
wMaxPacketSize 0x0008 1x 8 bytes
|
||||
bInterval 10
|
||||
Interface Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 4
|
||||
bInterfaceNumber 1
|
||||
bAlternateSetting 0
|
||||
bNumEndpoints 1
|
||||
bInterfaceClass 3 Human Interface Device
|
||||
bInterfaceSubClass 0
|
||||
bInterfaceProtocol 0
|
||||
iInterface 0
|
||||
HID Device Descriptor:
|
||||
bLength 9
|
||||
bDescriptorType 33
|
||||
bcdHID 1.10
|
||||
bCountryCode 0 Not supported
|
||||
bNumDescriptors 1
|
||||
bDescriptorType 34 Report
|
||||
wDescriptorLength 487
|
||||
Report Descriptors:
|
||||
** UNAVAILABLE **
|
||||
Endpoint Descriptor:
|
||||
bLength 7
|
||||
bDescriptorType 5
|
||||
bEndpointAddress 0x82 EP 2 IN
|
||||
bmAttributes 3
|
||||
Transfer Type Interrupt
|
||||
Synch Type None
|
||||
Usage Type Data
|
||||
wMaxPacketSize 0x0008 1x 8 bytes
|
||||
bInterval 10
|
||||
Device Status: 0x0000
|
||||
(Bus Powered)
|
||||
272
plugins/hailuck/fu-hailuck-bl-device.c
Normal file
272
plugins/hailuck/fu-hailuck-bl-device.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-chunk.h"
|
||||
#include "fu-hailuck-common.h"
|
||||
#include "fu-hailuck-bl-device.h"
|
||||
#include "fu-hailuck-kbd-firmware.h"
|
||||
|
||||
struct _FuHaiLuckBlDevice {
|
||||
FuHidDevice parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuHaiLuckBlDevice, fu_hailuck_bl_device, FU_TYPE_HID_DEVICE)
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_attach (FuDevice *device, GError **error)
|
||||
{
|
||||
guint8 buf[6] = {
|
||||
FU_HAILUCK_REPORT_ID_SHORT,
|
||||
FU_HAILUCK_CMD_ATTACH,
|
||||
};
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
|
||||
if (!fu_hid_device_set_report (FU_HID_DEVICE (device),
|
||||
buf[0], buf, sizeof(buf), 1000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error))
|
||||
return FALSE;
|
||||
if (!g_usb_device_reset (fu_usb_device_get_dev (FU_USB_DEVICE (device)), error))
|
||||
return FALSE;
|
||||
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_probe (FuUsbDevice *device, GError **error)
|
||||
{
|
||||
g_autofree gchar *devid = NULL;
|
||||
|
||||
/* add extra keyboard-specific GUID */
|
||||
devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&MODE_KBD",
|
||||
fu_usb_device_get_vid (device),
|
||||
fu_usb_device_get_pid (device));
|
||||
fu_device_add_instance_id (FU_DEVICE (device), devid);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_read_block_start (FuHaiLuckBlDevice *self,
|
||||
guint32 length,
|
||||
GError **error)
|
||||
{
|
||||
guint8 buf[6] = {
|
||||
FU_HAILUCK_REPORT_ID_SHORT,
|
||||
FU_HAILUCK_CMD_READ_BLOCK_START,
|
||||
};
|
||||
fu_common_write_uint16 (buf + 4, length, G_LITTLE_ENDIAN);
|
||||
return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0],
|
||||
buf, sizeof(buf), 100,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_read_block (FuHaiLuckBlDevice *self,
|
||||
guint8 *data, gsize data_sz,
|
||||
GError **error)
|
||||
{
|
||||
gsize bufsz = data_sz + 2;
|
||||
g_autofree guint8 *buf = g_malloc0 (bufsz);
|
||||
|
||||
buf[0] = FU_HAILUCK_REPORT_ID_LONG;
|
||||
buf[1] = FU_HAILUCK_CMD_READ_BLOCK;
|
||||
if (!fu_hid_device_get_report (FU_HID_DEVICE (self), buf[0],
|
||||
buf, bufsz, 2000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE,
|
||||
error))
|
||||
return FALSE;
|
||||
if (!fu_memcpy_safe (data, data_sz, 0x0, /* dst */
|
||||
buf, bufsz, 0x02, /* src */
|
||||
data_sz, error))
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
g_usleep (10000);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
fu_hailuck_bl_device_dump_firmware (FuDevice *device, GError **error)
|
||||
{
|
||||
FuHaiLuckBlDevice *self = FU_HAILUCK_BL_DEVICE (device);
|
||||
gsize fwsz = fu_device_get_firmware_size_max (device);
|
||||
g_autoptr(GByteArray) fwbuf = g_byte_array_new ();
|
||||
g_autoptr(GPtrArray) chunks = NULL;
|
||||
|
||||
/* tell device amount of data to send */
|
||||
fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ);
|
||||
if (!fu_hailuck_bl_device_read_block_start (self, fwsz, error))
|
||||
return NULL;
|
||||
|
||||
/* recieve data back */
|
||||
fu_byte_array_set_size (fwbuf, fwsz);
|
||||
chunks = fu_chunk_array_new (fwbuf->data, fwbuf->len, 0x0, 0x0, 2048);
|
||||
for (guint i = 0; i < chunks->len; i++) {
|
||||
FuChunk *chk = g_ptr_array_index (chunks, i);
|
||||
if (!fu_hailuck_bl_device_read_block (self,
|
||||
(guint8 *) chk->data,
|
||||
chk->data_sz,
|
||||
error))
|
||||
return NULL;
|
||||
fu_device_set_progress_full (device, i, chunks->len - 1);
|
||||
}
|
||||
|
||||
/* success */
|
||||
return g_byte_array_free_to_bytes (g_steal_pointer (&fwbuf));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_erase (FuHaiLuckBlDevice *self, GError **error)
|
||||
{
|
||||
guint8 buf[6] = {
|
||||
FU_HAILUCK_REPORT_ID_SHORT,
|
||||
FU_HAILUCK_CMD_ERASE,
|
||||
};
|
||||
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0],
|
||||
buf, sizeof(buf), 100,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error))
|
||||
return FALSE;
|
||||
fu_device_sleep_with_progress (FU_DEVICE (self), 2);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_write_block_start (FuHaiLuckBlDevice *self,
|
||||
guint32 length, GError **error)
|
||||
{
|
||||
guint8 buf[6] = {
|
||||
FU_HAILUCK_REPORT_ID_SHORT,
|
||||
FU_HAILUCK_CMD_WRITE_BLOCK_START,
|
||||
};
|
||||
fu_common_write_uint16 (buf + 4, length, G_LITTLE_ENDIAN);
|
||||
return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0],
|
||||
buf, sizeof(buf), 100,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_write_block (FuHaiLuckBlDevice *self,
|
||||
const guint8 *data, gsize data_sz,
|
||||
GError **error)
|
||||
{
|
||||
gsize bufsz = data_sz + 2;
|
||||
g_autofree guint8 *buf = g_malloc0 (bufsz);
|
||||
|
||||
buf[0] = FU_HAILUCK_REPORT_ID_LONG;
|
||||
buf[1] = FU_HAILUCK_CMD_WRITE_BLOCK;
|
||||
if (!fu_memcpy_safe (buf, bufsz, 0x02, /* dst */
|
||||
data, data_sz, 0x0, /* src */
|
||||
data_sz, error))
|
||||
return FALSE;
|
||||
if (!fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0],
|
||||
buf, bufsz, 2000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
g_usleep (10000);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FuFirmware *
|
||||
fu_hailuck_bl_device_prepare_firmware (FuDevice *device,
|
||||
GBytes *fw,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FuFirmware) firmware = fu_hailuck_kbd_firmware_new ();
|
||||
if (!fu_firmware_parse (firmware, fw, flags, error))
|
||||
return NULL;
|
||||
return g_steal_pointer (&firmware);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_bl_device_write_firmware (FuDevice *device,
|
||||
FuFirmware *firmware,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
FuHaiLuckBlDevice *self = FU_HAILUCK_BL_DEVICE (device);
|
||||
FuChunk *chk0;
|
||||
g_autoptr(GBytes) fw = NULL;
|
||||
g_autoptr(GBytes) fw_new = NULL;
|
||||
g_autoptr(GPtrArray) chunks = NULL;
|
||||
g_autofree guint8 *chk0_data = NULL;
|
||||
|
||||
/* get default image */
|
||||
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* erase all contents */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
||||
if (!fu_hailuck_bl_device_erase (self, error))
|
||||
return FALSE;
|
||||
|
||||
/* tell device amount of data to expect */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
||||
if (!fu_hailuck_bl_device_write_block_start (self, g_bytes_get_size (fw), error))
|
||||
return FALSE;
|
||||
|
||||
/* build packets */
|
||||
chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x00, 2048);
|
||||
|
||||
/* intentionally corrupt first chunk so that CRC fails */
|
||||
chk0 = g_ptr_array_index (chunks, 0);
|
||||
chk0_data = g_memdup (chk0->data, chk0->data_sz);
|
||||
chk0_data[0] = 0x00;
|
||||
if (!fu_hailuck_bl_device_write_block (self, chk0_data, chk0->data_sz, error))
|
||||
return FALSE;
|
||||
|
||||
/* send the rest of the chunks */
|
||||
for (guint i = 1; i < chunks->len; i++) {
|
||||
FuChunk *chk = g_ptr_array_index (chunks, i);
|
||||
if (!fu_hailuck_bl_device_write_block (self, chk->data, chk->data_sz, error))
|
||||
return FALSE;
|
||||
fu_device_set_progress_full (device, i, chunks->len);
|
||||
}
|
||||
|
||||
/* retry write of first block */
|
||||
if (!fu_hailuck_bl_device_write_block_start (self, g_bytes_get_size (fw), error))
|
||||
return FALSE;
|
||||
if (!fu_hailuck_bl_device_write_block (self, chk0->data, chk0->data_sz, error))
|
||||
return FALSE;
|
||||
fu_device_set_progress_full (device, chunks->len, chunks->len);
|
||||
|
||||
/* verify */
|
||||
fw_new = fu_hailuck_bl_device_dump_firmware (device, error);
|
||||
return fu_common_bytes_compare (fw, fw_new, error);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_bl_device_init (FuHaiLuckBlDevice *self)
|
||||
{
|
||||
fu_device_set_firmware_size (FU_DEVICE (self), 0x4000);
|
||||
fu_device_set_protocol (FU_DEVICE (self), "com.hailuck.kbd");
|
||||
fu_device_set_name (FU_DEVICE (self), "Keyboard [bootloader]");
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
fu_device_add_icon (FU_DEVICE (self), "input-keyboard");
|
||||
fu_hid_device_add_flag (FU_HID_DEVICE (self), FU_HID_DEVICE_FLAG_NO_KERNEL_REBIND);
|
||||
fu_device_set_remove_delay (FU_DEVICE (self),
|
||||
FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_bl_device_class_init (FuHaiLuckBlDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
|
||||
klass_device->dump_firmware = fu_hailuck_bl_device_dump_firmware;
|
||||
klass_device->prepare_firmware = fu_hailuck_bl_device_prepare_firmware;
|
||||
klass_device->write_firmware = fu_hailuck_bl_device_write_firmware;
|
||||
klass_device->attach = fu_hailuck_bl_device_attach;
|
||||
klass_usb_device->probe = fu_hailuck_bl_device_probe;
|
||||
}
|
||||
13
plugins/hailuck/fu-hailuck-bl-device.h
Normal file
13
plugins/hailuck/fu-hailuck-bl-device.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-plugin.h"
|
||||
#include "fu-hid-device.h"
|
||||
|
||||
#define FU_TYPE_HAILUCK_BL_DEVICE (fu_hailuck_bl_device_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuHaiLuckBlDevice, fu_hailuck_bl_device, FU, HAILUCK_BL_DEVICE, FuHidDevice)
|
||||
49
plugins/hailuck/fu-hailuck-common.c
Normal file
49
plugins/hailuck/fu-hailuck-common.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-hailuck-common.h"
|
||||
|
||||
const gchar *
|
||||
fu_hailuck_cmd_to_string (guint8 cmd)
|
||||
{
|
||||
if (cmd == FU_HAILUCK_CMD_ERASE)
|
||||
return "erase";
|
||||
if (cmd == FU_HAILUCK_CMD_READ_BLOCK_START)
|
||||
return "read-block-start";
|
||||
if (cmd == FU_HAILUCK_CMD_WRITE_BLOCK_START)
|
||||
return "write-block-start";
|
||||
if (cmd == FU_HAILUCK_CMD_READ_BLOCK)
|
||||
return "read-block";
|
||||
if (cmd == FU_HAILUCK_CMD_WRITE_BLOCK)
|
||||
return "write-block";
|
||||
if (cmd == FU_HAILUCK_CMD_GET_STATUS)
|
||||
return "get-status";
|
||||
if (cmd == FU_HAILUCK_CMD_DETACH)
|
||||
return "detach";
|
||||
if (cmd == FU_HAILUCK_CMD_ATTACH)
|
||||
return "attach";
|
||||
if (cmd == FU_HAILUCK_CMD_WRITE_TP)
|
||||
return "write-tp";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_CHECK_CHECKSUM)
|
||||
return "i2c-check-checksum";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_ENTER_BL)
|
||||
return "i2c-enter-bl";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_ERASE)
|
||||
return "i2c-erase";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_PROGRAM)
|
||||
return "i2c-program";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_VERIFY_BLOCK)
|
||||
return "i2c-verify-block";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_VERIFY_CHECKSUM)
|
||||
return "i2c-verify-checksum";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_PROGRAMPASS)
|
||||
return "i2c-programpass";
|
||||
if (cmd == FU_HAILUCK_CMD_I2C_END_PROGRAM)
|
||||
return "i2c-end-program";
|
||||
return NULL;
|
||||
}
|
||||
32
plugins/hailuck/fu-hailuck-common.h
Normal file
32
plugins/hailuck/fu-hailuck-common.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define FU_HAILUCK_REPORT_ID_SHORT 0x05
|
||||
#define FU_HAILUCK_REPORT_ID_LONG 0x06
|
||||
|
||||
#define FU_HAILUCK_CMD_ERASE 0x45
|
||||
#define FU_HAILUCK_CMD_READ_BLOCK_START 0x52
|
||||
#define FU_HAILUCK_CMD_ATTACH 0x55 /* guessed */
|
||||
#define FU_HAILUCK_CMD_WRITE_BLOCK_START 0x57
|
||||
#define FU_HAILUCK_CMD_READ_BLOCK 0x72
|
||||
#define FU_HAILUCK_CMD_DETACH 0x75 /* guessed */
|
||||
#define FU_HAILUCK_CMD_WRITE_BLOCK 0x77
|
||||
#define FU_HAILUCK_CMD_GET_STATUS 0xA1
|
||||
#define FU_HAILUCK_CMD_WRITE_TP 0xD0 /* guessed */
|
||||
#define FU_HAILUCK_CMD_I2C_CHECK_CHECKSUM 0xF0
|
||||
#define FU_HAILUCK_CMD_I2C_ENTER_BL 0xF1
|
||||
#define FU_HAILUCK_CMD_I2C_ERASE 0xF2
|
||||
#define FU_HAILUCK_CMD_I2C_PROGRAM 0xF3
|
||||
#define FU_HAILUCK_CMD_I2C_VERIFY_BLOCK 0xF4
|
||||
#define FU_HAILUCK_CMD_I2C_VERIFY_CHECKSUM 0xF5
|
||||
#define FU_HAILUCK_CMD_I2C_PROGRAMPASS 0xF6
|
||||
#define FU_HAILUCK_CMD_I2C_END_PROGRAM 0xF7
|
||||
|
||||
const gchar *fu_hailuck_cmd_to_string (guint8 cmd);
|
||||
82
plugins/hailuck/fu-hailuck-kbd-device.c
Normal file
82
plugins/hailuck/fu-hailuck-kbd-device.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-hailuck-common.h"
|
||||
#include "fu-hailuck-kbd-device.h"
|
||||
#include "fu-hailuck-tp-device.h"
|
||||
|
||||
struct _FuHaiLuckKbdDevice {
|
||||
FuHidDevice parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuHaiLuckKbdDevice, fu_hailuck_kbd_device, FU_TYPE_HID_DEVICE)
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_kbd_device_detach (FuDevice *device, GError **error)
|
||||
{
|
||||
guint8 buf[6] = {
|
||||
FU_HAILUCK_REPORT_ID_SHORT,
|
||||
FU_HAILUCK_CMD_DETACH
|
||||
};
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
|
||||
if (!fu_hid_device_set_report (FU_HID_DEVICE (device),
|
||||
buf[0], buf, sizeof(buf), 1000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error))
|
||||
return FALSE;
|
||||
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_kbd_device_probe (FuUsbDevice *device, GError **error)
|
||||
{
|
||||
g_autofree gchar *devid = NULL;
|
||||
g_autoptr(FuHaiLuckTpDevice) tp_device = fu_hailuck_tp_device_new (FU_DEVICE (device));
|
||||
|
||||
/* add extra keyboard-specific GUID */
|
||||
devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&MODE_KBD",
|
||||
fu_usb_device_get_vid (device),
|
||||
fu_usb_device_get_pid (device));
|
||||
fu_device_add_instance_id (FU_DEVICE (device), devid);
|
||||
|
||||
/* add touchpad */
|
||||
if (!fu_device_probe (FU_DEVICE (tp_device), error))
|
||||
return FALSE;
|
||||
|
||||
/* assume the TP has the same version as the keyboard */
|
||||
fu_device_set_version (FU_DEVICE (tp_device),
|
||||
fu_device_get_version (FU_DEVICE (device)));
|
||||
fu_device_set_version_format (FU_DEVICE (tp_device),
|
||||
fu_device_get_version_format (FU_DEVICE (device)));
|
||||
fu_device_add_child (FU_DEVICE (device), FU_DEVICE (tp_device));
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_kbd_device_init (FuHaiLuckKbdDevice *self)
|
||||
{
|
||||
fu_device_set_firmware_size (FU_DEVICE (self), 0x4000);
|
||||
fu_device_set_protocol (FU_DEVICE (self), "com.hailuck.kbd");
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
fu_device_add_icon (FU_DEVICE (self), "input-keyboard");
|
||||
fu_hid_device_set_interface (FU_HID_DEVICE (self), 0x1);
|
||||
fu_device_set_remove_delay (FU_DEVICE (self),
|
||||
FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_kbd_device_class_init (FuHaiLuckKbdDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
|
||||
klass_device->detach = fu_hailuck_kbd_device_detach;
|
||||
klass_usb_device->probe = fu_hailuck_kbd_device_probe;
|
||||
}
|
||||
13
plugins/hailuck/fu-hailuck-kbd-device.h
Normal file
13
plugins/hailuck/fu-hailuck-kbd-device.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-plugin.h"
|
||||
#include "fu-hid-device.h"
|
||||
|
||||
#define FU_TYPE_HAILUCK_KBD_DEVICE (fu_hailuck_kbd_device_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuHaiLuckKbdDevice, fu_hailuck_kbd_device, FU, HAILUCK_KBD_DEVICE, FuHidDevice)
|
||||
85
plugins/hailuck/fu-hailuck-kbd-firmware.c
Normal file
85
plugins/hailuck/fu-hailuck-kbd-firmware.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-common.h"
|
||||
|
||||
#include "fu-hailuck-kbd-firmware.h"
|
||||
|
||||
struct _FuHaiLuckKbdFirmware {
|
||||
FuIhexFirmwareClass parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuHaiLuckKbdFirmware, fu_hailuck_kbd_firmware, FU_TYPE_IHEX_FIRMWARE)
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_kbd_firmware_parse (FuFirmware *firmware,
|
||||
GBytes *fw,
|
||||
guint64 addr_start,
|
||||
guint64 addr_end,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *records = fu_ihex_firmware_get_records (FU_IHEX_FIRMWARE (firmware));
|
||||
g_autoptr(FuFirmwareImage) img = NULL;
|
||||
g_autoptr(GByteArray) buf = g_byte_array_new ();
|
||||
g_autoptr(GBytes) fw_new = NULL;
|
||||
|
||||
for (guint j = 0; j < records->len; j++) {
|
||||
FuIhexFirmwareRecord *rcd = g_ptr_array_index (records, j);
|
||||
if (rcd->record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EOF)
|
||||
break;
|
||||
if (rcd->record_type != FU_IHEX_FIRMWARE_RECORD_TYPE_DATA) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"only record 0x0 supported, got 0x%02x",
|
||||
rcd->record_type);
|
||||
return FALSE;
|
||||
}
|
||||
if (rcd->addr + rcd->data->len > buf->len)
|
||||
fu_byte_array_set_size (buf, rcd->addr + rcd->data->len);
|
||||
if (!fu_memcpy_safe (buf->data, buf->len, rcd->addr,
|
||||
rcd->data->data, rcd->data->len, 0x0,
|
||||
rcd->data->len, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* set the main function executed on system init */
|
||||
if (buf->len > 0x37FD && buf->data[1] == 0x38 && buf->data[2] == 0x00) {
|
||||
buf->data[0] = buf->data[0x37FB];
|
||||
buf->data[1] = buf->data[0x37FC];
|
||||
buf->data[2] = buf->data[0x37FD];
|
||||
buf->data[0x37FB] = 0x00;
|
||||
buf->data[0x37FC] = 0x00;
|
||||
buf->data[0x37FD] = 0x00;
|
||||
}
|
||||
|
||||
/* whole image */
|
||||
fw_new = g_byte_array_free_to_bytes (g_steal_pointer (&buf));
|
||||
img = fu_firmware_image_new (fw_new);
|
||||
fu_firmware_add_image (firmware, img);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_kbd_firmware_init (FuHaiLuckKbdFirmware *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_kbd_firmware_class_init (FuHaiLuckKbdFirmwareClass *klass)
|
||||
{
|
||||
FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass);
|
||||
klass_firmware->parse = fu_hailuck_kbd_firmware_parse;
|
||||
}
|
||||
|
||||
FuFirmware *
|
||||
fu_hailuck_kbd_firmware_new (void)
|
||||
{
|
||||
return FU_FIRMWARE (g_object_new (FU_TYPE_HAILUCK_KBD_FIRMWARE, NULL));
|
||||
}
|
||||
14
plugins/hailuck/fu-hailuck-kbd-firmware.h
Normal file
14
plugins/hailuck/fu-hailuck-kbd-firmware.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-ihex-firmware.h"
|
||||
|
||||
#define FU_TYPE_HAILUCK_KBD_FIRMWARE (fu_hailuck_kbd_firmware_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuHaiLuckKbdFirmware, fu_hailuck_kbd_firmware, FU, HAILUCK_KBD_FIRMWARE, FuIhexFirmware)
|
||||
|
||||
FuFirmware *fu_hailuck_kbd_firmware_new (void);
|
||||
233
plugins/hailuck/fu-hailuck-tp-device.c
Normal file
233
plugins/hailuck/fu-hailuck-tp-device.c
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-chunk.h"
|
||||
#include "fu-hid-device.h"
|
||||
|
||||
#include "fu-hailuck-common.h"
|
||||
#include "fu-hailuck-tp-device.h"
|
||||
|
||||
struct _FuHaiLuckTpDevice {
|
||||
FuDevice parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FuHaiLuckTpDevice, fu_hailuck_tp_device, FU_TYPE_DEVICE)
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_tp_device_probe (FuDevice *device, GError **error)
|
||||
{
|
||||
FuDevice *parent = fu_device_get_parent (device);
|
||||
g_autofree gchar *devid1 = NULL;
|
||||
g_autofree gchar *devid2 = NULL;
|
||||
|
||||
devid1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
|
||||
fu_usb_device_get_vid (FU_USB_DEVICE (parent)),
|
||||
fu_usb_device_get_pid (FU_USB_DEVICE (parent)));
|
||||
fu_device_add_instance_id (device, devid1);
|
||||
devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&MODE_TP",
|
||||
fu_usb_device_get_vid (FU_USB_DEVICE (parent)),
|
||||
fu_usb_device_get_pid (FU_USB_DEVICE (parent)));
|
||||
fu_device_add_instance_id (device, devid2);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_tp_device_open (FuDevice *device, GError **error)
|
||||
{
|
||||
FuDevice *parent = fu_device_get_parent (device);
|
||||
return fu_device_open (parent, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_tp_device_close (FuDevice *device, GError **error)
|
||||
{
|
||||
FuDevice *parent = fu_device_get_parent (device);
|
||||
return fu_device_close (parent, error);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
guint8 type;
|
||||
guint8 success; /* if 0xff, then cmd-0x10 */
|
||||
} FuHailuckTpDeviceReq;
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_tp_device_cmd_cb (FuDevice *device, gpointer user_data, GError **error)
|
||||
{
|
||||
FuDevice *parent = fu_device_get_parent (device);
|
||||
FuHailuckTpDeviceReq *req = (FuHailuckTpDeviceReq *) user_data;
|
||||
guint8 buf[6] = {
|
||||
FU_HAILUCK_REPORT_ID_SHORT,
|
||||
FU_HAILUCK_CMD_GET_STATUS,
|
||||
req->type,
|
||||
};
|
||||
guint8 success_tmp = req->success;
|
||||
if (!fu_hid_device_set_report (FU_HID_DEVICE (parent), buf[0],
|
||||
buf, sizeof(buf), 1000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error))
|
||||
return FALSE;
|
||||
if (!fu_hid_device_get_report (FU_HID_DEVICE (parent), buf[0],
|
||||
buf, sizeof(buf), 2000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE |
|
||||
FU_HID_DEVICE_FLAG_ALLOW_TRUNC,
|
||||
error))
|
||||
return FALSE;
|
||||
if (success_tmp == 0xff)
|
||||
success_tmp = req->type - 0x10;
|
||||
if (buf[0] != FU_HAILUCK_REPORT_ID_SHORT || buf[1] != success_tmp) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"report mismatch for type=0x%02x[%s]: "
|
||||
"expected=0x%02x, received=0x%02x",
|
||||
req->type,
|
||||
fu_hailuck_cmd_to_string (req->type),
|
||||
success_tmp, buf[1]);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_hailuck_tp_device_write_firmware (FuDevice *device,
|
||||
FuFirmware *firmware,
|
||||
FwupdInstallFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
FuDevice *parent = fu_device_get_parent (device);
|
||||
const guint block_size = 1024;
|
||||
g_autoptr(GBytes) fw = NULL;
|
||||
g_autoptr(GPtrArray) chunks = NULL;
|
||||
FuHailuckTpDeviceReq req = {
|
||||
.type = 0xff,
|
||||
.success = 0xff,
|
||||
};
|
||||
|
||||
/* get default image */
|
||||
fw = fu_firmware_get_image_default_bytes (firmware, error);
|
||||
if (fw == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* erase */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
|
||||
req.type = FU_HAILUCK_CMD_I2C_ERASE;
|
||||
if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) {
|
||||
g_prefix_error (error, "failed to erase: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (10000);
|
||||
|
||||
/* write */
|
||||
fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
|
||||
chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, block_size);
|
||||
for (guint i = 0; i < chunks->len; i++) {
|
||||
FuChunk *chk = g_ptr_array_index (chunks, i);
|
||||
g_autoptr(GByteArray) buf = g_byte_array_new ();
|
||||
|
||||
/* write block */
|
||||
fu_byte_array_append_uint8 (buf, FU_HAILUCK_REPORT_ID_LONG);
|
||||
fu_byte_array_append_uint8 (buf, FU_HAILUCK_CMD_WRITE_TP);
|
||||
fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN);
|
||||
fu_byte_array_append_uint16 (buf, chk->address, G_LITTLE_ENDIAN);
|
||||
fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN);
|
||||
g_byte_array_append (buf, chk->data, chk->data_sz);
|
||||
fu_byte_array_append_uint8 (buf, 0xEE);
|
||||
fu_byte_array_append_uint8 (buf, 0xD2);
|
||||
fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN);
|
||||
fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN);
|
||||
fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN);
|
||||
if (buf->len != block_size + 16) {
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"packet mismatch: len=0x%04x, expected=0x%04x",
|
||||
buf->len, block_size + 16);
|
||||
return FALSE;
|
||||
}
|
||||
if (!fu_hid_device_set_report (FU_HID_DEVICE (parent), buf->data[0],
|
||||
buf->data, buf->len, 1000,
|
||||
FU_HID_DEVICE_FLAG_IS_FEATURE, error)) {
|
||||
g_prefix_error (error, "failed to write block 0x%x: ", i);
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (150 * 1000);
|
||||
|
||||
/* verify block */
|
||||
req.type = FU_HAILUCK_CMD_I2C_VERIFY_BLOCK;
|
||||
if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) {
|
||||
g_prefix_error (error, "failed to verify block 0x%x: ", i);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* update progress */
|
||||
fu_device_set_progress_full (device, i, chunks->len - 1);
|
||||
}
|
||||
g_usleep (50 * 1000);
|
||||
|
||||
/* end-program */
|
||||
req.type = FU_HAILUCK_CMD_I2C_END_PROGRAM;
|
||||
if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) {
|
||||
g_prefix_error (error, "failed to end program: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (50 * 1000);
|
||||
|
||||
/* verify checksum */
|
||||
req.type = FU_HAILUCK_CMD_I2C_VERIFY_CHECKSUM;
|
||||
if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) {
|
||||
g_prefix_error (error, "failed to verify: ");
|
||||
return FALSE;
|
||||
}
|
||||
g_usleep (50 * 1000);
|
||||
|
||||
/* signal that programming has completed */
|
||||
req.type = FU_HAILUCK_CMD_I2C_PROGRAMPASS;
|
||||
req.success = 0x0;
|
||||
if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) {
|
||||
g_prefix_error (error, "failed to program: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success! */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_tp_device_init (FuHaiLuckTpDevice *self)
|
||||
{
|
||||
fu_device_retry_set_delay (FU_DEVICE (self), 50); /* ms */
|
||||
fu_device_set_firmware_size (FU_DEVICE (self), 0x6018);
|
||||
fu_device_set_protocol (FU_DEVICE (self), "com.hailuck.tp");
|
||||
fu_device_set_logical_id (FU_DEVICE (self), "TP");
|
||||
fu_device_set_name (FU_DEVICE (self), "Touchpad");
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
|
||||
fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
|
||||
fu_device_add_icon (FU_DEVICE (self), "input-touchpad");
|
||||
fu_device_set_remove_delay (FU_DEVICE (self),
|
||||
FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_hailuck_tp_device_class_init (FuHaiLuckTpDeviceClass *klass)
|
||||
{
|
||||
FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
|
||||
klass_device->write_firmware = fu_hailuck_tp_device_write_firmware;
|
||||
klass_device->open = fu_hailuck_tp_device_open;
|
||||
klass_device->close = fu_hailuck_tp_device_close;
|
||||
klass_device->probe = fu_hailuck_tp_device_probe;
|
||||
}
|
||||
|
||||
FuHaiLuckTpDevice *
|
||||
fu_hailuck_tp_device_new (FuDevice *device)
|
||||
{
|
||||
FuHaiLuckTpDevice *self;
|
||||
self = g_object_new (FU_TYPE_HAILUCK_TP_DEVICE,
|
||||
"parent", device,
|
||||
NULL);
|
||||
return FU_HAILUCK_TP_DEVICE (self);
|
||||
}
|
||||
14
plugins/hailuck/fu-hailuck-tp-device.h
Normal file
14
plugins/hailuck/fu-hailuck-tp-device.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fu-plugin.h"
|
||||
|
||||
#define FU_TYPE_HAILUCK_TP_DEVICE (fu_hailuck_tp_device_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FuHaiLuckTpDevice, fu_hailuck_tp_device, FU, HAILUCK_TP_DEVICE, FuDevice)
|
||||
|
||||
FuHaiLuckTpDevice *fu_hailuck_tp_device_new (FuDevice *parent);
|
||||
23
plugins/hailuck/fu-plugin-hailuck.c
Normal file
23
plugins/hailuck/fu-plugin-hailuck.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-plugin-vfuncs.h"
|
||||
#include "fu-hash.h"
|
||||
|
||||
#include "fu-hailuck-bl-device.h"
|
||||
#include "fu-hailuck-kbd-device.h"
|
||||
#include "fu-hailuck-kbd-firmware.h"
|
||||
|
||||
void
|
||||
fu_plugin_init (FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
|
||||
fu_plugin_add_firmware_gtype (plugin, "hailuck", FU_TYPE_HAILUCK_KBD_FIRMWARE);
|
||||
fu_plugin_set_device_gtype (plugin, FU_TYPE_HAILUCK_BL_DEVICE);
|
||||
fu_plugin_set_device_gtype (plugin, FU_TYPE_HAILUCK_KBD_DEVICE);
|
||||
}
|
||||
25
plugins/hailuck/hailuck.quirk
Normal file
25
plugins/hailuck/hailuck.quirk
Normal file
@ -0,0 +1,25 @@
|
||||
# bootloader
|
||||
|
||||
[DeviceInstanceId=USB\VID_0603&PID_1020]
|
||||
Plugin = hailuck
|
||||
GType = FuHaiLuckBlDevice
|
||||
#Flags = is-bootloader
|
||||
|
||||
[DeviceInstanceId=USB\VID_258A&PID_001E]
|
||||
Plugin = hailuck
|
||||
GType = FuHaiLuckKbdDevice
|
||||
Vendor = PINE64
|
||||
CounterpartGuid = USB\VID_0603&PID_1020
|
||||
|
||||
[DeviceInstanceId=USB\VID_258A&PID_001E&MODE_KBD]
|
||||
Name = Keyboard
|
||||
|
||||
[DeviceInstanceId=USB\VID_258A&PID_001F]
|
||||
Plugin = hailuck
|
||||
GType = FuHaiLuckKbdDevice
|
||||
CounterpartGuid = USB\VID_0603&PID_1020
|
||||
|
||||
[DeviceInstanceId=USB\VID_258A&PID_000D]
|
||||
Plugin = hailuck
|
||||
GType = FuHaiLuckKbdDevice
|
||||
CounterpartGuid = USB\VID_0603&PID_1020
|
||||
34
plugins/hailuck/meson.build
Normal file
34
plugins/hailuck/meson.build
Normal file
@ -0,0 +1,34 @@
|
||||
cargs = ['-DG_LOG_DOMAIN="FuPluginNovatek"']
|
||||
|
||||
install_data([
|
||||
'hailuck.quirk',
|
||||
],
|
||||
install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
|
||||
)
|
||||
|
||||
shared_module('fu_plugin_hailuck',
|
||||
fu_hash,
|
||||
sources : [
|
||||
'fu-hailuck-common.c',
|
||||
'fu-hailuck-bl-device.c',
|
||||
'fu-hailuck-kbd-device.c',
|
||||
'fu-hailuck-kbd-firmware.c',
|
||||
'fu-hailuck-tp-device.c',
|
||||
'fu-plugin-hailuck.c',
|
||||
],
|
||||
include_directories : [
|
||||
root_incdir,
|
||||
fwupd_incdir,
|
||||
fwupdplugin_incdir,
|
||||
],
|
||||
install : true,
|
||||
install_dir: plugin_dir,
|
||||
link_with : [
|
||||
fwupd,
|
||||
fwupdplugin,
|
||||
],
|
||||
c_args : cargs,
|
||||
dependencies : [
|
||||
plugin_deps,
|
||||
],
|
||||
)
|
||||
@ -11,6 +11,7 @@ subdir('ebitdo')
|
||||
subdir('ep963x')
|
||||
subdir('fastboot')
|
||||
subdir('fresco-pd')
|
||||
subdir('hailuck')
|
||||
subdir('iommu')
|
||||
subdir('jabra')
|
||||
subdir('linux-lockdown')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user