/src/fwupd/plugins/synaptics-cape/fu-synaptics-cape-sngl-firmware.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2023 Synaptics Incorporated <simon.ho@synaptics.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | | #include "config.h" |
8 | | |
9 | | #include <string.h> |
10 | | |
11 | | #include "fu-synaptics-cape-sngl-firmware.h" |
12 | | #include "fu-synaptics-cape-struct.h" |
13 | | |
14 | | struct _FuSynapticsCapeSnglFirmware { |
15 | | FuSynapticsCapeFirmware parent_instance; |
16 | | }; |
17 | | |
18 | 0 | G_DEFINE_TYPE(FuSynapticsCapeSnglFirmware, |
19 | 0 | fu_synaptics_cape_sngl_firmware, |
20 | 0 | FU_TYPE_SYNAPTICS_CAPE_FIRMWARE) |
21 | 0 |
|
22 | 0 | static gboolean |
23 | 0 | fu_synaptics_cape_sngl_firmware_parse(FuFirmware *firmware, |
24 | 0 | GInputStream *stream, |
25 | 0 | FuFirmwareParseFlags flags, |
26 | 0 | GError **error) |
27 | 0 | { |
28 | 0 | FuSynapticsCapeSnglFirmware *self = FU_SYNAPTICS_CAPE_SNGL_FIRMWARE(firmware); |
29 | 0 | gsize streamsz = 0; |
30 | 0 | guint16 num_fw_file; |
31 | 0 | g_autoptr(FuStructSynapticsCapeSnglHdr) st = NULL; |
32 | 0 | g_autofree gchar *version_str = NULL; |
33 | | |
34 | | /* sanity check */ |
35 | 0 | if (!fu_input_stream_size(stream, &streamsz, error)) |
36 | 0 | return FALSE; |
37 | 0 | if ((guint32)streamsz % 4 != 0) { |
38 | 0 | g_set_error_literal(error, |
39 | 0 | FWUPD_ERROR, |
40 | 0 | FWUPD_ERROR_INVALID_FILE, |
41 | 0 | "data not aligned to 32 bits"); |
42 | 0 | return FALSE; |
43 | 0 | } |
44 | 0 | if (streamsz < 8) { |
45 | 0 | g_set_error_literal(error, |
46 | 0 | FWUPD_ERROR, |
47 | 0 | FWUPD_ERROR_INVALID_FILE, |
48 | 0 | "image is too small"); |
49 | 0 | return FALSE; |
50 | 0 | } |
51 | | |
52 | | /* unpack */ |
53 | 0 | st = fu_struct_synaptics_cape_sngl_hdr_parse_stream(stream, 0x0, error); |
54 | 0 | if (st == NULL) |
55 | 0 | return FALSE; |
56 | 0 | if (fu_struct_synaptics_cape_sngl_hdr_get_file_size(st) != streamsz) { |
57 | 0 | g_set_error_literal(error, |
58 | 0 | FWUPD_ERROR, |
59 | 0 | FWUPD_ERROR_INVALID_FILE, |
60 | 0 | "file size is incorrect"); |
61 | 0 | return FALSE; |
62 | 0 | } |
63 | | |
64 | | /* check CRC */ |
65 | 0 | if ((flags & FU_FIRMWARE_PARSE_FLAG_IGNORE_CHECKSUM) == 0) { |
66 | 0 | guint32 crc_calc = 0xFFFFFFFF; |
67 | 0 | g_autoptr(GInputStream) stream_tmp = NULL; |
68 | |
|
69 | 0 | stream_tmp = fu_partial_input_stream_new(stream, 8, G_MAXSIZE, error); |
70 | 0 | if (stream_tmp == NULL) |
71 | 0 | return FALSE; |
72 | 0 | if (!fu_input_stream_compute_crc32(stream_tmp, |
73 | 0 | FU_CRC_KIND_B32_STANDARD, |
74 | 0 | &crc_calc, |
75 | 0 | error)) |
76 | 0 | return FALSE; |
77 | 0 | if (crc_calc != fu_struct_synaptics_cape_sngl_hdr_get_file_crc(st)) { |
78 | 0 | g_set_error(error, |
79 | 0 | FWUPD_ERROR, |
80 | 0 | FWUPD_ERROR_INVALID_DATA, |
81 | 0 | "CRC did not match, got 0x%x, expected 0x%x", |
82 | 0 | fu_struct_synaptics_cape_sngl_hdr_get_file_crc(st), |
83 | 0 | crc_calc); |
84 | 0 | return FALSE; |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | 0 | fu_synaptics_cape_firmware_set_vid(FU_SYNAPTICS_CAPE_FIRMWARE(self), |
89 | 0 | fu_struct_synaptics_cape_sngl_hdr_get_vid(st)); |
90 | 0 | fu_synaptics_cape_firmware_set_pid(FU_SYNAPTICS_CAPE_FIRMWARE(self), |
91 | 0 | fu_struct_synaptics_cape_sngl_hdr_get_pid(st)); |
92 | 0 | version_str = fu_version_from_uint32(fu_struct_synaptics_cape_sngl_hdr_get_fw_version(st), |
93 | 0 | FWUPD_VERSION_FORMAT_QUAD); |
94 | 0 | fu_firmware_set_version(FU_FIRMWARE(self), version_str); |
95 | | |
96 | | /* add each file */ |
97 | 0 | num_fw_file = fu_struct_synaptics_cape_sngl_hdr_get_fw_file_num(st); |
98 | 0 | if (num_fw_file == 0) { |
99 | 0 | g_set_error_literal(error, |
100 | 0 | FWUPD_ERROR, |
101 | 0 | FWUPD_ERROR_INVALID_DATA, |
102 | 0 | "no image files found"); |
103 | 0 | return FALSE; |
104 | 0 | } |
105 | | |
106 | | /* success */ |
107 | 0 | return TRUE; |
108 | 0 | } |
109 | | |
110 | | static GByteArray * |
111 | | fu_synaptics_cape_sngl_firmware_write(FuFirmware *firmware, GError **error) |
112 | 0 | { |
113 | 0 | FuSynapticsCapeSnglFirmware *self = FU_SYNAPTICS_CAPE_SNGL_FIRMWARE(firmware); |
114 | 0 | g_autoptr(FuStructSynapticsCapeSnglHdr) st = fu_struct_synaptics_cape_sngl_hdr_new(); |
115 | | |
116 | | /* pack */ |
117 | 0 | fu_struct_synaptics_cape_sngl_hdr_set_vid( |
118 | 0 | st, |
119 | 0 | fu_synaptics_cape_firmware_get_vid(FU_SYNAPTICS_CAPE_FIRMWARE(self))); |
120 | 0 | fu_struct_synaptics_cape_sngl_hdr_set_pid( |
121 | 0 | st, |
122 | 0 | fu_synaptics_cape_firmware_get_pid(FU_SYNAPTICS_CAPE_FIRMWARE(self))); |
123 | | |
124 | | /* success */ |
125 | 0 | return g_steal_pointer(&st->buf); |
126 | 0 | } |
127 | | |
128 | | static void |
129 | | fu_synaptics_cape_sngl_firmware_init(FuSynapticsCapeSnglFirmware *self) |
130 | 0 | { |
131 | 0 | fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); |
132 | 0 | } |
133 | | |
134 | | static void |
135 | | fu_synaptics_cape_sngl_firmware_class_init(FuSynapticsCapeSnglFirmwareClass *klass) |
136 | 0 | { |
137 | 0 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
138 | 0 | firmware_class->parse = fu_synaptics_cape_sngl_firmware_parse; |
139 | 0 | firmware_class->write = fu_synaptics_cape_sngl_firmware_write; |
140 | 0 | } |