Codebase list fwupd / f05d047
Merge tag '1.3.4' into debian Release fwupd 1.3.4 Mario Limonciello 4 years ago
166 changed file(s) with 8883 addition(s) and 5458 deletion(s). Raw diff Collapse all Expand all
00 fwupd Release Notes
11
2 Write release entries:
2 0. Create release version
33
4 git log --format="%s" --cherry-pick --right-only 1.3.2... | grep -i -v trivial | grep -v Merge | sort | uniq
4 export release_ver=
5
6 1. Write release entries:
7
8 git log --format="%s" --cherry-pick --right-only $(git describe --tags --abbrev=0)..HEAD | grep -i -v trivial | grep -v Merge | sort | uniq
59 Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml
610 appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS
711
8 Update translations:
12 2. Update translations:
913
1014 ninja-build fwupd-pot
1115 tx push --source
1317 ninja-build fix-translations
1418 git add ../po/*.po
1519
16 2. Commit changes to git:
17
18 # MAKE SURE THIS IS CORRECT
19 export release_ver="1.3.3"
20 3. Commit changes to git:
2021
2122 git commit -a -m "Release fwupd ${release_ver}"
2223 git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}"
2425 git push --tags
2526 git push
2627
27 3. Generate the tarball:
28 4. Generate the tarball:
2829
2930 ninja dist
3031
31 3a. Generate the additional verification metadata
32 4a. Generate the additional verification metadata
3233
3334 gpg -b -a meson-dist/fwupd-${release_ver}.tar.xz
3435
35 4. Upload tarball:
36 5. Upload tarball:
3637
3738 scp meson-dist/fwupd-${release_ver}.tar.* hughsient@people.freedesktop.org:~/public_html/releases
38
39 5. Do post release version bump in meson.build
40
41 6. Commit changes:
42
43 git commit -a -m "trivial: post release version bump"
44 git push
1515 pkgver() {
1616 cd ${pkgname}
1717
18 VERSION=$(git describe | sed 's/-/.r/;s/-/./')
19 [ -z $VERSION ] && VERSION=$(head meson.build | grep ' version :' | cut -d \' -f2)
20
18 VERSION=$(./contrib/get-version.py | sed 's/-/.r/;s/-/./')
2119 echo $VERSION
2220 }
2321
+0
-71
contrib/add-capsule-header.py less more
0 #!/usr/bin/python3
1 #
2 # Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 #
4 # SPDX-License-Identifier: LGPL-2.1+
5
6 import sys
7 import uuid
8 import argparse
9 import struct
10
11 CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000
12 CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000
13 CAPSULE_FLAGS_INITIATE_RESET = 0x00040000
14
15 def main(args):
16
17 # parse GUID from command line
18 try:
19 guid = uuid.UUID(args.guid)
20 except ValueError as e:
21 print(e)
22 return 1
23 try:
24 with open(args.bin, 'rb') as f:
25 bin_data = f.read()
26 except FileNotFoundError as e:
27 print(e)
28 return 1
29
30 # check if already has header
31 hdrsz = struct.calcsize('<16sIII')
32 if len(bin_data) >= hdrsz:
33 hdr = struct.unpack('<16sIII', bin_data[:hdrsz])
34 imgsz = hdr[3]
35 if imgsz == len(bin_data):
36 print('Replacing existing CAPSULE_HEADER of:')
37 guid_mixed = uuid.UUID(bytes_le=hdr[0])
38 hdrsz_old = hdr[1]
39 flags = hdr[2]
40 print('GUID: %s' % guid_mixed)
41 print('HdrSz: 0x%04x' % hdrsz_old)
42 print('Flags: 0x%04x' % flags)
43 print('PayloadSz: 0x%04x' % imgsz)
44 bin_data = bin_data[hdrsz_old:]
45
46 # set header flags
47 flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET
48 if args.flags:
49 flags = int(args.flags, 16)
50
51 # build update capsule header
52 imgsz = hdrsz + len(bin_data)
53 hdr = struct.pack('<16sIII', guid.bytes_le, hdrsz, flags, imgsz)
54 with open(args.cap, 'wb') as f:
55 f.write(hdr + bin_data)
56 print('Wrote capsule %s' % args.cap)
57 print('GUID: %s' % guid)
58 print('HdrSz: 0x%04x' % hdrsz)
59 print('Flags: 0x%04x' % flags)
60 print('PayloadSz: 0x%04x' % imgsz)
61 return 0
62
63 parser = argparse.ArgumentParser(description='Add capsule header on firmware')
64 parser.add_argument('--guid', help='GUID of the device', required=True)
65 parser.add_argument('--bin', help='Path to the .bin file', required=True)
66 parser.add_argument('--cap', help='Output capsule file path', required=True)
67 parser.add_argument('--flags', help='Flags, e.g. 0x40000', default=None)
68 args = parser.parse_args()
69
70 sys.exit(main(args))
1010 #prepare
1111 export DEBFULLNAME="CI Builder"
1212 export DEBEMAIL="ci@travis-ci.org"
13 VERSION=`git describe | sed 's/-/+r/;s/-/+/'`
14 [ -z $VERSION ] && VERSION=`head meson.build | grep ' version :' | cut -d \' -f2`
13 VERSION=`./contrib/get-version.py | sed 's/-/+r/;s/-/+/'`
1514 rm -rf build/
1615 mkdir -p build
1716 shopt -s extglob
895895 <package />
896896 </distro>
897897 <distro id="debian">
898 <control />
899 <package variant="x86_64" />
900 <package variant="i386" />
901 </distro>
902 <distro id="ubuntu">
903 <control />
898 <control>
899 <inclusive>amd64</inclusive>
900 <inclusive>arm64</inclusive>
901 <inclusive>armhf</inclusive>
902 <inclusive>i386</inclusive>
903 </control>
904 <package variant="x86_64" />
905 <package variant="i386" />
906 </distro>
907 <distro id="ubuntu">
908 <control>
909 <inclusive>amd64</inclusive>
910 <inclusive>arm64</inclusive>
911 <inclusive>armhf</inclusive>
912 <inclusive>i386</inclusive>
913 </control>
904914 <package variant="x86_64" />
905915 </distro>
906916 </dependency>
13181328 <package>tpm2-tss-devel</package>
13191329 </distro>
13201330 <distro id="debian">
1321 <control />
1322 <package variant="x86_64" />
1323 <package variant="i386" />
1324 </distro>
1325 <distro id="ubuntu">
1326 <control />
1331 <control>
1332 <inclusive>amd64</inclusive>
1333 <inclusive>arm64</inclusive>
1334 <inclusive>armhf</inclusive>
1335 <inclusive>i386</inclusive>
1336 </control>
1337 <package variant="x86_64" />
1338 <package variant="i386" />
1339 </distro>
1340 <distro id="ubuntu">
1341 <control>
1342 <inclusive>amd64</inclusive>
1343 <inclusive>arm64</inclusive>
1344 <inclusive>armhf</inclusive>
1345 <inclusive>i386</inclusive>
1346 </control>
13271347 <package variant="x86_64" />
13281348 </distro>
13291349 </dependency>
1919 -Dplugin_synaptics=true $@
2020 ninja-build dist
2121 popd
22 VERSION=`meson introspect build --projectinfo | jq -r .version`
22 VERSION=`./contrib/get-version.py`
2323 mkdir -p $HOME/rpmbuild/SOURCES/
2424 mv build/meson-dist/fwupd-$VERSION.tar.xz $HOME/rpmbuild/SOURCES/
2525
2626 #generate a spec file
2727 sed "s,#VERSION#,$VERSION,;
28 s,#TARBALL_VERSION#,$VERSION,;
2829 s,#BUILD#,1,;
2930 s,#LONGDATE#,`date '+%a %b %d %Y'`,;
3031 s,#ALPHATAG#,alpha,;
+0
-87
contrib/firmware-packager/README.md less more
0 # Firmware Packager
1
2 This script is intended to make firmware updating easier until OEMs upload their firmware packages to the LVFS. It works by extracting the firmware binary contained in a Microsoft .exe file (intended for performing the firmware update from a Windows system) and repackaging it in a cab file usable by fwupd. The cab file can then be install using `fwupdmgr install`
3
4 ## Prerequisites
5
6 To run this script you will need
7
8 1. Python3.5, a standard install should include all packages you need
9 2. 7z (for extracting .exe files)
10 3. gcab (for creating the cab file)
11
12 ## Usage
13
14 To create a firmware package, you must supply, at a minimum:
15
16 1. A string ID to name the firmware (`--firmware-id`). You are free to choose this, but [fwupd.org](http://fwupd.org/vendors.html) recommends using "a reverse-DNS prefix similar to java" and to "always use a .firmware suffix" (e.g. net.queuecumber.DellTBT.firmware)
17 2. A short name for the firmware package, again you are free to choose this (`--firmware-name`).
18 3. The unique ID of the device that the firmware is intended for (`--device-unique-id`). This *must* match the unique ID from `fwupdmgr get-devices`
19 4. The firmware version (`--release-version`), try to match the manufacturers versioning scheme
20 5. The path to the executable file to repackage (`--exe`)
21 6. The path *relative to the root of the exe archive* of the .bin file to package (`--bin`). Use 7z or archive-manager to inspect the .exe file and find this path.
22 For example, if I want to package `dell-thunderbolt-firmware.exe` and I open the .exe with archive-manager and find that `Intel/tbt.bin` is the path to the
23 bin file inside the archive, I would pass `--exe dell-thunderbolt-firmware.exe --bin Intel/tbt.bin`
24 7. The path to the cab file to output (`--out`).
25
26 ## Documentation
27
28 `--firmware-name` Short name of the firmware package can be customized (e.g. DellTBT) **REQUIRED**
29
30 `--firmware-summary` One line description of the firmware package (e.g. Dell thunderbolt firmware)
31
32 `--firmware-description` Longer description of the firmware package. Theoretically this can include HTML but I haven't tried it
33
34 `--device-guid` GUID ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED**
35
36 `--firmware-homepage` Website for the firmware provider (e.g. http://www.dell.com)
37
38 `-contact-info` Email address of the firmware developer (e.g. someone@something.net)
39
40 `--developer-name` Name of the firmware developer (e.g. Dell) **REQUIRED**
41
42 `--release-version` Version number of the firmware package (e.g. 4.21.01.002) **REQUIRED**
43 `--release-description` Description of the firmware release, again this can theoretically include HTML but I didn't try it.
44
45 `--exe` Executable file to extract firmware from (e.g. `dell-thunderbolt-firmware.exe`) **REQUIRED**
46
47 `--bin` Path to the .bin file inside the executable to use as the firmware image', relative to the root of the archive (e.g. `Intel/tbt.bin`) **REQUIRED**
48
49 `--out` Output cab file path (e.g. `updates/firmware.cab`) **REQUIRED**
50
51 ## Example
52
53 Let's say we downloaded `Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe` (available [here](https://downloads.dell.com/FOLDER04421073M/1/Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe)) containing updated firmware for Dell laptops thunderbolt controllers. Since Dell hasn't made this available on the LVFS yet, we want to package and install it ourselves.
54
55 Opening the .exe with archive manager, we see it has a single folder: `Intel` and inside that, a set of firmware binaries (along with some microsoft junk). We pick the file `0x07BE_secure.bin` since we have a Dell XPS 9560 and that is its device string.
56
57 Next we use `fwupdmgr` to get the device ID for the thunderbolt controller:
58
59 ```
60 $ fwupdmgr get-devices
61 Thunderbolt Controller
62 Guid: 72533768-6a6c-5c06-994a-367374336810
63 DeviceID: 08001575
64 Plugin: thunderbolt
65 Flags: internal|allow-online
66 DeviceVendor: Intel
67 Version: 21.00
68 Created: 2017-08-16
69 ```
70 The GUID field contains what we are looking for
71
72 We can then run the firmware-packager with the following arguments:
73
74 ```
75 $ firmware-packager --firmware-id net.queuecumber.DellTBT.firmware --firmware-name DellTBT --device-unique-id 72533768-6a6c-5c06-994a-367374336810 --release-version 4.21.01.002 --exe ~/Downloads/Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe --bin Intel/0x07BE_secure.bin --out firmware.cab
76 Using temp directory /tmp/tmpoey6_zx_
77 Extracting firmware exe
78 Locating firmware bin
79 Creating metainfo
80 Cabbing firmware files
81 Done
82 ```
83 And we should have a firmware.cab that contains the packaged firmware. We can then install this firmware with
84 ```
85 $ fwupdmgr install firmware.cab
86 ```
+0
-122
contrib/firmware-packager/firmware-packager less more
0 #!/usr/bin/python3
1 #
2 # Copyright (C) 2017 Max Ehrlich max.ehr@gmail.com
3 #
4 # SPDX-License-Identifier: LGPL-2.1+
5 #
6
7 import argparse
8 import subprocess
9 import contextlib
10 import os
11 import shutil
12 import tempfile
13 import time
14
15
16 @contextlib.contextmanager
17 def cd(path):
18 prev_cwd = os.getcwd()
19 os.chdir(path)
20 yield
21 os.chdir(prev_cwd)
22
23 firmware_metainfo_template = """
24 <?xml version="1.0" encoding="UTF-8"?>
25 <component type="firmware">
26 <id>org.{developer_name}.guid{firmware_id}</id>
27 <name>{firmware_name}</name>
28 <summary>{firmware_summary}</summary>
29 <description>
30 {firmware_description}
31 </description>
32 <provides>
33 <firmware type="flashed">{device_guid}</firmware>
34 </provides>
35 <url type="homepage">{firmware_homepage}</url>
36 <metadata_license>CC0-1.0</metadata_license>
37 <project_license>proprietary</project_license>
38 <updatecontact>{contact_info}</updatecontact>
39 <developer_name>{developer_name}</developer_name>
40 <releases>
41 <release version="{release_version}" timestamp="{timestamp}">
42 <description>
43 {release_description}
44 </description>
45 </release>
46 </releases>
47 </component>
48 """
49
50
51 def make_firmware_metainfo(firmware_info, dst):
52 local_info = vars(firmware_info)
53 local_info["firmware_id"] = local_info["device_guid"][0:8]
54 firmware_metainfo = firmware_metainfo_template.format(**local_info, timestamp=time.time())
55
56 with open(os.path.join(dst, 'firmware.metainfo.xml'), 'w') as f:
57 f.write(firmware_metainfo)
58
59
60 def extract_exe(exe, dst):
61 command = ['7z', 'x', '-o{}'.format(dst), exe]
62 subprocess.check_call(command, stdout=subprocess.DEVNULL)
63
64
65 def get_firmware_bin(root, bin_path, dst):
66 with cd(root):
67 shutil.copy(bin_path, os.path.join(dst, 'firmware.bin'))
68
69
70 def create_firmware_cab(exe, folder):
71 with cd(folder):
72 if os.name == "nt":
73 directive = os.path.join (folder, "directive")
74 with open (directive, 'w') as wfd:
75 wfd.write('.OPTION EXPLICIT\r\n')
76 wfd.write('.Set CabinetNameTemplate=firmware.cab\r\n')
77 wfd.write('.Set DiskDirectory1=.\r\n')
78 wfd.write('firmware.bin\r\n')
79 wfd.write('firmware.metainfo.xml\r\n')
80 command = ['makecab.exe', '/f', directive]
81 else:
82 command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml']
83 subprocess.check_call(command)
84
85
86 def main(args):
87 with tempfile.TemporaryDirectory() as dir:
88 print('Using temp directory {}'.format(dir))
89
90 if args.exe:
91 print('Extracting firmware exe')
92 extract_exe(args.exe, dir)
93
94 print('Locating firmware bin')
95 get_firmware_bin(dir, args.bin, dir)
96
97 print('Creating metainfo')
98 make_firmware_metainfo(args, dir)
99
100 print('Cabbing firmware files')
101 create_firmware_cab(args, dir)
102
103 print('Done')
104 shutil.copy(os.path.join(dir, 'firmware.cab'), args.out)
105
106 parser = argparse.ArgumentParser(description='Create fwupd packaged from windows executables')
107 parser.add_argument('--firmware-name', help='Name of the firmware package can be customized (e.g. DellTBT)', required=True)
108 parser.add_argument('--firmware-summary', help='One line description of the firmware package')
109 parser.add_argument('--firmware-description', help='Longer description of the firmware package')
110 parser.add_argument('--device-guid', help='GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`', required=True)
111 parser.add_argument('--firmware-homepage', help='Website for the firmware provider')
112 parser.add_argument('--contact-info', help='Email address of the firmware developer')
113 parser.add_argument('--developer-name', help='Name of the firmware developer', required=True)
114 parser.add_argument('--release-version', help='Version number of the firmware package', required=True)
115 parser.add_argument('--release-description', help='Description of the firmware release')
116 parser.add_argument('--exe', help='(optional) Executable file to extract firmware from')
117 parser.add_argument('--bin', help='Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image', required=True)
118 parser.add_argument('--out', help='Output cab file path', required=True)
119 args = parser.parse_args()
120
121 main(args)
+0
-4
contrib/firmware-packager/meson.build less more
0 if get_option('firmware-packager')
1 install_data('firmware-packager',
2 install_dir : 'share/fwupd')
3 endif
0 # Firmware Packager
1
2 This script is intended to make firmware updating easier until OEMs upload their firmware packages to the LVFS. It works by extracting the firmware binary contained in a Microsoft .exe file (intended for performing the firmware update from a Windows system) and repackaging it in a cab file usable by fwupd. The cab file can then be install using `fwupdmgr install`
3
4 ## Prerequisites
5
6 To run this script you will need
7
8 1. Python3.5, a standard install should include all packages you need
9 2. 7z (for extracting .exe files)
10 3. gcab (for creating the cab file)
11
12 ## Usage
13
14 To create a firmware package, you must supply, at a minimum:
15
16 1. A string ID to name the firmware (`--firmware-id`). You are free to choose this, but [fwupd.org](http://fwupd.org/vendors.html) recommends using "a reverse-DNS prefix similar to java" and to "always use a .firmware suffix" (e.g. net.queuecumber.DellTBT.firmware)
17 2. A short name for the firmware package, again you are free to choose this (`--firmware-name`).
18 3. The unique ID of the device that the firmware is intended for (`--device-unique-id`). This *must* match the unique ID from `fwupdmgr get-devices`
19 4. The firmware version (`--release-version`), try to match the manufacturers versioning scheme
20 5. The path to the executable file to repackage (`--exe`)
21 6. The path *relative to the root of the exe archive* of the .bin file to package (`--bin`). Use 7z or archive-manager to inspect the .exe file and find this path.
22 For example, if I want to package `dell-thunderbolt-firmware.exe` and I open the .exe with archive-manager and find that `Intel/tbt.bin` is the path to the
23 bin file inside the archive, I would pass `--exe dell-thunderbolt-firmware.exe --bin Intel/tbt.bin`
24 7. The path to the cab file to output (`--out`).
25
26 ## Documentation
27
28 `--firmware-name` Short name of the firmware package can be customized (e.g. DellTBT) **REQUIRED**
29
30 `--firmware-summary` One line description of the firmware package (e.g. Dell thunderbolt firmware)
31
32 `--firmware-description` Longer description of the firmware package. Theoretically this can include HTML but I haven't tried it
33
34 `--device-guid` GUID ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED**
35
36 `--firmware-homepage` Website for the firmware provider (e.g. http://www.dell.com)
37
38 `-contact-info` Email address of the firmware developer (e.g. someone@something.net)
39
40 `--developer-name` Name of the firmware developer (e.g. Dell) **REQUIRED**
41
42 `--release-version` Version number of the firmware package (e.g. 4.21.01.002) **REQUIRED**
43 `--release-description` Description of the firmware release, again this can theoretically include HTML but I didn't try it.
44
45 `--exe` Executable file to extract firmware from (e.g. `dell-thunderbolt-firmware.exe`) **REQUIRED**
46
47 `--bin` Path to the .bin file inside the executable to use as the firmware image', relative to the root of the archive (e.g. `Intel/tbt.bin`) **REQUIRED**
48
49 `--out` Output cab file path (e.g. `updates/firmware.cab`) **REQUIRED**
50
51 ## Example
52
53 Let's say we downloaded `Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe` (available [here](https://downloads.dell.com/FOLDER04421073M/1/Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe)) containing updated firmware for Dell laptops thunderbolt controllers. Since Dell hasn't made this available on the LVFS yet, we want to package and install it ourselves.
54
55 Opening the .exe with archive manager, we see it has a single folder: `Intel` and inside that, a set of firmware binaries (along with some microsoft junk). We pick the file `0x07BE_secure.bin` since we have a Dell XPS 9560 and that is its device string.
56
57 Next we use `fwupdmgr` to get the device ID for the thunderbolt controller:
58
59 ```
60 $ fwupdmgr get-devices
61 Thunderbolt Controller
62 Guid: 72533768-6a6c-5c06-994a-367374336810
63 DeviceID: 08001575
64 Plugin: thunderbolt
65 Flags: internal|allow-online
66 DeviceVendor: Intel
67 Version: 21.00
68 Created: 2017-08-16
69 ```
70 The GUID field contains what we are looking for
71
72 We can then run the firmware-packager with the following arguments:
73
74 ```
75 $ firmware-packager --firmware-id net.queuecumber.DellTBT.firmware --firmware-name DellTBT --device-unique-id 72533768-6a6c-5c06-994a-367374336810 --release-version 4.21.01.002 --exe ~/Downloads/Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe --bin Intel/0x07BE_secure.bin --out firmware.cab
76 Using temp directory /tmp/tmpoey6_zx_
77 Extracting firmware exe
78 Locating firmware bin
79 Creating metainfo
80 Cabbing firmware files
81 Done
82 ```
83 And we should have a firmware.cab that contains the packaged firmware. We can then install this firmware with
84 ```
85 $ fwupdmgr install firmware.cab
86 ```
0 #!/usr/bin/python3
1 #
2 # Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 #
4 # SPDX-License-Identifier: LGPL-2.1+
5
6 import sys
7 import uuid
8 import argparse
9 import ctypes
10
11 CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000
12 CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000
13 CAPSULE_FLAGS_INITIATE_RESET = 0x00040000
14
15 def add_header(infile, outfile, gd, fl=None):
16 # parse GUID from command line
17 try:
18 guid = uuid.UUID(gd)
19 except ValueError as e:
20 print(e)
21 return 1
22 import struct
23 try:
24 with open(infile, 'rb') as f:
25 bin_data = f.read()
26 except FileNotFoundError as e:
27 print(e)
28 return 1
29
30 # check if already has header
31 hdrsz = struct.calcsize('<16sIII')
32 if len(bin_data) >= hdrsz:
33 hdr = struct.unpack('<16sIII', bin_data[:hdrsz])
34 imgsz = hdr[3]
35 if imgsz == len(bin_data):
36 print('Replacing existing CAPSULE_HEADER of:')
37 guid_mixed = uuid.UUID(bytes_le=hdr[0])
38 hdrsz_old = hdr[1]
39 flags = hdr[2]
40 print('GUID: %s' % guid_mixed)
41 print('HdrSz: 0x%04x' % hdrsz_old)
42 print('Flags: 0x%04x' % flags)
43 print('PayloadSz: 0x%04x' % imgsz)
44 bin_data = bin_data[hdrsz_old:]
45
46 # set header flags
47 flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
48 if fl:
49 flags = int(fl, 16)
50
51 # build update capsule header
52 hdrsz = 4096
53 imgsz = hdrsz + len(bin_data)
54 hdr = ctypes.create_string_buffer(hdrsz)
55 struct.pack_into('<16sIII', hdr, 0, guid.bytes_le, hdrsz, flags, imgsz)
56 with open(outfile, 'wb') as f:
57 f.write(hdr)
58 f.write(bin_data)
59 print('Wrote capsule %s' % outfile)
60 print('GUID: %s' % guid)
61 print('HdrSz: 0x%04x' % hdrsz)
62 print('Flags: 0x%04x' % flags)
63 print('PayloadSz: 0x%04x' % imgsz)
64 return 0
65
66 if __name__ == '__main__':
67 parser = argparse.ArgumentParser(description='Add capsule header on firmware')
68 parser.add_argument('--guid', help='GUID of the device', required=True)
69 parser.add_argument('--bin', help='Path to the .bin file', required=True)
70 parser.add_argument('--cap', help='Output capsule file path', required=True)
71 parser.add_argument('--flags', help='Flags, e.g. 0x40000', default=None)
72 args = parser.parse_args()
73
74 sys.exit(add_header(args.bin, args.cap, args.guid, args.flags))
0 #!/usr/bin/python3
1 #
2 # Copyright (C) 2017 Max Ehrlich max.ehr@gmail.com
3 #
4 # SPDX-License-Identifier: LGPL-2.1+
5 #
6
7 import argparse
8 import subprocess
9 import contextlib
10 import os
11 import shutil
12 import tempfile
13 import time
14
15
16 @contextlib.contextmanager
17 def cd(path):
18 prev_cwd = os.getcwd()
19 os.chdir(path)
20 yield
21 os.chdir(prev_cwd)
22
23 firmware_metainfo_template = """
24 <?xml version="1.0" encoding="UTF-8"?>
25 <component type="firmware">
26 <id>org.{developer_name}.guid{firmware_id}</id>
27 <name>{firmware_name}</name>
28 <summary>{firmware_summary}</summary>
29 <description>
30 {firmware_description}
31 </description>
32 <provides>
33 <firmware type="flashed">{device_guid}</firmware>
34 </provides>
35 <url type="homepage">{firmware_homepage}</url>
36 <metadata_license>CC0-1.0</metadata_license>
37 <project_license>proprietary</project_license>
38 <updatecontact>{contact_info}</updatecontact>
39 <developer_name>{developer_name}</developer_name>
40 <releases>
41 <release version="{release_version}" timestamp="{timestamp}">
42 <description>
43 {release_description}
44 </description>
45 </release>
46 </releases>
47 </component>
48 """
49
50
51 def make_firmware_metainfo(firmware_info, dst):
52 local_info = vars(firmware_info)
53 local_info["firmware_id"] = local_info["device_guid"][0:8]
54 firmware_metainfo = firmware_metainfo_template.format(**local_info, timestamp=time.time())
55
56 with open(os.path.join(dst, 'firmware.metainfo.xml'), 'w') as f:
57 f.write(firmware_metainfo)
58
59
60 def extract_exe(exe, dst):
61 command = ['7z', 'x', '-o{}'.format(dst), exe]
62 subprocess.check_call(command, stdout=subprocess.DEVNULL)
63
64
65 def get_firmware_bin(root, bin_path, dst):
66 with cd(root):
67 shutil.copy(bin_path, os.path.join(dst, 'firmware.bin'))
68
69
70 def create_firmware_cab(exe, folder):
71 with cd(folder):
72 if os.name == "nt":
73 directive = os.path.join (folder, "directive")
74 with open (directive, 'w') as wfd:
75 wfd.write('.OPTION EXPLICIT\r\n')
76 wfd.write('.Set CabinetNameTemplate=firmware.cab\r\n')
77 wfd.write('.Set DiskDirectory1=.\r\n')
78 wfd.write('firmware.bin\r\n')
79 wfd.write('firmware.metainfo.xml\r\n')
80 command = ['makecab.exe', '/f', directive]
81 else:
82 command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml']
83 subprocess.check_call(command)
84
85
86 def main(args):
87 with tempfile.TemporaryDirectory() as dir:
88 print('Using temp directory {}'.format(dir))
89
90 if args.exe:
91 print('Extracting firmware exe')
92 extract_exe(args.exe, dir)
93
94 print('Locating firmware bin')
95 get_firmware_bin(dir, args.bin, dir)
96
97 print('Creating metainfo')
98 make_firmware_metainfo(args, dir)
99
100 print('Cabbing firmware files')
101 create_firmware_cab(args, dir)
102
103 print('Done')
104 shutil.copy(os.path.join(dir, 'firmware.cab'), args.out)
105
106 if __name__ == '__main__':
107 parser = argparse.ArgumentParser(description='Create fwupd packaged from windows executables')
108 parser.add_argument('--firmware-name', help='Name of the firmware package can be customized (e.g. DellTBT)', required=True)
109 parser.add_argument('--firmware-summary', help='One line description of the firmware package')
110 parser.add_argument('--firmware-description', help='Longer description of the firmware package')
111 parser.add_argument('--device-guid', help='GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`', required=True)
112 parser.add_argument('--firmware-homepage', help='Website for the firmware provider')
113 parser.add_argument('--contact-info', help='Email address of the firmware developer')
114 parser.add_argument('--developer-name', help='Name of the firmware developer', required=True)
115 parser.add_argument('--release-version', help='Version number of the firmware package', required=True)
116 parser.add_argument('--release-description', help='Description of the firmware release')
117 parser.add_argument('--exe', help='(optional) Executable file to extract firmware from')
118 parser.add_argument('--bin', help='Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image', required=True)
119 parser.add_argument('--out', help='Output cab file path', required=True)
120 args = parser.parse_args()
121
122 main(args)
0 #!/usr/bin/python3
1 #
2 # Copyright (C) 2019 Mario Limonciello <mario.limonciello@dell.com>
3 #
4 # SPDX-License-Identifier: LGPL-2.1+
5
6 import dbus
7 import os.path
8 import sys
9 import tempfile
10 import gi
11 gi.require_version('Fwupd', '2.0')
12 from gi.repository import Fwupd #pylint: disable=wrong-import-position
13 from simple_client import install, check_exists
14 from add_capsule_header import add_header
15 from firmware_packager import make_firmware_metainfo, create_firmware_cab
16
17 class Variables:
18 def __init__(self, device_guid, version):
19 self.device_guid = device_guid
20 self.developer_name = "Dell Inc"
21 self.firmware_name = "New firmware"
22 self.firmware_summary = "Unknown"
23 self.firmware_description = "Unknown"
24 self.firmware_homepage = "https://support.dell.com"
25 self.contact_info = "Unknown"
26 self.release_version = version
27 self.release_description = "Unknown"
28
29 def parse_args():
30 """Parse arguments for this client"""
31 import argparse
32 parser = argparse.ArgumentParser(description="Interact with fwupd daemon")
33 parser.add_argument('exe', nargs='?', help='exe file')
34 parser.add_argument('deviceid', nargs='?',
35 help='DeviceID to operate on(optional)')
36 args = parser.parse_args()
37 return args
38
39 def generate_cab(infile, directory, guid, version):
40 output = os.path.join(directory, "firmware.bin")
41 ret = add_header(infile, output, guid)
42 if ret:
43 sys.exit(ret)
44 variables = Variables(guid, version)
45 make_firmware_metainfo(variables, directory)
46 create_firmware_cab(variables, directory)
47 cab = os.path.join(directory, "firmware.cab")
48 print("Generated CAB file %s" % cab)
49 return cab
50
51 def find_uefi_device(client, deviceid):
52 devices = client.get_devices()
53 for item in devices:
54 #match the device we were given
55 if deviceid:
56 if item.get_id() != deviceid:
57 continue
58 # internal
59 if not item.has_flag(1 << 0):
60 continue
61 # needs reboot
62 if not item.has_flag(1 << 8):
63 continue
64 # return the first hit for UEFI plugin
65 if item.get_plugin() == 'uefi':
66 print("Installing to %s" % item.get_name())
67 return item.get_guid_default(),item.get_id(),item.get_version()
68 print("Couldn't find any UEFI devices")
69 sys.exit(1)
70
71 def prompt_reboot():
72 print("An update requires a reboot to complete")
73 while True:
74 res = input("Restart now? (Y/N) ")
75 if res.lower() == 'n':
76 print("Reboot your machine manually to finish the update.")
77 break
78 if res.lower() != 'y':
79 continue
80 #reboot using logind
81 obj = dbus.SystemBus().get_object('org.freedesktop.login1',
82 '/org/freedesktop/login1')
83 obj.Reboot(True, dbus_interface='org.freedesktop.login1.Manager')
84
85 if __name__ == '__main__':
86 ARGS = parse_args()
87 CLIENT = Fwupd.Client()
88 CLIENT.connect()
89 check_exists(ARGS.exe)
90 directory = tempfile.mkdtemp()
91 guid, deviceid, version=find_uefi_device(CLIENT, ARGS.deviceid)
92 cab = generate_cab(ARGS.exe, directory, guid, version)
93 install(CLIENT, cab, deviceid, True, True)
94 prompt_reboot()
0 if get_option('firmware-packager')
1 install_data('firmware_packager.py',
2 install_dir : 'share/fwupd')
3 install_data('simple_client.py',
4 install_dir : 'share/fwupd')
5 install_data('add_capsule_header.py',
6 install_dir : 'share/fwupd')
7 install_data('install_dell_bios_exe.py',
8 install_dir : 'share/fwupd')
9 endif
0 #!/usr/bin/python3
1 # SPDX-License-Identifier: LGPL-2.1+
2 """A simple fwupd frontend"""
3 import sys
4 import os
5 import gi
6 from gi.repository import GLib
7 gi.require_version('Fwupd', '2.0')
8 from gi.repository import Fwupd #pylint: disable=wrong-import-position
9
10 class Progress():
11 """Class to track the signal changes of progress events"""
12 def __init__(self):
13 self.device = None
14 self.status = None
15 self.percent = 0
16 self.erase = 0
17
18 def device_changed(self, new_device):
19 """Indicate new device string to track"""
20 if self.device != new_device:
21 self.device = new_device
22 print("\nUpdating %s" % self.device)
23
24 def status_changed(self, percent, status):
25 """Indicate new status string or % complete to track"""
26 if self.status != status or self.percent != percent:
27 for i in range(0, self.erase):
28 sys.stdout.write("\b \b")
29 self.status = status
30 self.percent = percent
31 status_str = "["
32 for i in range(0, 50):
33 if i < percent/2:
34 status_str += '*'
35 else:
36 status_str += ' '
37 status_str += "] %d%% %s" %(percent, status)
38 self.erase = len(status_str)
39 sys.stdout.write(status_str)
40 sys.stdout.flush()
41 if 'idle' in status:
42 sys.stdout.write("\n")
43
44 def parse_args():
45 """Parse arguments for this client"""
46 import argparse
47 parser = argparse.ArgumentParser(description="Interact with fwupd daemon")
48 parser.add_argument("--allow-older", action="store_true",
49 help="Install older payloads(default False)")
50 parser.add_argument("--allow-reinstall", action="store_true",
51 help="Reinstall payloads(default False)")
52 parser.add_argument("command", choices=["get-devices",
53 "get-details",
54 "install"], help="What to do")
55 parser.add_argument('cab', nargs='?', help='CAB file')
56 parser.add_argument('deviceid', nargs='?',
57 help='DeviceID to operate on(optional)')
58 args = parser.parse_args()
59 return args
60
61 def get_devices(client):
62 """Use fwupd client to fetch devices"""
63 devices = client.get_devices()
64 for item in devices:
65 print(item.to_string())
66
67 def get_details(client, cab):
68 """Use fwupd client to fetch details for a CAB file"""
69 devices = client.get_details(cab, None)
70 for device in devices:
71 print(device.to_string())
72
73 def status_changed(client, spec, progress): #pylint: disable=unused-argument
74 """Signal emitted by fwupd daemon indicating status changed"""
75 progress.status_changed(client.get_percentage(),
76 Fwupd.status_to_string(client.get_status()))
77
78 def device_changed(client, device, progress): #pylint: disable=unused-argument
79 """Signal emitted by fwupd daemon indicating active device changed"""
80 progress.device_changed(device.get_name())
81
82 def install(client, cab, target, older, reinstall):
83 """Use fwupd client to install CAB file to applicable devices"""
84 # FWUPD_DEVICE_ID_ANY
85 if not target:
86 target = '*'
87 flags = Fwupd.InstallFlags.NONE
88 if older:
89 flags |= Fwupd.InstallFlags.ALLOW_OLDER
90 if reinstall:
91 flags |= Fwupd.InstallFlags.ALLOW_REINSTALL
92 progress = Progress()
93 parent = super(client.__class__, client)
94 parent.connect('device-changed', device_changed, progress)
95 parent.connect('notify::percentage', status_changed, progress)
96 parent.connect('notify::status', status_changed, progress)
97 try:
98 client.install(target, cab, flags, None)
99 except GLib.Error as glib_err: #pylint: disable=catching-non-exception
100 progress.status_changed(0, 'idle')
101 print("%s" % glib_err)
102 sys.exit(1)
103 print("\n")
104
105 def check_exists(cab):
106 """Check that CAB file exists"""
107 if not cab:
108 print("Need to specify payload")
109 sys.exit(1)
110 if not os.path.isfile(cab):
111 print("%s doesn't exist or isn't a file" % cab)
112 sys.exit(1)
113
114 if __name__ == '__main__':
115 ARGS = parse_args()
116 CLIENT = Fwupd.Client()
117 CLIENT.connect()
118
119 if ARGS.command == "get-devices":
120 get_devices(CLIENT)
121 elif ARGS.command == "get-details":
122 check_exists(ARGS.cab)
123 get_details(CLIENT, ARGS.cab)
124 elif ARGS.command == "install":
125 check_exists(ARGS.cab)
126 install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall)
55 %global json_glib_version 1.1.1
66
77 %define alphatag #ALPHATAG#
8 %define tarball_version #TARBALL_VERSION#
89
910 %global enable_ci 0
1011 %global enable_tests 1
3536 Summary: Firmware update daemon
3637 Name: fwupd
3738 Version: #VERSION#
38 Release: 0.#BUILD#%{?alphatag}%{?dist}
39 Release: 999.#BUILD#%{?alphatag}%{?dist}
3940 License: LGPLv2+
4041 URL: https://github.com/fwupd/fwupd
41 Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz
42 Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{tarball_version}.tar.xz
4243
4344 BuildRequires: gettext
4445 BuildRequires: glib2-devel >= %{glib2_version}
135136 Data files for installed tests.
136137
137138 %prep
138 %autosetup -p1
139 %autosetup -p1 -n %{name}-%{tarball_version}
139140
140141 %build
141142
214215 # delete most files from the subproject
215216 rm ${RPM_BUILD_ROOT}%{_includedir}/libflashrom.h
216217 rm ${RPM_BUILD_ROOT}%{_libdir}/libflashrom.so
217 rm ${RPM_BUILD_ROOT}%{_libdir}/pkgconfig/libflashrom.pc
218 rm ${RPM_BUILD_ROOT}%{_libdir}/pkgconfig/flashrom.pc
218219 rm ${RPM_BUILD_ROOT}%{_sbindir}/flashrom
219220 %endif
220221
281282 %{_datadir}/man/man1/fwupdmgr.1.gz
282283 %{_datadir}/metainfo/org.freedesktop.fwupd.metainfo.xml
283284 %{_datadir}/icons/hicolor/scalable/apps/org.freedesktop.fwupd.svg
284 %{_datadir}/fwupd/firmware-packager
285 %{_datadir}/fwupd/firmware_packager.py
286 %{_datadir}/fwupd/simple_client.py
287 %{_datadir}/fwupd/add_capsule_header.py
288 %{_datadir}/fwupd/install_dell_bios_exe.py
285289 %{_unitdir}/fwupd-offline-update.service
286290 %{_unitdir}/fwupd.service
287291 %{_unitdir}/fwupd-refresh.service
348352 %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi.so
349353 %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_recovery.so
350354 %endif
351 %{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so
355 %{_libdir}/fwupd-plugins-3/libfu_plugin_logitech_hidpp.so
352356 %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so
353357 %{_libdir}/fwupd-plugins-3/libfu_plugin_vli_usbhub.so
354358 %{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so
0 #!/usr/bin/python3
1 #
2 # Copyright (C) 2019 Dell, Inc.
3 #
4 # SPDX-License-Identifier: LGPL-2.1+
5 #
6
7 import xml.etree.ElementTree as etree
8 import os
9 import subprocess
10
11 def sanitize_for_ci(version):
12 if not 'CI' in os.environ:
13 return version
14 OS=os.getenv('OS')
15 if not OS:
16 return version
17 if "fedora" in OS:
18 return version.replace('-','.')
19 return version
20
21 def get_version_git():
22 try:
23 version = subprocess.check_output(['git', 'describe'], stderr=subprocess.DEVNULL)
24 return version.strip().decode('utf-8')
25 except (subprocess.CalledProcessError, PermissionError, FileNotFoundError):
26 return ''
27
28 def get_version():
29 tree = etree.parse(os.path.join("data", "org.freedesktop.fwupd.metainfo.xml"))
30 version = ''
31 for child in tree.findall('releases'):
32 for release in child:
33 if not "version" in release.attrib:
34 continue
35 if release.attrib['version'] > version:
36 version = release.attrib['version']
37 return version
38
39 if __name__ == '__main__':
40
41 version = get_version_git()
42 if version:
43 version = sanitize_for_ci(version)
44 else:
45 version = get_version()
46 print(version)
0 subdir('firmware-packager')
0 subdir('firmware_packager')
+0
-126
contrib/simple_client.py less more
0 #!/usr/bin/python3
1 # SPDX-License-Identifier: LGPL-2.1+
2 """A simple fwupd frontend"""
3 import sys
4 import os
5 import gi
6 from gi.repository import GLib
7 gi.require_version('Fwupd', '2.0')
8 from gi.repository import Fwupd #pylint: disable=wrong-import-position
9
10 class Progress():
11 """Class to track the signal changes of progress events"""
12 def __init__(self):
13 self.device = None
14 self.status = None
15 self.percent = 0
16 self.erase = 0
17
18 def device_changed(self, new_device):
19 """Indicate new device string to track"""
20 if self.device != new_device:
21 self.device = new_device
22 print("\nUpdating %s" % self.device)
23
24 def status_changed(self, percent, status):
25 """Indicate new status string or % complete to track"""
26 if self.status != status or self.percent != percent:
27 for i in range(0, self.erase):
28 sys.stdout.write("\b \b")
29 self.status = status
30 self.percent = percent
31 status_str = "["
32 for i in range(0, 50):
33 if i < percent/2:
34 status_str += '*'
35 else:
36 status_str += ' '
37 status_str += "] %d%% %s" %(percent, status)
38 status_str.erase = len(status_str)
39 sys.stdout.write(status_str)
40 sys.stdout.flush()
41 if 'idle' in status:
42 sys.stdout.write("\n")
43
44 def parse_args():
45 """Parse arguments for this client"""
46 import argparse
47 parser = argparse.ArgumentParser(description="Interact with fwupd daemon")
48 parser.add_argument("--allow-older", action="store_true",
49 help="Install older payloads(default False)")
50 parser.add_argument("--allow-reinstall", action="store_true",
51 help="Reinstall payloads(default False)")
52 parser.add_argument("command", choices=["get-devices",
53 "get-details",
54 "install"], help="What to do")
55 parser.add_argument('cab', nargs='?', help='CAB file')
56 parser.add_argument('deviceid', nargs='?',
57 help='DeviceID to operate on(optional)')
58 args = parser.parse_args()
59 return args
60
61 def get_devices(client):
62 """Use fwupd client to fetch devices"""
63 devices = client.get_devices()
64 for item in devices:
65 print(item.to_string())
66
67 def get_details(client, cab):
68 """Use fwupd client to fetch details for a CAB file"""
69 devices = client.get_details(cab, None)
70 for device in devices:
71 print(device.to_string())
72
73 def status_changed(client, spec, progress): #pylint: disable=unused-argument
74 """Signal emitted by fwupd daemon indicating status changed"""
75 progress.status_changed(client.get_percentage(),
76 Fwupd.status_to_string(client.get_status()))
77
78 def device_changed(client, device, progress): #pylint: disable=unused-argument
79 """Signal emitted by fwupd daemon indicating active device changed"""
80 progress.device_changed(device.get_name())
81
82 def install(client, cab, target, older, reinstall):
83 """Use fwupd client to install CAB file to applicable devices"""
84 # FWUPD_DEVICE_ID_ANY
85 if not target:
86 target = '*'
87 flags = Fwupd.InstallFlags.NONE
88 if older:
89 flags |= Fwupd.InstallFlags.ALLOW_OLDER
90 if reinstall:
91 flags |= Fwupd.InstallFlags.ALLOW_REINSTALL
92 progress = Progress()
93 parent = super(client.__class__, client)
94 parent.connect('device-changed', device_changed, progress)
95 parent.connect('notify::percentage', status_changed, progress)
96 parent.connect('notify::status', status_changed, progress)
97 try:
98 client.install(target, cab, flags, None)
99 except GLib.Error as glib_err: #pylint: disable=catching-non-exception
100 progress.status_changed(0, 'idle')
101 print("%s" % glib_err)
102 sys.exit(1)
103
104 def check_cab(cab):
105 """Check that CAB file exists"""
106 if not cab:
107 print("Need to specify payload")
108 sys.exit(1)
109 if not os.path.isfile(cab):
110 print("%s doesn't exist or isn't a file" % cab)
111 sys.exit(1)
112
113 if __name__ == '__main__':
114 ARGS = parse_args()
115 CLIENT = Fwupd.Client()
116 CLIENT.connect()
117
118 if ARGS.command == "get-devices":
119 get_devices(CLIENT)
120 elif ARGS.command == "get-details":
121 check_cab(ARGS.cab)
122 get_details(CLIENT, ARGS.cab)
123 elif ARGS.command == "install":
124 check_cab(ARGS.cab)
125 install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall)
117117 test.add_file('0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab', '2.0.7')
118118 tests.append(test)
119119
120 # Logitech Unifying Receiver (RQR12) using 'unifying'
120 # Logitech Unifying Receiver (RQR12) using logitech_hidpp
121121 test = Test('UnifyingRQR12', '9d131a0c-a606-580f-8eda-80587250b8d6')
122122 test.add_file('6e5ab5961ec4c577bff198ebb465106e979cf686-Logitech-Unifying-RQR12.05_B0028.cab', 'RQR12.05_B0028')
123123 test.add_file('938fec082652c603a1cdafde7cd25d76baadc70d-Logitech-Unifying-RQR12.07_B0029.cab', 'RQR12.07_B0029')
124124 tests.append(test)
125125
126 # Logitech Unifying Receiver (RQR24) using 'unifying'
126 # Logitech Unifying Receiver (RQR24) using logitech_hidpp
127127 test = Test('UnifyingRQR24', 'cc4cbfa9-bf9d-540b-b92b-172ce31013c1')
128128 test.add_file('82b90b2614a9a4d0aced1ab8a4a99e228c95585c-Logitech-Unifying-RQ024.03_B0027.cab', 'RQR24.03_B0027')
129129 test.add_file('4511b9b0d123bdbe8a2007233318ab215a59dfe6-Logitech-Unifying-RQR24.05_B0029.cab', 'RQR24.05_B0029')
3131 <binary>fwupdmgr</binary>
3232 </provides>
3333 <releases>
34 <release version="1.3.4" date="2019-11-22">
35 <description>
36 <p>This release adds the following features:</p>
37 <ul>
38 <li>Add a new property Interactive to the daemon</li>
39 <li>Add a new script for installing a Dell BIOS from an EXE file</li>
40 <li>Add support for Foxconn T77W968 and DW5821e eSIM</li>
41 <li>Add support for matching firmware requirements on device parents</li>
42 <li>Add support for writing VIA PD and I2C devices</li>
43 <li>Add versions formats for the Microsoft Surface devices</li>
44 </ul>
45 <p>This release fixes the following bugs:</p>
46 <ul>
47 <li>Allows confined snaps to activate fwupd via D-Bus</li>
48 <li>Correct Wacom panel HWID support</li>
49 <li>Don't assume all udev devices have device_file</li>
50 <li>Dynamically determine release version</li>
51 <li>Fall back to `ID_LIKE` when the path for `ID` doesn't exist</li>
52 <li>Fix a fastboot regression when updating modem firmware</li>
53 <li>Fix regression when coldplugging superio devices</li>
54 <li>Fix the linking of the UEFI update binary</li>
55 <li>Fix the vendor id of hidraw devices</li>
56 <li>Make loading USB device strings non-fatal</li>
57 <li>Reject invalid Synaptics MST chip IDs</li>
58 <li>Skip cleanup after device is done updating if required</li>
59 </ul>
60 </description>
61 </release>
3462 <release version="1.3.3" date="2019-11-01">
3563 <description>
3664 <p>This release adds the following features:</p>
33 Exec=@libexecdir@/fwupd/fwupd
44 User=root
55 SystemdService=fwupd.service
6 AssumedAppArmorLabel=unconfined
411411 set process-wide.
412412 This allows plugins to detect when they should output detailed debugging
413413 information that would normally be too verbose to keep in the journal.
414 For example, using <code>--plugin-verbose=unifying</code> would set
415 <code>FWUPD_UNIFYING_VERBOSE=1</code>.
414 For example, using <code>--plugin-verbose=logitech_hidpp</code> would set
415 <code>FWUPD_LOGITECH_HID_VERBOSE=1</code>.
416416 </para>
417417 </section>
418418
3737 typedef struct {
3838 FwupdStatus status;
3939 gboolean tainted;
40 gboolean interactive;
4041 guint percentage;
4142 gchar *daemon_version;
4243 gchar *host_product;
6263 PROP_TAINTED,
6364 PROP_HOST_PRODUCT,
6465 PROP_HOST_MACHINE_ID,
66 PROP_INTERACTIVE,
6567 PROP_LAST
6668 };
6769
162164 g_object_notify (G_OBJECT (client), "tainted");
163165 }
164166 }
167 if (g_variant_dict_contains (dict, "Interactive")) {
168 g_autoptr(GVariant) val = NULL;
169 val = g_dbus_proxy_get_cached_property (proxy, "Interactive");
170 if (val != NULL) {
171 priv->interactive = g_variant_get_boolean (val);
172 g_object_notify (G_OBJECT (client), "interactive");
173 }
174 }
165175 if (g_variant_dict_contains (dict, "Percentage")) {
166176 g_autoptr(GVariant) val = NULL;
167177 val = g_dbus_proxy_get_cached_property (proxy, "Percentage");
282292 val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Tainted");
283293 if (val2 != NULL)
284294 priv->tainted = g_variant_get_boolean (val2);
295 val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Interactive");
296 if (val2 != NULL)
297 priv->interactive = g_variant_get_boolean (val2);
285298 val = g_dbus_proxy_get_cached_property (priv->proxy, "HostProduct");
286299 if (val != NULL)
287300 fwupd_client_set_host_product (client, g_variant_get_string (val, NULL));
12601273 FwupdClientPrivate *priv = GET_PRIVATE (client);
12611274 g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
12621275 return priv->tainted;
1276 }
1277
1278
1279 /**
1280 * fwupd_client_get_daemon_interactive:
1281 * @client: A #FwupdClient
1282 *
1283 * Gets if the daemon is running in an interactive terminal.
1284 *
1285 * Returns: %TRUE if the daemon is running in an interactive terminal
1286 *
1287 * Since: 1.3.4
1288 **/
1289 gboolean
1290 fwupd_client_get_daemon_interactive (FwupdClient *client)
1291 {
1292 FwupdClientPrivate *priv = GET_PRIVATE (client);
1293 g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
1294 return priv->interactive;
12631295 }
12641296
12651297 /**
17541786 case PROP_HOST_MACHINE_ID:
17551787 g_value_set_string (value, priv->host_machine_id);
17561788 break;
1789 case PROP_INTERACTIVE:
1790 g_value_set_boolean (value, priv->interactive);
1791 break;
17571792 default:
17581793 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
17591794 break;
18971932 g_object_class_install_property (object_class, PROP_TAINTED, pspec);
18981933
18991934 /**
1935 * FwupdClient:interactive:
1936 *
1937 * If the daemon is running in an interactive terminal
1938 *
1939 * Since: 1.3.4
1940 */
1941 pspec = g_param_spec_boolean ("interactive", NULL, NULL, FALSE,
1942 G_PARAM_READABLE | G_PARAM_STATIC_NAME);
1943 g_object_class_install_property (object_class, PROP_INTERACTIVE, pspec);
1944
1945 /**
19001946 * FwupdClient:percentage:
19011947 *
19021948 * The last-reported percentage of the daemon.
124124 GError **error);
125125 FwupdStatus fwupd_client_get_status (FwupdClient *client);
126126 gboolean fwupd_client_get_tainted (FwupdClient *client);
127 gboolean fwupd_client_get_daemon_interactive (FwupdClient *client);
127128 guint fwupd_client_get_percentage (FwupdClient *client);
128129 const gchar *fwupd_client_get_daemon_version (FwupdClient *client);
129130 const gchar *fwupd_client_get_host_product (FwupdClient *client);
492492 return FWUPD_VERSION_FORMAT_INTEL_ME;
493493 if (g_strcmp0 (str, "intel-me2") == 0)
494494 return FWUPD_VERSION_FORMAT_INTEL_ME2;
495 if (g_strcmp0 (str, "surface-legacy") == 0)
496 return FWUPD_VERSION_FORMAT_SURFACE_LEGACY;
497 if (g_strcmp0 (str, "surface") == 0)
498 return FWUPD_VERSION_FORMAT_SURFACE;
495499 return FWUPD_VERSION_FORMAT_UNKNOWN;
496500 }
497501
524528 return "intel-me";
525529 if (kind == FWUPD_VERSION_FORMAT_INTEL_ME2)
526530 return "intel-me2";
527 return NULL;
528 }
531 if (kind == FWUPD_VERSION_FORMAT_SURFACE_LEGACY)
532 return "surface-legacy";
533 if (kind == FWUPD_VERSION_FORMAT_SURFACE)
534 return "surface";
535 return NULL;
536 }
244244 * @FWUPD_VERSION_FORMAT_BCD: Binary coded decimal notation
245245 * @FWUPD_VERSION_FORMAT_INTEL_ME: Intel ME-style bitshifted notation
246246 * @FWUPD_VERSION_FORMAT_INTEL_ME2: Intel ME-style A.B.CC.DDDD notation notation
247 * @FWUPD_VERSION_FORMAT_SURFACE_LEGACY: Legacy Microsoft Surface 10b.12b.10b
248 * @FWUPD_VERSION_FORMAT_SURFACE: Microsoft Surface 8b.16b.8b
247249 *
248250 * The flags used when parsing version numbers.
249251 *
260262 FWUPD_VERSION_FORMAT_BCD, /* Since: 1.2.9 */
261263 FWUPD_VERSION_FORMAT_INTEL_ME, /* Since: 1.2.9 */
262264 FWUPD_VERSION_FORMAT_INTEL_ME2, /* Since: 1.2.9 */
265 FWUPD_VERSION_FORMAT_SURFACE_LEGACY, /* Since: 1.3.4 */
266 FWUPD_VERSION_FORMAT_SURFACE, /* Since: 1.3.4 */
263267 /*< private >*/
264268 FWUPD_VERSION_FORMAT_LAST
265269 } FwupdVersionFormat;
398398 fwupd_remote_get_automatic_reports;
399399 local: *;
400400 } LIBFWUPD_1.3.2;
401
402 LIBFWUPD_1.3.4 {
403 global:
404 fwupd_client_get_daemon_interactive;
405 local: *;
406 } LIBFWUPD_1.3.3;
00 project('fwupd', 'c',
1 version : '1.3.3',
1 version : run_command('contrib/get-version.py').stdout().strip(),
22 license : 'LGPL-2.1+',
33 meson_version : '>=0.47.0',
44 default_options : ['warning_level=2', 'c_std=c99'],
88 varr = fwupd_version.split('.')
99 fwupd_major_version = varr[0]
1010 fwupd_minor_version = varr[1]
11 fwupd_micro_version = varr[2]
12
11 fwupd_micro_version = varr[2].split('-')[0]
1312 conf = configuration_data()
13
14 if varr[2].contains('-')
15 fwupd_dirty_version = varr[2].split('-')[1]
16 fwupd_commit = varr[2].split('-')[2]
17 conf.set('FWUPD_DIRTY_VERSION', fwupd_dirty_version)
18 conf.set_quoted('FWUPD_COMMIT_VERSION', fwupd_commit)
19 endif
1420 conf.set('FWUPD_MAJOR_VERSION', fwupd_major_version)
1521 conf.set('FWUPD_MINOR_VERSION', fwupd_minor_version)
1622 conf.set('FWUPD_MICRO_VERSION', fwupd_micro_version)
1723 conf.set_quoted('PACKAGE_VERSION', fwupd_version)
18
19 archiver = find_program('git', required : false)
20 if archiver.found()
21 result = run_command('git', 'describe')
22 if result.returncode() == 0
23 describe = result.stdout().strip()
24 conf.set_quoted('FWUPD_GIT_DESCRIBE', describe)
25 endif
26 endif
2724
2825 # libtool versioning - this applies to libfwupd
2926 #
4946
5047 # get supported warning flags
5148 warning_flags = [
52 '-fstack-protector-strong',
5349 '-Waggregate-return',
5450 '-Wunused',
5551 '-Warray-bounds',
106102 cc = meson.get_compiler('c')
107103 add_project_arguments(cc.get_supported_arguments(warning_flags), language : 'c')
108104
105 if not meson.is_cross_build()
106 add_project_arguments('-fstack-protector-strong', language : 'c')
107 endif
108
109109 # enable full RELRO where possible
110110 # FIXME: until https://github.com/mesonbuild/meson/issues/1140 is fixed
111111 global_link_args = []
164164 endif
165165 if build_standalone
166166 gmodule = dependency('gmodule-2.0')
167 gudev = dependency('gudev-1.0')
168 if gudev.version().version_compare('>= 232')
169 conf.set('HAVE_GUDEV_232', '1')
170 endif
167 gudev = dependency('gudev-1.0', version : '>= 232')
171168 libxmlb = dependency('xmlb', version : '>= 0.1.13', fallback : ['libxmlb', 'libxmlb_dep'])
172169 gusb = dependency('gusb', version : '>= 0.2.9')
173170 sqlite = dependency('sqlite3')
2525 };
2626
2727 G_DEFINE_TYPE (FuAltosDevice, fu_altos_device, FU_TYPE_USB_DEVICE)
28
29 #ifndef HAVE_GUDEV_232
30 #pragma clang diagnostic push
31 #pragma clang diagnostic ignored "-Wunused-function"
32 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref)
33 #pragma clang diagnostic pop
34 #endif
3528
3629 static void
3730 fu_altos_device_finalize (GObject *object)
7373 };
7474
7575 G_DEFINE_TYPE (FuAtaDevice, fu_ata_device, FU_TYPE_UDEV_DEVICE)
76
77 #ifndef HAVE_GUDEV_232
78 #pragma clang diagnostic push
79 #pragma clang diagnostic ignored "-Wunused-function"
80 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
81 #pragma clang diagnostic pop
82 #endif
8376
8477 guint8
8578 fu_ata_device_get_transfer_mode (FuAtaDevice *self)
103103 g_debug ("attempt %d/%d: set control transfer failed: %s",
104104 i, HID_MAX_RETRIES,
105105 error_local->message);
106 sleep (1);
106 g_usleep (G_USEC_PER_SEC);
107107 }
108108 }
109109 if (actual_len != 192) {
415415 }
416416
417417 /* get header and payload */
418 fw_hdr = fu_firmware_get_image_by_id_bytes (firmware, "header", error);
418 fw_hdr = fu_firmware_get_image_by_id_bytes (firmware,
419 FU_FIRMWARE_IMAGE_ID_HEADER,
420 error);
419421 if (fw_hdr == NULL)
420422 return FALSE;
421 fw_payload = fu_firmware_get_image_by_id_bytes (firmware, "payload", error);
423 fw_payload = fu_firmware_get_image_by_id_bytes (firmware,
424 FU_FIRMWARE_IMAGE_ID_PAYLOAD,
425 error);
422426 if (fw_payload == NULL)
423427 return FALSE;
424428
507511 /* when doing a soft-reboot the device does not re-enumerate properly
508512 * so manually reboot the GUsbDevice */
509513 fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
510 if (!g_usb_device_reset (usb_device, error)) {
511 g_prefix_error (error, "failed to force-reset device: ");
514 if (!g_usb_device_reset (usb_device, &error_local)) {
515 g_prefix_error (&error_local, "failed to force-reset device: ");
516 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_WILL_DISAPPEAR)) {
517 fu_device_set_remove_delay (device, 0);
518 g_debug ("%s", error_local->message);
519 return TRUE;
520 }
521 g_propagate_error (error, g_steal_pointer (&error_local));
512522 return FALSE;
513523 }
514524
7777
7878 /* add header */
7979 fw_hdr = g_bytes_new_from_bytes (fw, 0x0, sizeof(FuEbitdoFirmwareHeader));
80 fu_firmware_image_set_id (img_hdr, "header");
80 fu_firmware_image_set_id (img_hdr, FU_FIRMWARE_IMAGE_ID_HEADER);
8181 fu_firmware_image_set_bytes (img_hdr, fw_hdr);
8282 fu_firmware_add_image (firmware, img_hdr);
8383
8484 /* add payload */
8585 fw_payload = g_bytes_new_from_bytes (fw, sizeof(FuEbitdoFirmwareHeader), payload_len);
86 fu_firmware_image_set_id (img_payload, "payload");
86 fu_firmware_image_set_id (img_payload, FU_FIRMWARE_IMAGE_ID_PAYLOAD);
8787 fu_firmware_image_set_addr (img_payload, GUINT32_FROM_LE(hdr->destination_addr));
8888 fu_firmware_image_set_bytes (img_payload, fw_payload);
8989 fu_firmware_add_image (firmware, img_payload);
694694 /* this is a safe default, even using USBv1 */
695695 self->blocksz = 512;
696696 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
697 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
697698 fu_device_set_remove_delay (FU_DEVICE (self), FASTBOOT_REMOVE_DELAY_RE_ENUMERATE);
698699 }
699700
0 Logitech HID Support
1 ================
2
3 Introduction
4 ------------
5
6 This plugin can flash the firmware on Logitech Unifying dongles, both the
7 Nordic (U0007) device and the Texas Instruments (U0008) version.
8
9 This plugin will not work with the different "Nano" dongle (U0010) as it does
10 not use the Unifying protocol.
11
12 Some bootloader protocol information was taken from the Mousejack[1] project,
13 specifically logitech-usb-restore.py and unifying.py. Other documentation was
14 supplied by Logitech.
15
16 Additional constants were taken from the Solaar[2] project.
17
18 Firmware Format
19 ---------------
20
21 The daemon will decompress the cabinet archive and extract a firmware blob in
22 a vendor-specific format that appears to be a subset of the Intel HEX format.
23
24 This plugin supports the following protocol IDs:
25
26 * com.logitech.unifying
27 * com.logitech.unifyingsigned
28
29 GUID Generation
30 ---------------
31
32 These devices use the standard USB DeviceInstanceId values when in DFU mode:
33
34 * `USB\VID_046D&PID_AAAA&REV_0001`
35 * `USB\VID_046D&PID_AAAA`
36 * `USB\VID_046D`
37
38 When in runtime mode, the HID raw DeviceInstanceId values are used:
39
40 * `HIDRAW\VEN_046D&DEV_C52B`
41 * `HIDRAW\VEN_046D`
42
43 Design Notes
44 ------------
45
46 When a dongle is detected in bootloader mode we detach the hidraw driver from
47 the kernel and use raw control transfers. This ensures that we don't accidentally
48 corrupt the uploading firmware. For application firmware we use hidraw which
49 means the hardware keeps working while probing, and also allows us to detect
50 paired devices.
51
52 [1] https://www.mousejack.com/
53 [2] https://pwr-Solaar.github.io/Solaar/
0 Bus 001 Device 036: ID 046d:aaaa Logitech, Inc.
1 Device Descriptor:
2 bLength 18
3 bDescriptorType 1
4 bcdUSB 2.00
5 bDeviceClass 0
6 bDeviceSubClass 0
7 bDeviceProtocol 0
8 bMaxPacketSize0 32
9 idVendor 0x046d Logitech, Inc.
10 idProduct 0xaaaa
11 bcdDevice 1.02
12 iManufacturer 1
13 iProduct 2
14 iSerial 0
15 bNumConfigurations 1
16 Configuration Descriptor:
17 bLength 9
18 bDescriptorType 2
19 wTotalLength 34
20 bNumInterfaces 1
21 bConfigurationValue 1
22 iConfiguration 4
23 bmAttributes 0x80
24 (Bus Powered)
25 MaxPower 98mA
26 Interface Descriptor:
27 bLength 9
28 bDescriptorType 4
29 bInterfaceNumber 0
30 bAlternateSetting 0
31 bNumEndpoints 1
32 bInterfaceClass 3 Human Interface Device
33 bInterfaceSubClass 0
34 bInterfaceProtocol 0
35 iInterface 0
36 HID Device Descriptor:
37 bLength 9
38 bDescriptorType 33
39 bcdHID 1.11
40 bCountryCode 0 Not supported
41 bNumDescriptors 1
42 bDescriptorType 34 Report
43 wDescriptorLength 25
44 Report Descriptors:
45 ** UNAVAILABLE **
46 Endpoint Descriptor:
47 bLength 7
48 bDescriptorType 5
49 bEndpointAddress 0x81 EP 1 IN
50 bmAttributes 3
51 Transfer Type Interrupt
52 Synch Type None
53 Usage Type Data
54 wMaxPacketSize 0x0020 1x 32 bytes
55 bInterval 1
0 Bus 001 Device 049: ID 046d:c52b Logitech, Inc. Unifying Receiver
1 Device Descriptor:
2 bLength 18
3 bDescriptorType 1
4 bcdUSB 2.00
5 bDeviceClass 0
6 bDeviceSubClass 0
7 bDeviceProtocol 0
8 bMaxPacketSize0 8
9 idVendor 0x046d Logitech, Inc.
10 idProduct 0xc52b Unifying Receiver
11 bcdDevice 12.07
12 iManufacturer 1 Logitech
13 iProduct 2 USB Receiver
14 iSerial 0
15 bNumConfigurations 1
16 Configuration Descriptor:
17 bLength 9
18 bDescriptorType 2
19 wTotalLength 84
20 bNumInterfaces 3
21 bConfigurationValue 1
22 iConfiguration 4 RQR12.07_B0029
23 bmAttributes 0xa0
24 (Bus Powered)
25 Remote Wakeup
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 1 Boot Interface Subclass
35 bInterfaceProtocol 1 Keyboard
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 59
45 Report Descriptor: (length is 59)
46 Endpoint Descriptor:
47 bLength 7
48 bDescriptorType 5
49 bEndpointAddress 0x81 EP 1 IN
50 bmAttributes 3
51 Transfer Type Interrupt
52 Synch Type None
53 Usage Type Data
54 wMaxPacketSize 0x0008 1x 8 bytes
55 bInterval 8
56 Interface Descriptor:
57 bLength 9
58 bDescriptorType 4
59 bInterfaceNumber 1
60 bAlternateSetting 0
61 bNumEndpoints 1
62 bInterfaceClass 3 Human Interface Device
63 bInterfaceSubClass 1 Boot Interface Subclass
64 bInterfaceProtocol 2 Mouse
65 iInterface 0
66 HID Device Descriptor:
67 bLength 9
68 bDescriptorType 33
69 bcdHID 1.11
70 bCountryCode 0 Not supported
71 bNumDescriptors 1
72 bDescriptorType 34 Report
73 wDescriptorLength 148
74 Report Descriptors:
75 ** UNAVAILABLE **
76 Endpoint Descriptor:
77 bLength 7
78 bDescriptorType 5
79 bEndpointAddress 0x82 EP 2 IN
80 bmAttributes 3
81 Transfer Type Interrupt
82 Synch Type None
83 Usage Type Data
84 wMaxPacketSize 0x0008 1x 8 bytes
85 bInterval 2
86 Interface Descriptor:
87 bLength 9
88 bDescriptorType 4
89 bInterfaceNumber 2
90 bAlternateSetting 0
91 bNumEndpoints 1
92 bInterfaceClass 3 Human Interface Device
93 bInterfaceSubClass 0
94 bInterfaceProtocol 0
95 iInterface 0
96 HID Device Descriptor:
97 bLength 9
98 bDescriptorType 33
99 bcdHID 1.11
100 bCountryCode 0 Not supported
101 bNumDescriptors 1
102 bDescriptorType 34 Report
103 wDescriptorLength 93
104 Report Descriptors:
105 ** UNAVAILABLE **
106 Endpoint Descriptor:
107 bLength 7
108 bDescriptorType 5
109 bEndpointAddress 0x83 EP 3 IN
110 bmAttributes 3
111 Transfer Type Interrupt
112 Synch Type None
113 Usage Type Data
114 wMaxPacketSize 0x0020 1x 32 bytes
115 bInterval 2
116 Device Status: 0x0000
117 (Bus Powered)
0
1 Bus 003 Device 036: ID 046d:aaac Logitech, Inc.
2 Device Descriptor:
3 bLength 18
4 bDescriptorType 1
5 bcdUSB 2.00
6 bDeviceClass 0
7 bDeviceSubClass 0
8 bDeviceProtocol 0
9 bMaxPacketSize0 32
10 idVendor 0x046d Logitech, Inc.
11 idProduct 0xaaac
12 bcdDevice 3.01
13 iManufacturer 1 Logitech
14 iProduct 2 USB BootLoader
15 iSerial 0
16 bNumConfigurations 1
17 Configuration Descriptor:
18 bLength 9
19 bDescriptorType 2
20 wTotalLength 34
21 bNumInterfaces 1
22 bConfigurationValue 1
23 iConfiguration 4 BOT03.01_B0008
24 bmAttributes 0x80
25 (Bus Powered)
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 0
35 bInterfaceProtocol 0
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 25
45 Report Descriptor: (length is 25)
46 Item(Global): Usage Page, data= [ 0xb0 0xff ] 65456
47 (null)
48 Item(Local ): Usage, data= [ 0x01 ] 1
49 (null)
50 Item(Main ): Collection, data= [ 0x01 ] 1
51 Application
52 Item(Global): Report Size, data= [ 0x08 ] 8
53 Item(Global): Report Count, data= [ 0x20 ] 32
54 Item(Global): Logical Minimum, data= [ 0x00 ] 0
55 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
56 Item(Local ): Usage, data= [ 0x01 ] 1
57 (null)
58 Item(Main ): Input, data= [ 0x00 ] 0
59 Data Array Absolute No_Wrap Linear
60 Preferred_State No_Null_Position Non_Volatile Bitfield
61 Item(Local ): Usage, data= [ 0x01 ] 1
62 (null)
63 Item(Main ): Output, data= [ 0x00 ] 0
64 Data Array Absolute No_Wrap Linear
65 Preferred_State No_Null_Position Non_Volatile Bitfield
66 Item(Main ): End Collection, data=none
67 Endpoint Descriptor:
68 bLength 7
69 bDescriptorType 5
70 bEndpointAddress 0x81 EP 1 IN
71 bmAttributes 3
72 Transfer Type Interrupt
73 Synch Type None
74 Usage Type Data
75 wMaxPacketSize 0x0020 1x 32 bytes
76 bInterval 1
77 Device Status: 0x0000
78 (Bus Powered)
0
1 Bus 003 Device 039: ID 046d:aaac Logitech, Inc.
2 Device Descriptor:
3 bLength 18
4 bDescriptorType 1
5 bcdUSB 2.00
6 bDeviceClass 0
7 bDeviceSubClass 0
8 bDeviceProtocol 0
9 bMaxPacketSize0 32
10 idVendor 0x046d Logitech, Inc.
11 idProduct 0xaaac
12 bcdDevice 3.00
13 iManufacturer 1 Logitech
14 iProduct 2 USB BootLoader
15 iSerial 0
16 bNumConfigurations 1
17 Configuration Descriptor:
18 bLength 9
19 bDescriptorType 2
20 wTotalLength 34
21 bNumInterfaces 1
22 bConfigurationValue 1
23 iConfiguration 4 BOT03.00_B0006
24 bmAttributes 0x80
25 (Bus Powered)
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 0
35 bInterfaceProtocol 0
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 25
45 Report Descriptor: (length is 25)
46 Item(Global): Usage Page, data= [ 0xb0 0xff ] 65456
47 (null)
48 Item(Local ): Usage, data= [ 0x01 ] 1
49 (null)
50 Item(Main ): Collection, data= [ 0x01 ] 1
51 Application
52 Item(Global): Report Size, data= [ 0x08 ] 8
53 Item(Global): Report Count, data= [ 0x20 ] 32
54 Item(Global): Logical Minimum, data= [ 0x00 ] 0
55 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
56 Item(Local ): Usage, data= [ 0x01 ] 1
57 (null)
58 Item(Main ): Input, data= [ 0x00 ] 0
59 Data Array Absolute No_Wrap Linear
60 Preferred_State No_Null_Position Non_Volatile Bitfield
61 Item(Local ): Usage, data= [ 0x01 ] 1
62 (null)
63 Item(Main ): Output, data= [ 0x00 ] 0
64 Data Array Absolute No_Wrap Linear
65 Preferred_State No_Null_Position Non_Volatile Bitfield
66 Item(Main ): End Collection, data=none
67 Endpoint Descriptor:
68 bLength 7
69 bDescriptorType 5
70 bEndpointAddress 0x81 EP 1 IN
71 bmAttributes 3
72 Transfer Type Interrupt
73 Synch Type None
74 Usage Type Data
75 wMaxPacketSize 0x0020 1x 32 bytes
76 bInterval 1
77 Device Status: 0x0000
78 (Bus Powered)
0
1 Bus 003 Device 033: ID 046d:c52b Logitech, Inc. Unifying Receiver
2 Device Descriptor:
3 bLength 18
4 bDescriptorType 1
5 bcdUSB 2.00
6 bDeviceClass 0
7 bDeviceSubClass 0
8 bDeviceProtocol 0
9 bMaxPacketSize0 32
10 idVendor 0x046d Logitech, Inc.
11 idProduct 0xc52b Unifying Receiver
12 bcdDevice 24.01
13 iManufacturer 1 Logitech
14 iProduct 2 USB Receiver
15 iSerial 0
16 bNumConfigurations 1
17 Configuration Descriptor:
18 bLength 9
19 bDescriptorType 2
20 wTotalLength 84
21 bNumInterfaces 3
22 bConfigurationValue 1
23 iConfiguration 4 RQR24.01_B0023
24 bmAttributes 0xa0
25 (Bus Powered)
26 Remote Wakeup
27 MaxPower 98mA
28 Interface Descriptor:
29 bLength 9
30 bDescriptorType 4
31 bInterfaceNumber 0
32 bAlternateSetting 0
33 bNumEndpoints 1
34 bInterfaceClass 3 Human Interface Device
35 bInterfaceSubClass 1 Boot Interface Subclass
36 bInterfaceProtocol 1 Keyboard
37 iInterface 0
38 HID Device Descriptor:
39 bLength 9
40 bDescriptorType 33
41 bcdHID 1.11
42 bCountryCode 0 Not supported
43 bNumDescriptors 1
44 bDescriptorType 34 Report
45 wDescriptorLength 59
46 Report Descriptor: (length is 59)
47 Item(Global): Usage Page, data= [ 0x01 ] 1
48 Generic Desktop Controls
49 Item(Local ): Usage, data= [ 0x06 ] 6
50 Keyboard
51 Item(Main ): Collection, data= [ 0x01 ] 1
52 Application
53 Item(Global): Usage Page, data= [ 0x07 ] 7
54 Keyboard
55 Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
56 Control Left
57 Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
58 GUI Right
59 Item(Global): Logical Minimum, data= [ 0x00 ] 0
60 Item(Global): Logical Maximum, data= [ 0x01 ] 1
61 Item(Global): Report Size, data= [ 0x01 ] 1
62 Item(Global): Report Count, data= [ 0x08 ] 8
63 Item(Main ): Input, data= [ 0x02 ] 2
64 Data Variable Absolute No_Wrap Linear
65 Preferred_State No_Null_Position Non_Volatile Bitfield
66 Item(Main ): Input, data= [ 0x03 ] 3
67 Constant Variable Absolute No_Wrap Linear
68 Preferred_State No_Null_Position Non_Volatile Bitfield
69 Item(Global): Report Count, data= [ 0x05 ] 5
70 Item(Global): Usage Page, data= [ 0x08 ] 8
71 LEDs
72 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
73 NumLock
74 Item(Local ): Usage Maximum, data= [ 0x05 ] 5
75 Kana
76 Item(Main ): Output, data= [ 0x02 ] 2
77 Data Variable Absolute No_Wrap Linear
78 Preferred_State No_Null_Position Non_Volatile Bitfield
79 Item(Global): Report Count, data= [ 0x01 ] 1
80 Item(Global): Report Size, data= [ 0x03 ] 3
81 Item(Main ): Output, data= [ 0x01 ] 1
82 Constant Array Absolute No_Wrap Linear
83 Preferred_State No_Null_Position Non_Volatile Bitfield
84 Item(Global): Report Count, data= [ 0x06 ] 6
85 Item(Global): Report Size, data= [ 0x08 ] 8
86 Item(Global): Logical Minimum, data= [ 0x00 ] 0
87 Item(Global): Logical Maximum, data= [ 0xa4 0x00 ] 164
88 Item(Global): Usage Page, data= [ 0x07 ] 7
89 Keyboard
90 Item(Local ): Usage Minimum, data= [ 0x00 ] 0
91 No Event
92 Item(Local ): Usage Maximum, data= [ 0xa4 0x00 ] 164
93 ExSel
94 Item(Main ): Input, data= [ 0x00 ] 0
95 Data Array Absolute No_Wrap Linear
96 Preferred_State No_Null_Position Non_Volatile Bitfield
97 Item(Main ): End Collection, data=none
98 Endpoint Descriptor:
99 bLength 7
100 bDescriptorType 5
101 bEndpointAddress 0x81 EP 1 IN
102 bmAttributes 3
103 Transfer Type Interrupt
104 Synch Type None
105 Usage Type Data
106 wMaxPacketSize 0x0008 1x 8 bytes
107 bInterval 8
108 Interface Descriptor:
109 bLength 9
110 bDescriptorType 4
111 bInterfaceNumber 1
112 bAlternateSetting 0
113 bNumEndpoints 1
114 bInterfaceClass 3 Human Interface Device
115 bInterfaceSubClass 1 Boot Interface Subclass
116 bInterfaceProtocol 2 Mouse
117 iInterface 0
118 HID Device Descriptor:
119 bLength 9
120 bDescriptorType 33
121 bcdHID 1.11
122 bCountryCode 0 Not supported
123 bNumDescriptors 1
124 bDescriptorType 34 Report
125 wDescriptorLength 148
126 Report Descriptor: (length is 148)
127 Item(Global): Usage Page, data= [ 0x01 ] 1
128 Generic Desktop Controls
129 Item(Local ): Usage, data= [ 0x02 ] 2
130 Mouse
131 Item(Main ): Collection, data= [ 0x01 ] 1
132 Application
133 Item(Global): Report ID, data= [ 0x02 ] 2
134 Item(Local ): Usage, data= [ 0x01 ] 1
135 Pointer
136 Item(Main ): Collection, data= [ 0x00 ] 0
137 Physical
138 Item(Global): Usage Page, data= [ 0x09 ] 9
139 Buttons
140 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
141 Button 1 (Primary)
142 Item(Local ): Usage Maximum, data= [ 0x10 ] 16
143 (null)
144 Item(Global): Logical Minimum, data= [ 0x00 ] 0
145 Item(Global): Logical Maximum, data= [ 0x01 ] 1
146 Item(Global): Report Count, data= [ 0x10 ] 16
147 Item(Global): Report Size, data= [ 0x01 ] 1
148 Item(Main ): Input, data= [ 0x02 ] 2
149 Data Variable Absolute No_Wrap Linear
150 Preferred_State No_Null_Position Non_Volatile Bitfield
151 Item(Global): Usage Page, data= [ 0x01 ] 1
152 Generic Desktop Controls
153 Item(Global): Logical Minimum, data= [ 0x01 0xf8 ] 63489
154 Item(Global): Logical Maximum, data= [ 0xff 0x07 ] 2047
155 Item(Global): Report Size, data= [ 0x0c ] 12
156 Item(Global): Report Count, data= [ 0x02 ] 2
157 Item(Local ): Usage, data= [ 0x30 ] 48
158 Direction-X
159 Item(Local ): Usage, data= [ 0x31 ] 49
160 Direction-Y
161 Item(Main ): Input, data= [ 0x06 ] 6
162 Data Variable Relative No_Wrap Linear
163 Preferred_State No_Null_Position Non_Volatile Bitfield
164 Item(Global): Logical Minimum, data= [ 0x81 ] 129
165 Item(Global): Logical Maximum, data= [ 0x7f ] 127
166 Item(Global): Report Size, data= [ 0x08 ] 8
167 Item(Global): Report Count, data= [ 0x01 ] 1
168 Item(Local ): Usage, data= [ 0x38 ] 56
169 Wheel
170 Item(Main ): Input, data= [ 0x06 ] 6
171 Data Variable Relative No_Wrap Linear
172 Preferred_State No_Null_Position Non_Volatile Bitfield
173 Item(Global): Usage Page, data= [ 0x0c ] 12
174 Consumer
175 Item(Local ): Usage, data= [ 0x38 0x02 ] 568
176 AC Pan
177 Item(Global): Report Count, data= [ 0x01 ] 1
178 Item(Main ): Input, data= [ 0x06 ] 6
179 Data Variable Relative No_Wrap Linear
180 Preferred_State No_Null_Position Non_Volatile Bitfield
181 Item(Main ): End Collection, data=none
182 Item(Main ): End Collection, data=none
183 Item(Global): Usage Page, data= [ 0x0c ] 12
184 Consumer
185 Item(Local ): Usage, data= [ 0x01 ] 1
186 Consumer Control
187 Item(Main ): Collection, data= [ 0x01 ] 1
188 Application
189 Item(Global): Report ID, data= [ 0x03 ] 3
190 Item(Global): Report Size, data= [ 0x10 ] 16
191 Item(Global): Report Count, data= [ 0x02 ] 2
192 Item(Global): Logical Minimum, data= [ 0x01 ] 1
193 Item(Global): Logical Maximum, data= [ 0x8c 0x02 ] 652
194 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
195 Consumer Control
196 Item(Local ): Usage Maximum, data= [ 0x8c 0x02 ] 652
197 (null)
198 Item(Main ): Input, data= [ 0x00 ] 0
199 Data Array Absolute No_Wrap Linear
200 Preferred_State No_Null_Position Non_Volatile Bitfield
201 Item(Main ): End Collection, data=none
202 Item(Global): Usage Page, data= [ 0x01 ] 1
203 Generic Desktop Controls
204 Item(Local ): Usage, data= [ 0x80 ] 128
205 System Control
206 Item(Main ): Collection, data= [ 0x01 ] 1
207 Application
208 Item(Global): Report ID, data= [ 0x04 ] 4
209 Item(Global): Report Size, data= [ 0x02 ] 2
210 Item(Global): Report Count, data= [ 0x01 ] 1
211 Item(Global): Logical Minimum, data= [ 0x01 ] 1
212 Item(Global): Logical Maximum, data= [ 0x03 ] 3
213 Item(Local ): Usage, data= [ 0x82 ] 130
214 System Sleep
215 Item(Local ): Usage, data= [ 0x81 ] 129
216 System Power Down
217 Item(Local ): Usage, data= [ 0x83 ] 131
218 System Wake Up
219 Item(Main ): Input, data= [ 0x60 ] 96
220 Data Array Absolute No_Wrap Linear
221 No_Preferred_State Null_State Non_Volatile Bitfield
222 Item(Global): Report Size, data= [ 0x06 ] 6
223 Item(Main ): Input, data= [ 0x03 ] 3
224 Constant Variable Absolute No_Wrap Linear
225 Preferred_State No_Null_Position Non_Volatile Bitfield
226 Item(Main ): End Collection, data=none
227 Item(Global): Usage Page, data= [ 0xbc 0xff ] 65468
228 (null)
229 Item(Local ): Usage, data= [ 0x88 ] 136
230 (null)
231 Item(Main ): Collection, data= [ 0x01 ] 1
232 Application
233 Item(Global): Report ID, data= [ 0x08 ] 8
234 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
235 (null)
236 Item(Local ): Usage Maximum, data= [ 0xff ] 255
237 (null)
238 Item(Global): Logical Minimum, data= [ 0x01 ] 1
239 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
240 Item(Global): Report Size, data= [ 0x08 ] 8
241 Item(Global): Report Count, data= [ 0x01 ] 1
242 Item(Main ): Input, data= [ 0x00 ] 0
243 Data Array Absolute No_Wrap Linear
244 Preferred_State No_Null_Position Non_Volatile Bitfield
245 Item(Main ): End Collection, data=none
246 Endpoint Descriptor:
247 bLength 7
248 bDescriptorType 5
249 bEndpointAddress 0x82 EP 2 IN
250 bmAttributes 3
251 Transfer Type Interrupt
252 Synch Type None
253 Usage Type Data
254 wMaxPacketSize 0x0008 1x 8 bytes
255 bInterval 2
256 Interface Descriptor:
257 bLength 9
258 bDescriptorType 4
259 bInterfaceNumber 2
260 bAlternateSetting 0
261 bNumEndpoints 1
262 bInterfaceClass 3 Human Interface Device
263 bInterfaceSubClass 0
264 bInterfaceProtocol 0
265 iInterface 0
266 HID Device Descriptor:
267 bLength 9
268 bDescriptorType 33
269 bcdHID 1.11
270 bCountryCode 0 Not supported
271 bNumDescriptors 1
272 bDescriptorType 34 Report
273 wDescriptorLength 98
274 Report Descriptor: (length is 98)
275 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
276 (null)
277 Item(Local ): Usage, data= [ 0x01 ] 1
278 (null)
279 Item(Main ): Collection, data= [ 0x01 ] 1
280 Application
281 Item(Global): Report ID, data= [ 0x10 ] 16
282 Item(Global): Report Size, data= [ 0x08 ] 8
283 Item(Global): Report Count, data= [ 0x06 ] 6
284 Item(Global): Logical Minimum, data= [ 0x00 ] 0
285 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
286 Item(Local ): Usage, data= [ 0x01 ] 1
287 (null)
288 Item(Main ): Input, data= [ 0x00 ] 0
289 Data Array Absolute No_Wrap Linear
290 Preferred_State No_Null_Position Non_Volatile Bitfield
291 Item(Local ): Usage, data= [ 0x01 ] 1
292 (null)
293 Item(Main ): Output, data= [ 0x00 ] 0
294 Data Array Absolute No_Wrap Linear
295 Preferred_State No_Null_Position Non_Volatile Bitfield
296 Item(Main ): End Collection, data=none
297 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
298 (null)
299 Item(Local ): Usage, data= [ 0x02 ] 2
300 (null)
301 Item(Main ): Collection, data= [ 0x01 ] 1
302 Application
303 Item(Global): Report ID, data= [ 0x11 ] 17
304 Item(Global): Report Size, data= [ 0x08 ] 8
305 Item(Global): Report Count, data= [ 0x13 ] 19
306 Item(Global): Logical Minimum, data= [ 0x00 ] 0
307 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
308 Item(Local ): Usage, data= [ 0x02 ] 2
309 (null)
310 Item(Main ): Input, data= [ 0x00 ] 0
311 Data Array Absolute No_Wrap Linear
312 Preferred_State No_Null_Position Non_Volatile Bitfield
313 Item(Local ): Usage, data= [ 0x02 ] 2
314 (null)
315 Item(Main ): Output, data= [ 0x00 ] 0
316 Data Array Absolute No_Wrap Linear
317 Preferred_State No_Null_Position Non_Volatile Bitfield
318 Item(Main ): End Collection, data=none
319 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
320 (null)
321 Item(Local ): Usage, data= [ 0x04 ] 4
322 (null)
323 Item(Main ): Collection, data= [ 0x01 ] 1
324 Application
325 Item(Global): Report ID, data= [ 0x20 ] 32
326 Item(Global): Report Size, data= [ 0x08 ] 8
327 Item(Global): Report Count, data= [ 0x0e ] 14
328 Item(Global): Logical Minimum, data= [ 0x00 ] 0
329 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
330 Item(Local ): Usage, data= [ 0x41 ] 65
331 (null)
332 Item(Main ): Input, data= [ 0x00 ] 0
333 Data Array Absolute No_Wrap Linear
334 Preferred_State No_Null_Position Non_Volatile Bitfield
335 Item(Local ): Usage, data= [ 0x41 ] 65
336 (null)
337 Item(Main ): Output, data= [ 0x00 ] 0
338 Data Array Absolute No_Wrap Linear
339 Preferred_State No_Null_Position Non_Volatile Bitfield
340 Item(Global): Report ID, data= [ 0x21 ] 33
341 Item(Global): Report Count, data= [ 0x1f ] 31
342 Item(Global): Logical Minimum, data= [ 0x00 ] 0
343 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
344 Item(Local ): Usage, data= [ 0x42 ] 66
345 (null)
346 Item(Main ): Input, data= [ 0x00 ] 0
347 Data Array Absolute No_Wrap Linear
348 Preferred_State No_Null_Position Non_Volatile Bitfield
349 Item(Local ): Usage, data= [ 0x42 ] 66
350 (null)
351 Item(Main ): Output, data= [ 0x00 ] 0
352 Data Array Absolute No_Wrap Linear
353 Preferred_State No_Null_Position Non_Volatile Bitfield
354 Item(Main ): End Collection, data=none
355 Endpoint Descriptor:
356 bLength 7
357 bDescriptorType 5
358 bEndpointAddress 0x83 EP 3 IN
359 bmAttributes 3
360 Transfer Type Interrupt
361 Synch Type None
362 Usage Type Data
363 wMaxPacketSize 0x0020 1x 32 bytes
364 bInterval 2
365 Device Status: 0x0000
366 (Bus Powered)
0 Bus 003 Device 032: ID 046d:c52b Logitech, Inc. Unifying Receiver
1 Device Descriptor:
2 bLength 18
3 bDescriptorType 1
4 bcdUSB 2.00
5 bDeviceClass 0
6 bDeviceSubClass 0
7 bDeviceProtocol 0
8 bMaxPacketSize0 32
9 idVendor 0x046d Logitech, Inc.
10 idProduct 0xc52b Unifying Receiver
11 bcdDevice 24.05
12 iManufacturer 1 Logitech
13 iProduct 2 USB Receiver
14 iSerial 0
15 bNumConfigurations 1
16 Configuration Descriptor:
17 bLength 9
18 bDescriptorType 2
19 wTotalLength 84
20 bNumInterfaces 3
21 bConfigurationValue 1
22 iConfiguration 4 RQR24.05_B0029
23 bmAttributes 0xa0
24 (Bus Powered)
25 Remote Wakeup
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 1 Boot Interface Subclass
35 bInterfaceProtocol 1 Keyboard
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 59
45 Report Descriptor: (length is 59)
46 Item(Global): Usage Page, data= [ 0x01 ] 1
47 Generic Desktop Controls
48 Item(Local ): Usage, data= [ 0x06 ] 6
49 Keyboard
50 Item(Main ): Collection, data= [ 0x01 ] 1
51 Application
52 Item(Global): Usage Page, data= [ 0x07 ] 7
53 Keyboard
54 Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
55 Control Left
56 Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
57 GUI Right
58 Item(Global): Logical Minimum, data= [ 0x00 ] 0
59 Item(Global): Logical Maximum, data= [ 0x01 ] 1
60 Item(Global): Report Size, data= [ 0x01 ] 1
61 Item(Global): Report Count, data= [ 0x08 ] 8
62 Item(Main ): Input, data= [ 0x02 ] 2
63 Data Variable Absolute No_Wrap Linear
64 Preferred_State No_Null_Position Non_Volatile Bitfield
65 Item(Main ): Input, data= [ 0x03 ] 3
66 Constant Variable Absolute No_Wrap Linear
67 Preferred_State No_Null_Position Non_Volatile Bitfield
68 Item(Global): Report Count, data= [ 0x05 ] 5
69 Item(Global): Usage Page, data= [ 0x08 ] 8
70 LEDs
71 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
72 NumLock
73 Item(Local ): Usage Maximum, data= [ 0x05 ] 5
74 Kana
75 Item(Main ): Output, data= [ 0x02 ] 2
76 Data Variable Absolute No_Wrap Linear
77 Preferred_State No_Null_Position Non_Volatile Bitfield
78 Item(Global): Report Count, data= [ 0x01 ] 1
79 Item(Global): Report Size, data= [ 0x03 ] 3
80 Item(Main ): Output, data= [ 0x01 ] 1
81 Constant Array Absolute No_Wrap Linear
82 Preferred_State No_Null_Position Non_Volatile Bitfield
83 Item(Global): Report Count, data= [ 0x06 ] 6
84 Item(Global): Report Size, data= [ 0x08 ] 8
85 Item(Global): Logical Minimum, data= [ 0x00 ] 0
86 Item(Global): Logical Maximum, data= [ 0xa4 0x00 ] 164
87 Item(Global): Usage Page, data= [ 0x07 ] 7
88 Keyboard
89 Item(Local ): Usage Minimum, data= [ 0x00 ] 0
90 No Event
91 Item(Local ): Usage Maximum, data= [ 0xa4 0x00 ] 164
92 ExSel
93 Item(Main ): Input, data= [ 0x00 ] 0
94 Data Array Absolute No_Wrap Linear
95 Preferred_State No_Null_Position Non_Volatile Bitfield
96 Item(Main ): End Collection, data=none
97 Endpoint Descriptor:
98 bLength 7
99 bDescriptorType 5
100 bEndpointAddress 0x81 EP 1 IN
101 bmAttributes 3
102 Transfer Type Interrupt
103 Synch Type None
104 Usage Type Data
105 wMaxPacketSize 0x0008 1x 8 bytes
106 bInterval 8
107 Interface Descriptor:
108 bLength 9
109 bDescriptorType 4
110 bInterfaceNumber 1
111 bAlternateSetting 0
112 bNumEndpoints 1
113 bInterfaceClass 3 Human Interface Device
114 bInterfaceSubClass 1 Boot Interface Subclass
115 bInterfaceProtocol 2 Mouse
116 iInterface 0
117 HID Device Descriptor:
118 bLength 9
119 bDescriptorType 33
120 bcdHID 1.11
121 bCountryCode 0 Not supported
122 bNumDescriptors 1
123 bDescriptorType 34 Report
124 wDescriptorLength 148
125 Report Descriptor: (length is 148)
126 Item(Global): Usage Page, data= [ 0x01 ] 1
127 Generic Desktop Controls
128 Item(Local ): Usage, data= [ 0x02 ] 2
129 Mouse
130 Item(Main ): Collection, data= [ 0x01 ] 1
131 Application
132 Item(Global): Report ID, data= [ 0x02 ] 2
133 Item(Local ): Usage, data= [ 0x01 ] 1
134 Pointer
135 Item(Main ): Collection, data= [ 0x00 ] 0
136 Physical
137 Item(Global): Usage Page, data= [ 0x09 ] 9
138 Buttons
139 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
140 Button 1 (Primary)
141 Item(Local ): Usage Maximum, data= [ 0x10 ] 16
142 (null)
143 Item(Global): Logical Minimum, data= [ 0x00 ] 0
144 Item(Global): Logical Maximum, data= [ 0x01 ] 1
145 Item(Global): Report Count, data= [ 0x10 ] 16
146 Item(Global): Report Size, data= [ 0x01 ] 1
147 Item(Main ): Input, data= [ 0x02 ] 2
148 Data Variable Absolute No_Wrap Linear
149 Preferred_State No_Null_Position Non_Volatile Bitfield
150 Item(Global): Usage Page, data= [ 0x01 ] 1
151 Generic Desktop Controls
152 Item(Global): Logical Minimum, data= [ 0x01 0xf8 ] 63489
153 Item(Global): Logical Maximum, data= [ 0xff 0x07 ] 2047
154 Item(Global): Report Size, data= [ 0x0c ] 12
155 Item(Global): Report Count, data= [ 0x02 ] 2
156 Item(Local ): Usage, data= [ 0x30 ] 48
157 Direction-X
158 Item(Local ): Usage, data= [ 0x31 ] 49
159 Direction-Y
160 Item(Main ): Input, data= [ 0x06 ] 6
161 Data Variable Relative No_Wrap Linear
162 Preferred_State No_Null_Position Non_Volatile Bitfield
163 Item(Global): Logical Minimum, data= [ 0x81 ] 129
164 Item(Global): Logical Maximum, data= [ 0x7f ] 127
165 Item(Global): Report Size, data= [ 0x08 ] 8
166 Item(Global): Report Count, data= [ 0x01 ] 1
167 Item(Local ): Usage, data= [ 0x38 ] 56
168 Wheel
169 Item(Main ): Input, data= [ 0x06 ] 6
170 Data Variable Relative No_Wrap Linear
171 Preferred_State No_Null_Position Non_Volatile Bitfield
172 Item(Global): Usage Page, data= [ 0x0c ] 12
173 Consumer
174 Item(Local ): Usage, data= [ 0x38 0x02 ] 568
175 AC Pan
176 Item(Global): Report Count, data= [ 0x01 ] 1
177 Item(Main ): Input, data= [ 0x06 ] 6
178 Data Variable Relative No_Wrap Linear
179 Preferred_State No_Null_Position Non_Volatile Bitfield
180 Item(Main ): End Collection, data=none
181 Item(Main ): End Collection, data=none
182 Item(Global): Usage Page, data= [ 0x0c ] 12
183 Consumer
184 Item(Local ): Usage, data= [ 0x01 ] 1
185 Consumer Control
186 Item(Main ): Collection, data= [ 0x01 ] 1
187 Application
188 Item(Global): Report ID, data= [ 0x03 ] 3
189 Item(Global): Report Size, data= [ 0x10 ] 16
190 Item(Global): Report Count, data= [ 0x02 ] 2
191 Item(Global): Logical Minimum, data= [ 0x01 ] 1
192 Item(Global): Logical Maximum, data= [ 0x8c 0x02 ] 652
193 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
194 Consumer Control
195 Item(Local ): Usage Maximum, data= [ 0x8c 0x02 ] 652
196 (null)
197 Item(Main ): Input, data= [ 0x00 ] 0
198 Data Array Absolute No_Wrap Linear
199 Preferred_State No_Null_Position Non_Volatile Bitfield
200 Item(Main ): End Collection, data=none
201 Item(Global): Usage Page, data= [ 0x01 ] 1
202 Generic Desktop Controls
203 Item(Local ): Usage, data= [ 0x80 ] 128
204 System Control
205 Item(Main ): Collection, data= [ 0x01 ] 1
206 Application
207 Item(Global): Report ID, data= [ 0x04 ] 4
208 Item(Global): Report Size, data= [ 0x02 ] 2
209 Item(Global): Report Count, data= [ 0x01 ] 1
210 Item(Global): Logical Minimum, data= [ 0x01 ] 1
211 Item(Global): Logical Maximum, data= [ 0x03 ] 3
212 Item(Local ): Usage, data= [ 0x82 ] 130
213 System Sleep
214 Item(Local ): Usage, data= [ 0x81 ] 129
215 System Power Down
216 Item(Local ): Usage, data= [ 0x83 ] 131
217 System Wake Up
218 Item(Main ): Input, data= [ 0x60 ] 96
219 Data Array Absolute No_Wrap Linear
220 No_Preferred_State Null_State Non_Volatile Bitfield
221 Item(Global): Report Size, data= [ 0x06 ] 6
222 Item(Main ): Input, data= [ 0x03 ] 3
223 Constant Variable Absolute No_Wrap Linear
224 Preferred_State No_Null_Position Non_Volatile Bitfield
225 Item(Main ): End Collection, data=none
226 Item(Global): Usage Page, data= [ 0xbc 0xff ] 65468
227 (null)
228 Item(Local ): Usage, data= [ 0x88 ] 136
229 (null)
230 Item(Main ): Collection, data= [ 0x01 ] 1
231 Application
232 Item(Global): Report ID, data= [ 0x08 ] 8
233 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
234 (null)
235 Item(Local ): Usage Maximum, data= [ 0xff ] 255
236 (null)
237 Item(Global): Logical Minimum, data= [ 0x01 ] 1
238 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
239 Item(Global): Report Size, data= [ 0x08 ] 8
240 Item(Global): Report Count, data= [ 0x01 ] 1
241 Item(Main ): Input, data= [ 0x00 ] 0
242 Data Array Absolute No_Wrap Linear
243 Preferred_State No_Null_Position Non_Volatile Bitfield
244 Item(Main ): End Collection, data=none
245 Endpoint Descriptor:
246 bLength 7
247 bDescriptorType 5
248 bEndpointAddress 0x82 EP 2 IN
249 bmAttributes 3
250 Transfer Type Interrupt
251 Synch Type None
252 Usage Type Data
253 wMaxPacketSize 0x0008 1x 8 bytes
254 bInterval 2
255 Interface Descriptor:
256 bLength 9
257 bDescriptorType 4
258 bInterfaceNumber 2
259 bAlternateSetting 0
260 bNumEndpoints 1
261 bInterfaceClass 3 Human Interface Device
262 bInterfaceSubClass 0
263 bInterfaceProtocol 0
264 iInterface 0
265 HID Device Descriptor:
266 bLength 9
267 bDescriptorType 33
268 bcdHID 1.11
269 bCountryCode 0 Not supported
270 bNumDescriptors 1
271 bDescriptorType 34 Report
272 wDescriptorLength 98
273 Report Descriptor: (length is 98)
274 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
275 (null)
276 Item(Local ): Usage, data= [ 0x01 ] 1
277 (null)
278 Item(Main ): Collection, data= [ 0x01 ] 1
279 Application
280 Item(Global): Report ID, data= [ 0x10 ] 16
281 Item(Global): Report Size, data= [ 0x08 ] 8
282 Item(Global): Report Count, data= [ 0x06 ] 6
283 Item(Global): Logical Minimum, data= [ 0x00 ] 0
284 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
285 Item(Local ): Usage, data= [ 0x01 ] 1
286 (null)
287 Item(Main ): Input, data= [ 0x00 ] 0
288 Data Array Absolute No_Wrap Linear
289 Preferred_State No_Null_Position Non_Volatile Bitfield
290 Item(Local ): Usage, data= [ 0x01 ] 1
291 (null)
292 Item(Main ): Output, data= [ 0x00 ] 0
293 Data Array Absolute No_Wrap Linear
294 Preferred_State No_Null_Position Non_Volatile Bitfield
295 Item(Main ): End Collection, data=none
296 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
297 (null)
298 Item(Local ): Usage, data= [ 0x02 ] 2
299 (null)
300 Item(Main ): Collection, data= [ 0x01 ] 1
301 Application
302 Item(Global): Report ID, data= [ 0x11 ] 17
303 Item(Global): Report Size, data= [ 0x08 ] 8
304 Item(Global): Report Count, data= [ 0x13 ] 19
305 Item(Global): Logical Minimum, data= [ 0x00 ] 0
306 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
307 Item(Local ): Usage, data= [ 0x02 ] 2
308 (null)
309 Item(Main ): Input, data= [ 0x00 ] 0
310 Data Array Absolute No_Wrap Linear
311 Preferred_State No_Null_Position Non_Volatile Bitfield
312 Item(Local ): Usage, data= [ 0x02 ] 2
313 (null)
314 Item(Main ): Output, data= [ 0x00 ] 0
315 Data Array Absolute No_Wrap Linear
316 Preferred_State No_Null_Position Non_Volatile Bitfield
317 Item(Main ): End Collection, data=none
318 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
319 (null)
320 Item(Local ): Usage, data= [ 0x04 ] 4
321 (null)
322 Item(Main ): Collection, data= [ 0x01 ] 1
323 Application
324 Item(Global): Report ID, data= [ 0x20 ] 32
325 Item(Global): Report Size, data= [ 0x08 ] 8
326 Item(Global): Report Count, data= [ 0x0e ] 14
327 Item(Global): Logical Minimum, data= [ 0x00 ] 0
328 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
329 Item(Local ): Usage, data= [ 0x41 ] 65
330 (null)
331 Item(Main ): Input, data= [ 0x00 ] 0
332 Data Array Absolute No_Wrap Linear
333 Preferred_State No_Null_Position Non_Volatile Bitfield
334 Item(Local ): Usage, data= [ 0x41 ] 65
335 (null)
336 Item(Main ): Output, data= [ 0x00 ] 0
337 Data Array Absolute No_Wrap Linear
338 Preferred_State No_Null_Position Non_Volatile Bitfield
339 Item(Global): Report ID, data= [ 0x21 ] 33
340 Item(Global): Report Count, data= [ 0x1f ] 31
341 Item(Global): Logical Minimum, data= [ 0x00 ] 0
342 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
343 Item(Local ): Usage, data= [ 0x42 ] 66
344 (null)
345 Item(Main ): Input, data= [ 0x00 ] 0
346 Data Array Absolute No_Wrap Linear
347 Preferred_State No_Null_Position Non_Volatile Bitfield
348 Item(Local ): Usage, data= [ 0x42 ] 66
349 (null)
350 Item(Main ): Output, data= [ 0x00 ] 0
351 Data Array Absolute No_Wrap Linear
352 Preferred_State No_Null_Position Non_Volatile Bitfield
353 Item(Main ): End Collection, data=none
354 Endpoint Descriptor:
355 bLength 7
356 bDescriptorType 5
357 bEndpointAddress 0x83 EP 3 IN
358 bmAttributes 3
359 Transfer Type Interrupt
360 Synch Type None
361 Usage Type Data
362 wMaxPacketSize 0x0020 1x 32 bytes
363 bInterval 2
364 Device Status: 0x0000
365 (Bus Powered)
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-logitech-hidpp-common.h"
11 #include "fu-logitech-hidpp-bootloader-nordic.h"
12
13 struct _FuLogitechHidPpBootloaderNordic
14 {
15 FuLogitechHidPpBootloader parent_instance;
16 };
17
18 G_DEFINE_TYPE (FuLogitechHidPpBootloaderNordic, fu_logitech_hidpp_bootloader_nordic, FU_TYPE_UNIFYING_BOOTLOADER)
19
20 static gchar *
21 fu_logitech_hidpp_bootloader_nordic_get_hw_platform_id (FuLogitechHidPpBootloader *self, GError **error)
22 {
23 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
24 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_HW_PLATFORM_ID;
25 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
26 g_prefix_error (error, "failed to get HW ID: ");
27 return NULL;
28 }
29 return g_strndup ((const gchar *) req->data, req->len);
30 }
31
32 static gchar *
33 fu_logitech_hidpp_bootloader_nordic_get_fw_version (FuLogitechHidPpBootloader *self, GError **error)
34 {
35 guint16 micro;
36
37 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
38 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_FW_VERSION;
39 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
40 g_prefix_error (error, "failed to get firmware version: ");
41 return NULL;
42 }
43
44 /* RRRxx.yy_Bzzzz
45 * 012345678901234*/
46 micro = (guint16) fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 10) << 8;
47 micro += fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 12);
48 return fu_logitech_hidpp_format_version ("RQR",
49 fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 3),
50 fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 6),
51 micro);
52 }
53
54 static gboolean
55 fu_logitech_hidpp_bootloader_nordic_setup (FuLogitechHidPpBootloader *self, GError **error)
56 {
57 g_autofree gchar *hw_platform_id = NULL;
58 g_autofree gchar *version_fw = NULL;
59 g_autoptr(GError) error_local = NULL;
60
61 /* get MCU */
62 hw_platform_id = fu_logitech_hidpp_bootloader_nordic_get_hw_platform_id (self, error);
63 if (hw_platform_id == NULL)
64 return FALSE;
65 g_debug ("hw-platform-id=%s", hw_platform_id);
66
67 /* get firmware version, which is not fatal */
68 version_fw = fu_logitech_hidpp_bootloader_nordic_get_fw_version (self, &error_local);
69 if (version_fw == NULL) {
70 g_warning ("failed to get firmware version: %s",
71 error_local->message);
72 fu_device_set_version (FU_DEVICE (self), "RQR12.00_B0000",
73 FWUPD_VERSION_FORMAT_PLAIN);
74 } else {
75 fu_device_set_version (FU_DEVICE (self), version_fw,
76 FWUPD_VERSION_FORMAT_PLAIN);
77 }
78
79 return TRUE;
80 }
81
82 static gboolean
83 fu_logitech_hidpp_bootloader_nordic_write_signature (FuLogitechHidPpBootloader *self,
84 guint16 addr, guint8 len, const guint8 *data,
85 GError **error)
86 {
87 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new();
88 req->cmd = 0xC0;
89 req->addr = addr;
90 req->len = len;
91 memcpy (req->data, data, req->len);
92 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
93 g_prefix_error (error, "failed to write sig @0x%02x: ", addr);
94 return FALSE;
95 }
96 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) {
97 g_set_error (error,
98 G_IO_ERROR,
99 G_IO_ERROR_FAILED,
100 "failed to write @%04x: signature is too big",
101 addr);
102 return FALSE;
103 }
104 return TRUE;
105 }
106
107 static gboolean
108 fu_logitech_hidpp_bootloader_nordic_write (FuLogitechHidPpBootloader *self,
109 guint16 addr, guint8 len, const guint8 *data,
110 GError **error)
111 {
112 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
113 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE;
114 req->addr = addr;
115 req->len = len;
116 if (req->len > 28) {
117 g_set_error (error,
118 G_IO_ERROR,
119 G_IO_ERROR_FAILED,
120 "failed to write @%04x: data length too large %02x",
121 addr, req->len);
122 return FALSE;
123 }
124 memcpy (req->data, data, req->len);
125 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
126 g_prefix_error (error, "failed to transfer fw @0x%02x: ", addr);
127 return FALSE;
128 }
129 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_ADDR) {
130 g_set_error (error,
131 G_IO_ERROR,
132 G_IO_ERROR_FAILED,
133 "failed to write @%04x: invalid address",
134 addr);
135 return FALSE;
136 }
137 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_VERIFY_FAIL) {
138 g_set_error (error,
139 G_IO_ERROR,
140 G_IO_ERROR_FAILED,
141 "failed to write @%04x: failed to verify flash content",
142 addr);
143 return FALSE;
144 }
145 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_NONZERO_START) {
146 g_debug ("wrote %d bytes at address %04x, value %02x", req->len,
147 req->addr, req->data[0]);
148 g_set_error (error,
149 G_IO_ERROR,
150 G_IO_ERROR_FAILED,
151 "failed to write @%04x: only 1 byte write of 0xff supported",
152 addr);
153 return FALSE;
154 }
155 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_CRC) {
156 g_set_error (error,
157 G_IO_ERROR,
158 G_IO_ERROR_FAILED,
159 "failed to write @%04x: invalid CRC",
160 addr);
161 return FALSE;
162 }
163 return TRUE;
164 }
165
166 static gboolean
167 fu_logitech_hidpp_bootloader_nordic_erase (FuLogitechHidPpBootloader *self, guint16 addr, GError **error)
168 {
169 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
170 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE;
171 req->addr = addr;
172 req->len = 0x01;
173 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
174 g_prefix_error (error, "failed to erase fw @0x%02x: ", addr);
175 return FALSE;
176 }
177 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR) {
178 g_set_error (error,
179 G_IO_ERROR,
180 G_IO_ERROR_FAILED,
181 "failed to erase @%04x: invalid page",
182 addr);
183 return FALSE;
184 }
185 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START) {
186 g_set_error (error,
187 G_IO_ERROR,
188 G_IO_ERROR_FAILED,
189 "failed to erase @%04x: byte 0x00 is not 0xff",
190 addr);
191 return FALSE;
192 }
193 return TRUE;
194 }
195
196 static gboolean
197 fu_logitech_hidpp_bootloader_nordic_write_firmware (FuDevice *device,
198 FuFirmware *firmware,
199 FwupdInstallFlags flags,
200 GError **error)
201 {
202 FuLogitechHidPpBootloader *self = FU_UNIFYING_BOOTLOADER (device);
203 const FuLogitechHidPpBootloaderRequest *payload;
204 guint16 addr;
205 g_autoptr(GBytes) fw = NULL;
206 g_autoptr(GPtrArray) reqs = NULL;
207
208 /* get default image */
209 fw = fu_firmware_get_image_default_bytes (firmware, error);
210 if (fw == NULL)
211 return FALSE;
212
213 /* erase firmware pages up to the bootloader */
214 fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
215 for (addr = fu_logitech_hidpp_bootloader_get_addr_lo (self);
216 addr < fu_logitech_hidpp_bootloader_get_addr_hi (self);
217 addr += fu_logitech_hidpp_bootloader_get_blocksize (self)) {
218 if (!fu_logitech_hidpp_bootloader_nordic_erase (self, addr, error))
219 return FALSE;
220 }
221
222 /* transfer payload */
223 reqs = fu_logitech_hidpp_bootloader_parse_requests (self, fw, error);
224 if (reqs == NULL)
225 return FALSE;
226 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
227 for (guint i = 1; i < reqs->len; i++) {
228 gboolean res;
229 payload = g_ptr_array_index (reqs, i);
230
231 if (payload->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
232 res = fu_logitech_hidpp_bootloader_nordic_write_signature (self,
233 payload->addr,
234 payload->len,
235 payload->data,
236 error);
237 } else {
238 res = fu_logitech_hidpp_bootloader_nordic_write (self,
239 payload->addr,
240 payload->len,
241 payload->data,
242 error);
243 }
244
245 if (!res)
246 return FALSE;
247 fu_device_set_progress_full (device, i * 32, reqs->len * 32);
248 }
249
250 /* send the first managed packet last, excluding the reset vector */
251 payload = g_ptr_array_index (reqs, 0);
252 if (!fu_logitech_hidpp_bootloader_nordic_write (self,
253 payload->addr + 1,
254 payload->len - 1,
255 payload->data + 1,
256 error))
257 return FALSE;
258
259 if (!fu_logitech_hidpp_bootloader_nordic_write (self,
260 0x0000,
261 0x01,
262 payload->data,
263 error))
264 return FALSE;
265
266 /* mark as complete */
267 fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32);
268
269 /* success! */
270 return TRUE;
271 }
272
273 static void
274 fu_logitech_hidpp_bootloader_nordic_class_init (FuLogitechHidPpBootloaderNordicClass *klass)
275 {
276 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
277 FuLogitechHidPpBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass);
278 klass_device->write_firmware = fu_logitech_hidpp_bootloader_nordic_write_firmware;
279 klass_device_bootloader->setup = fu_logitech_hidpp_bootloader_nordic_setup;
280 }
281
282 static void
283 fu_logitech_hidpp_bootloader_nordic_init (FuLogitechHidPpBootloaderNordic *self)
284 {
285 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-logitech-hidpp-bootloader.h"
9
10 #define FU_TYPE_UNIFYING_BOOTLOADER_NORDIC (fu_logitech_hidpp_bootloader_nordic_get_type ())
11 G_DECLARE_FINAL_TYPE (FuLogitechHidPpBootloaderNordic, fu_logitech_hidpp_bootloader_nordic, FU, UNIFYING_BOOTLOADER_NORDIC, FuLogitechHidPpBootloader)
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-logitech-hidpp-common.h"
11 #include "fu-logitech-hidpp-bootloader-texas.h"
12
13 struct _FuLogitechHidPpBootloaderTexas
14 {
15 FuLogitechHidPpBootloader parent_instance;
16 };
17
18 G_DEFINE_TYPE (FuLogitechHidPpBootloaderTexas, fu_logitech_hidpp_bootloader_texas, FU_TYPE_UNIFYING_BOOTLOADER)
19
20 static gboolean
21 fu_logitech_hidpp_bootloader_texas_erase_all (FuLogitechHidPpBootloader *self, GError **error)
22 {
23 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
24 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
25 req->len = 0x01; /* magic number */
26 req->data[0] = 0x00; /* magic number */
27 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
28 g_prefix_error (error, "failed to erase all pages: ");
29 return FALSE;
30 }
31 return TRUE;
32 }
33
34 static gboolean
35 fu_logitech_hidpp_bootloader_texas_compute_and_test_crc (FuLogitechHidPpBootloader *self, GError **error)
36 {
37 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
38 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
39 req->len = 0x01; /* magic number */
40 req->data[0] = 0x03; /* magic number */
41 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
42 g_prefix_error (error, "failed to compute and test CRC: ");
43 return FALSE;
44 }
45 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC) {
46 g_set_error_literal (error,
47 G_IO_ERROR,
48 G_IO_ERROR_FAILED,
49 "CRC is incorrect");
50 return FALSE;
51 }
52 return TRUE;
53 }
54
55 static gboolean
56 fu_logitech_hidpp_bootloader_texas_flash_ram_buffer (FuLogitechHidPpBootloader *self, guint16 addr, GError **error)
57 {
58 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
59 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
60 req->addr = addr;
61 req->len = 0x01; /* magic number */
62 req->data[0] = 0x01; /* magic number */
63 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
64 g_prefix_error (error, "failed to flash ram buffer @%04x: ", addr);
65 return FALSE;
66 }
67 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR) {
68 g_set_error (error,
69 G_IO_ERROR,
70 G_IO_ERROR_FAILED,
71 "failed to flash ram buffer @%04x: invalid flash page",
72 addr);
73 return FALSE;
74 }
75 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID) {
76 g_set_error (error,
77 G_IO_ERROR,
78 G_IO_ERROR_FAILED,
79 "failed to flash ram buffer @%04x: invalid App JMP vector",
80 addr);
81 return FALSE;
82 }
83 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER) {
84 g_set_error (error,
85 G_IO_ERROR,
86 G_IO_ERROR_FAILED,
87 "failed to flash ram buffer @%04x: page flashed before page 0",
88 addr);
89 return FALSE;
90 }
91 return TRUE;
92 }
93
94 static gboolean
95 fu_logitech_hidpp_bootloader_texas_clear_ram_buffer (FuLogitechHidPpBootloader *self, GError **error)
96 {
97 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
98 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
99 req->addr = 0x0000;
100 req->len = 0x01; /* magic number */
101 req->data[0] = 0x02; /* magic number */
102 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
103 g_prefix_error (error, "failed to clear ram buffer @%04x: ", req->addr);
104 return FALSE;
105 }
106 return TRUE;
107 }
108
109 static gboolean
110 fu_logitech_hidpp_bootloader_texas_write_firmware (FuDevice *device,
111 FuFirmware *firmware,
112 FwupdInstallFlags flags,
113 GError **error)
114 {
115 FuLogitechHidPpBootloader *self = FU_UNIFYING_BOOTLOADER (device);
116 const FuLogitechHidPpBootloaderRequest *payload;
117 g_autoptr(GBytes) fw = NULL;
118 g_autoptr(GPtrArray) reqs = NULL;
119 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
120
121 /* get default image */
122 fw = fu_firmware_get_image_default_bytes (firmware, error);
123 if (fw == NULL)
124 return FALSE;
125
126 /* transfer payload */
127 reqs = fu_logitech_hidpp_bootloader_parse_requests (self, fw, error);
128 if (reqs == NULL)
129 return FALSE;
130
131 /* erase all flash pages */
132 fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
133 if (!fu_logitech_hidpp_bootloader_texas_erase_all (self, error))
134 return FALSE;
135
136 /* set existing RAM buffer to 0xff's */
137 if (!fu_logitech_hidpp_bootloader_texas_clear_ram_buffer (self, error))
138 return FALSE;
139
140 /* write to RAM buffer */
141 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
142 for (guint i = 0; i < reqs->len; i++) {
143 payload = g_ptr_array_index (reqs, i);
144
145 /* check size */
146 if (payload->len != 16) {
147 g_set_error (error,
148 G_IO_ERROR,
149 G_IO_ERROR_FAILED,
150 "payload size invalid @%04x: got 0x%02x",
151 payload->addr, payload->len);
152 return FALSE;
153 }
154
155 /* build packet */
156 req->cmd = payload->cmd;
157
158 /* signature addresses do not need to fit inside 128 bytes */
159 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE)
160 req->addr = payload->addr;
161 else
162 req->addr = payload->addr % 0x80;
163
164 req->len = payload->len;
165 memcpy (req->data, payload->data, payload->len);
166 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
167 g_prefix_error (error,
168 "failed to write ram buffer @0x%02x: ",
169 req->addr);
170 return FALSE;
171 }
172 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) {
173 g_set_error (error,
174 G_IO_ERROR,
175 G_IO_ERROR_FAILED,
176 "failed to write ram buffer @%04x: invalid location",
177 req->addr);
178 return FALSE;
179 }
180 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW) {
181 g_set_error (error,
182 G_IO_ERROR,
183 G_IO_ERROR_FAILED,
184 "failed to write ram buffer @%04x: invalid size 0x%02x",
185 req->addr, req->len);
186 return FALSE;
187 }
188
189 /* flush RAM buffer to EEPROM */
190 if ((payload->addr + 0x10) % 0x80 == 0 &&
191 req->cmd != FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
192 guint16 addr_start = payload->addr - (7 * 0x10);
193 g_debug ("addr flush @ 0x%04x for 0x%04x",
194 payload->addr, addr_start);
195 if (!fu_logitech_hidpp_bootloader_texas_flash_ram_buffer (self,
196 addr_start,
197 error)) {
198 g_prefix_error (error,
199 "failed to flash ram buffer @0x%04x: ",
200 addr_start);
201 return FALSE;
202 }
203 }
204
205 /* update progress */
206 fu_device_set_progress_full (device, i * 32, reqs->len * 32);
207 }
208
209 /* check CRC */
210 if (!fu_logitech_hidpp_bootloader_texas_compute_and_test_crc (self, error))
211 return FALSE;
212
213 /* mark as complete */
214 fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32);
215
216 /* success! */
217 return TRUE;
218 }
219
220 static gboolean
221 fu_logitech_hidpp_bootloader_texas_setup (FuLogitechHidPpBootloader *self, GError **error)
222 {
223 fu_device_set_version (FU_DEVICE (self), "RQR24.00_B0000",
224 FWUPD_VERSION_FORMAT_PLAIN);
225 return TRUE;
226 }
227
228 static void
229 fu_logitech_hidpp_bootloader_texas_class_init (FuLogitechHidPpBootloaderTexasClass *klass)
230 {
231 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
232 FuLogitechHidPpBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass);
233 klass_device->write_firmware = fu_logitech_hidpp_bootloader_texas_write_firmware;
234 klass_device_bootloader->setup = fu_logitech_hidpp_bootloader_texas_setup;
235 }
236
237 static void
238 fu_logitech_hidpp_bootloader_texas_init (FuLogitechHidPpBootloaderTexas *self)
239 {
240 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-logitech-hidpp-bootloader.h"
9
10 #define FU_TYPE_UNIFYING_BOOTLOADER_TEXAS (fu_logitech_hidpp_bootloader_texas_get_type ())
11 G_DECLARE_FINAL_TYPE (FuLogitechHidPpBootloaderTexas, fu_logitech_hidpp_bootloader_texas, FU, UNIFYING_BOOTLOADER_TEXAS, FuLogitechHidPpBootloader)
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-firmware-common.h"
11 #include "fu-logitech-hidpp-common.h"
12 #include "fu-logitech-hidpp-bootloader.h"
13 #include "fu-logitech-hidpp-hidpp.h"
14
15 typedef struct
16 {
17 guint16 flash_addr_lo;
18 guint16 flash_addr_hi;
19 guint16 flash_blocksize;
20 } FuLogitechHidPpBootloaderPrivate;
21
22 #define FU_UNIFYING_DEVICE_EP1 0x81
23 #define FU_UNIFYING_DEVICE_EP3 0x83
24
25 G_DEFINE_TYPE_WITH_PRIVATE (FuLogitechHidPpBootloader, fu_logitech_hidpp_bootloader, FU_TYPE_USB_DEVICE)
26
27 #define GET_PRIVATE(o) (fu_logitech_hidpp_bootloader_get_instance_private (o))
28
29 static void
30 fu_logitech_hidpp_bootloader_to_string (FuDevice *device, guint idt, GString *str)
31 {
32 FuLogitechHidPpBootloader *self = FU_UNIFYING_BOOTLOADER (device);
33 FuLogitechHidPpBootloaderPrivate *priv = GET_PRIVATE (self);
34 fu_common_string_append_kx (str, idt, "FlashAddrHigh", priv->flash_addr_hi);
35 fu_common_string_append_kx (str, idt, "FlashAddrLow", priv->flash_addr_lo);
36 fu_common_string_append_kx (str, idt, "FlashBlockSize", priv->flash_blocksize);
37 }
38
39 FuLogitechHidPpBootloaderRequest *
40 fu_logitech_hidpp_bootloader_request_new (void)
41 {
42 FuLogitechHidPpBootloaderRequest *req = g_new0 (FuLogitechHidPpBootloaderRequest, 1);
43 return req;
44 }
45
46 GPtrArray *
47 fu_logitech_hidpp_bootloader_parse_requests (FuLogitechHidPpBootloader *self, GBytes *fw, GError **error)
48 {
49 const gchar *tmp;
50 g_auto(GStrv) lines = NULL;
51 g_autoptr(GPtrArray) reqs = NULL;
52 guint32 last_addr = 0;
53
54 reqs = g_ptr_array_new_with_free_func (g_free);
55 tmp = g_bytes_get_data (fw, NULL);
56 lines = g_strsplit_set (tmp, "\n\r", -1);
57 for (guint i = 0; lines[i] != NULL; i++) {
58 g_autoptr(FuLogitechHidPpBootloaderRequest) payload = NULL;
59 guint8 rec_type = 0x00;
60 guint16 offset = 0x0000;
61 gboolean exit = FALSE;
62
63 /* skip empty lines */
64 tmp = lines[i];
65 if (strlen (tmp) < 5)
66 continue;
67
68 payload = fu_logitech_hidpp_bootloader_request_new ();
69 payload->len = fu_logitech_hidpp_buffer_read_uint8 (tmp + 0x01);
70 if (payload->len > 28) {
71 g_set_error (error,
72 G_IO_ERROR,
73 G_IO_ERROR_INVALID_DATA,
74 "firmware data invalid: too large %u bytes",
75 payload->len);
76 return NULL;
77 }
78 payload->addr = fu_firmware_strparse_uint16 (tmp + 0x03);
79 payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER;
80
81 rec_type = fu_logitech_hidpp_buffer_read_uint8 (tmp + 0x07);
82
83 switch (rec_type) {
84 case 0x00: /* data */
85 break;
86 case 0x01: /* EOF */
87 exit = TRUE;
88 break;
89 case 0x03: /* start segment address */
90 /* this is used to specify the start address,
91 it is doesn't mater in this context so we can
92 safely ignore it */
93 continue;
94 case 0x04: /* extended linear address */
95 offset = fu_firmware_strparse_uint16 (tmp + 0x09);
96 if (offset != 0x0000) {
97 g_set_error (error,
98 G_IO_ERROR,
99 G_IO_ERROR_INVALID_DATA,
100 "extended linear addresses with offset different from 0 are not supported");
101 return NULL;
102 }
103 continue;
104 case 0x05: /* start linear address */
105 /* this is used to specify the start address,
106 it is doesn't mater in this context so we can
107 safely ignore it */
108 continue;
109 case 0xFD: /* custom - vendor */
110 /* record type of 0xFD indicates signature data */
111 payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE;
112 break;
113 default:
114 g_set_error (error,
115 G_IO_ERROR,
116 G_IO_ERROR_INVALID_DATA,
117 "intel hex file record type %02x not supported",
118 rec_type);
119 return NULL;
120 }
121
122 if (exit)
123 break;
124
125 /* read the data, but skip the checksum byte */
126 for (guint j = 0; j < payload->len; j++) {
127 const gchar *ptr = tmp + 0x09 + (j * 2);
128 if (ptr[0] == '\0') {
129 g_set_error (error,
130 G_IO_ERROR,
131 G_IO_ERROR_INVALID_DATA,
132 "firmware data invalid: expected %u bytes",
133 payload->len);
134 return NULL;
135 }
136 payload->data[j] = fu_logitech_hidpp_buffer_read_uint8 (ptr);
137 }
138
139 /* no need to bound check signature addresses */
140 if (payload->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
141 g_ptr_array_add (reqs, g_steal_pointer (&payload));
142 continue;
143 }
144
145 /* skip the bootloader */
146 if (payload->addr > fu_logitech_hidpp_bootloader_get_addr_hi (self)) {
147 g_debug ("skipping write @ %04x", payload->addr);
148 continue;
149 }
150
151 /* skip the header */
152 if (payload->addr < fu_logitech_hidpp_bootloader_get_addr_lo (self)) {
153 g_debug ("skipping write @ %04x", payload->addr);
154 continue;
155 }
156
157 /* make sure firmware addresses only go up */
158 if (payload->addr < last_addr) {
159 g_debug ("skipping write @ %04x", payload->addr);
160 continue;
161 }
162 last_addr = payload->addr;
163
164 /* pending */
165 g_ptr_array_add (reqs, g_steal_pointer (&payload));
166 }
167 if (reqs->len == 0) {
168 g_set_error_literal (error,
169 G_IO_ERROR,
170 G_IO_ERROR_INVALID_DATA,
171 "firmware data invalid: no payloads found");
172 return NULL;
173 }
174 return g_steal_pointer (&reqs);
175 }
176
177 guint16
178 fu_logitech_hidpp_bootloader_get_addr_lo (FuLogitechHidPpBootloader *self)
179 {
180 FuLogitechHidPpBootloaderPrivate *priv = GET_PRIVATE (self);
181 g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000);
182 return priv->flash_addr_lo;
183 }
184
185 guint16
186 fu_logitech_hidpp_bootloader_get_addr_hi (FuLogitechHidPpBootloader *self)
187 {
188 FuLogitechHidPpBootloaderPrivate *priv = GET_PRIVATE (self);
189 g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000);
190 return priv->flash_addr_hi;
191 }
192
193 guint16
194 fu_logitech_hidpp_bootloader_get_blocksize (FuLogitechHidPpBootloader *self)
195 {
196 FuLogitechHidPpBootloaderPrivate *priv = GET_PRIVATE (self);
197 g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000);
198 return priv->flash_blocksize;
199 }
200
201 static gboolean
202 fu_logitech_hidpp_bootloader_attach (FuDevice *device, GError **error)
203 {
204 FuLogitechHidPpBootloader *self = FU_UNIFYING_BOOTLOADER (device);
205 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
206 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_REBOOT;
207 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
208 g_prefix_error (error, "failed to attach back to runtime: ");
209 return FALSE;
210 }
211 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
212 return TRUE;
213 }
214
215 static gboolean
216 fu_logitech_hidpp_bootloader_set_bl_version (FuLogitechHidPpBootloader *self, GError **error)
217 {
218 guint16 build;
219 g_autofree gchar *version = NULL;
220 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
221
222 /* call into hardware */
223 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_BL_VERSION;
224 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
225 g_prefix_error (error, "failed to get firmware version: ");
226 return FALSE;
227 }
228
229 /* BOTxx.yy_Bzzzz
230 * 012345678901234 */
231 build = (guint16) fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 10) << 8;
232 build += fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 12);
233 version = fu_logitech_hidpp_format_version ("BOT",
234 fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 3),
235 fu_logitech_hidpp_buffer_read_uint8 ((const gchar *) req->data + 6),
236 build);
237 if (version == NULL) {
238 g_prefix_error (error, "failed to format firmware version: ");
239 return FALSE;
240 }
241 fu_device_set_version_bootloader (FU_DEVICE (self), version);
242 return TRUE;
243 }
244
245 static gboolean
246 fu_logitech_hidpp_bootloader_open (FuUsbDevice *device, GError **error)
247 {
248 GUsbDevice *usb_device = fu_usb_device_get_dev (device);
249 const guint idx = 0x00;
250
251 /* claim the only interface */
252 if (!g_usb_device_claim_interface (usb_device, idx,
253 G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
254 error)) {
255 g_prefix_error (error, "Failed to claim 0x%02x: ", idx);
256 return FALSE;
257 }
258
259 /* success */
260 return TRUE;
261 }
262
263 static gboolean
264 fu_logitech_hidpp_bootloader_setup (FuDevice *device, GError **error)
265 {
266 FuLogitechHidPpBootloaderClass *klass = FU_UNIFYING_BOOTLOADER_GET_CLASS (device);
267 FuLogitechHidPpBootloader *self = FU_UNIFYING_BOOTLOADER (device);
268 FuLogitechHidPpBootloaderPrivate *priv = GET_PRIVATE (self);
269 g_autoptr(FuLogitechHidPpBootloaderRequest) req = fu_logitech_hidpp_bootloader_request_new ();
270
271 /* get memory map */
272 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO;
273 if (!fu_logitech_hidpp_bootloader_request (self, req, error)) {
274 g_prefix_error (error, "failed to get meminfo: ");
275 return FALSE;
276 }
277 if (req->len != 0x06) {
278 g_set_error (error,
279 G_IO_ERROR,
280 G_IO_ERROR_FAILED,
281 "failed to get meminfo: invalid size %02x",
282 req->len);
283 return FALSE;
284 }
285
286 /* parse values */
287 priv->flash_addr_lo = fu_common_read_uint16 (req->data + 0, G_BIG_ENDIAN);
288 priv->flash_addr_hi = fu_common_read_uint16 (req->data + 2, G_BIG_ENDIAN);
289 priv->flash_blocksize = fu_common_read_uint16 (req->data + 4, G_BIG_ENDIAN);
290
291 /* get bootloader version */
292 if (!fu_logitech_hidpp_bootloader_set_bl_version (self, error))
293 return FALSE;
294
295 /* subclassed further */
296 if (klass->setup != NULL)
297 return klass->setup (self, error);
298
299 /* success */
300 return TRUE;
301 }
302
303 static gboolean
304 fu_logitech_hidpp_bootloader_close (FuUsbDevice *device, GError **error)
305 {
306 GUsbDevice *usb_device = fu_usb_device_get_dev (device);
307 if (usb_device != NULL) {
308 if (!g_usb_device_release_interface (usb_device, 0x00,
309 G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
310 error)) {
311 return FALSE;
312 }
313 }
314 return TRUE;
315 }
316
317 gboolean
318 fu_logitech_hidpp_bootloader_request (FuLogitechHidPpBootloader *self,
319 FuLogitechHidPpBootloaderRequest *req,
320 GError **error)
321 {
322 GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
323 gsize actual_length = 0;
324 guint8 buf_request[32];
325 guint8 buf_response[32];
326
327 /* build packet */
328 memset (buf_request, 0x00, sizeof (buf_request));
329 buf_request[0x00] = req->cmd;
330 buf_request[0x01] = req->addr >> 8;
331 buf_request[0x02] = req->addr & 0xff;
332 buf_request[0x03] = req->len;
333 if (!fu_memcpy_safe (buf_request, sizeof(buf_request), 0x04, /* dst */
334 req->data, sizeof(req->data), 0x0, /* src */
335 sizeof(req->data), error))
336 return FALSE;
337
338 /* send request */
339 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
340 fu_common_dump_raw (G_LOG_DOMAIN, "host->device",
341 buf_request, sizeof (buf_request));
342 }
343 if (usb_device != NULL) {
344 if (!g_usb_device_control_transfer (usb_device,
345 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
346 G_USB_DEVICE_REQUEST_TYPE_CLASS,
347 G_USB_DEVICE_RECIPIENT_INTERFACE,
348 HID_REPORT_SET,
349 0x0200, 0x0000,
350 buf_request,
351 sizeof (buf_request),
352 &actual_length,
353 FU_UNIFYING_DEVICE_TIMEOUT_MS,
354 NULL,
355 error)) {
356 g_prefix_error (error, "failed to send data: ");
357 return FALSE;
358 }
359 }
360
361 /* no response required when rebooting */
362 if (usb_device != NULL &&
363 req->cmd == FU_UNIFYING_BOOTLOADER_CMD_REBOOT) {
364 g_autoptr(GError) error_ignore = NULL;
365 if (!g_usb_device_interrupt_transfer (usb_device,
366 FU_UNIFYING_DEVICE_EP1,
367 buf_response,
368 sizeof (buf_response),
369 &actual_length,
370 FU_UNIFYING_DEVICE_TIMEOUT_MS,
371 NULL,
372 &error_ignore)) {
373 g_debug ("ignoring: %s", error_ignore->message);
374 } else {
375 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
376 fu_common_dump_raw (G_LOG_DOMAIN, "device->host",
377 buf_response, actual_length);
378 }
379 }
380 return TRUE;
381 }
382
383 /* get response */
384 memset (buf_response, 0x00, sizeof (buf_response));
385 if (usb_device != NULL) {
386 if (!g_usb_device_interrupt_transfer (usb_device,
387 FU_UNIFYING_DEVICE_EP1,
388 buf_response,
389 sizeof (buf_response),
390 &actual_length,
391 FU_UNIFYING_DEVICE_TIMEOUT_MS,
392 NULL,
393 error)) {
394 g_prefix_error (error, "failed to get data: ");
395 return FALSE;
396 }
397 } else {
398 /* emulated */
399 buf_response[0] = buf_request[0];
400 if (buf_response[0] == FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO) {
401 buf_response[3] = 0x06; /* len */
402 buf_response[4] = 0x40; /* lo MSB */
403 buf_response[5] = 0x00; /* lo LSB */
404 buf_response[6] = 0x6b; /* hi MSB */
405 buf_response[7] = 0xff; /* hi LSB */
406 buf_response[8] = 0x00; /* bs MSB */
407 buf_response[9] = 0x80; /* bs LSB */
408 }
409 actual_length = sizeof (buf_response);
410 }
411 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
412 fu_common_dump_raw (G_LOG_DOMAIN, "device->host",
413 buf_response, actual_length);
414 }
415
416 /* parse response */
417 if ((buf_response[0x00] & 0xf0) != req->cmd) {
418 g_set_error (error,
419 G_IO_ERROR,
420 G_IO_ERROR_FAILED,
421 "invalid command response of %02x, expected %02x",
422 buf_response[0x00], req->cmd);
423 return FALSE;
424 }
425 req->cmd = buf_response[0x00];
426 req->addr = ((guint16) buf_response[0x01] << 8) + buf_response[0x02];
427 req->len = buf_response[0x03];
428 if (req->len > 28) {
429 g_set_error (error,
430 G_IO_ERROR,
431 G_IO_ERROR_FAILED,
432 "invalid data size of %02x", req->len);
433 return FALSE;
434 }
435 memset (req->data, 0x00, 28);
436 if (req->len > 0)
437 memcpy (req->data, buf_response + 0x04, req->len);
438 return TRUE;
439 }
440
441 static void
442 fu_logitech_hidpp_bootloader_init (FuLogitechHidPpBootloader *self)
443 {
444 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
445 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
446 fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard");
447 fu_device_set_name (FU_DEVICE (self), "Unifying Receiver");
448 fu_device_set_summary (FU_DEVICE (self), "A miniaturised USB wireless receiver (bootloader)");
449 fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN);
450 fu_device_set_remove_delay (FU_DEVICE (self), FU_UNIFYING_DEVICE_TIMEOUT_MS);
451 }
452
453 static void
454 fu_logitech_hidpp_bootloader_class_init (FuLogitechHidPpBootloaderClass *klass)
455 {
456 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
457 FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
458 klass_device->to_string = fu_logitech_hidpp_bootloader_to_string;
459 klass_device->attach = fu_logitech_hidpp_bootloader_attach;
460 klass_device->setup = fu_logitech_hidpp_bootloader_setup;
461 klass_usb_device->open = fu_logitech_hidpp_bootloader_open;
462 klass_usb_device->close = fu_logitech_hidpp_bootloader_close;
463 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-usb-device.h"
9
10 #define FU_TYPE_UNIFYING_BOOTLOADER (fu_logitech_hidpp_bootloader_get_type ())
11 G_DECLARE_DERIVABLE_TYPE (FuLogitechHidPpBootloader, fu_logitech_hidpp_bootloader, FU, UNIFYING_BOOTLOADER, FuUsbDevice)
12
13 struct _FuLogitechHidPpBootloaderClass
14 {
15 FuUsbDeviceClass parent_class;
16 gboolean (*setup) (FuLogitechHidPpBootloader *self,
17 GError **error);
18 };
19
20 typedef enum {
21 FU_UNIFYING_BOOTLOADER_CMD_GENERAL_ERROR = 0x01,
22 FU_UNIFYING_BOOTLOADER_CMD_READ = 0x10,
23 FU_UNIFYING_BOOTLOADER_CMD_WRITE = 0x20,
24 FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_ADDR = 0x21,
25 FU_UNIFYING_BOOTLOADER_CMD_WRITE_VERIFY_FAIL = 0x22,
26 FU_UNIFYING_BOOTLOADER_CMD_WRITE_NONZERO_START = 0x23,
27 FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_CRC = 0x24,
28 FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE = 0x30,
29 FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR = 0x31,
30 FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START = 0x33,
31 FU_UNIFYING_BOOTLOADER_CMD_GET_HW_PLATFORM_ID = 0x40,
32 FU_UNIFYING_BOOTLOADER_CMD_GET_FW_VERSION = 0x50,
33 FU_UNIFYING_BOOTLOADER_CMD_GET_CHECKSUM = 0x60,
34 FU_UNIFYING_BOOTLOADER_CMD_REBOOT = 0x70,
35 FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO = 0x80,
36 FU_UNIFYING_BOOTLOADER_CMD_GET_BL_VERSION = 0x90,
37 FU_UNIFYING_BOOTLOADER_CMD_GET_INIT_FW_VERSION = 0xa0,
38 FU_UNIFYING_BOOTLOADER_CMD_READ_SIGNATURE = 0xb0,
39 FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER = 0xc0,
40 FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR= 0xc1,
41 FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW = 0xc2,
42 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM = 0xd0,
43 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR = 0xd1,
44 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC = 0xd2,
45 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID = 0xd3,
46 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER = 0xd4,
47 FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE = 0xe0,
48 FU_UNIFYING_BOOTLOADER_CMD_LAST
49 } FuLogitechHidPpBootloaderCmd;
50
51 /* packet to and from device */
52 typedef struct __attribute__((packed)) {
53 guint8 cmd;
54 guint16 addr;
55 guint8 len;
56 guint8 data[28];
57 } FuLogitechHidPpBootloaderRequest;
58
59 FuLogitechHidPpBootloaderRequest *fu_logitech_hidpp_bootloader_request_new (void);
60
61 #pragma clang diagnostic push
62 #pragma clang diagnostic ignored "-Wunused-function"
63 G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuLogitechHidPpBootloaderRequest, g_free);
64 #pragma clang diagnostic pop
65
66 GPtrArray *fu_logitech_hidpp_bootloader_parse_requests (FuLogitechHidPpBootloader *self,
67 GBytes *fw,
68 GError **error);
69 gboolean fu_logitech_hidpp_bootloader_request (FuLogitechHidPpBootloader *self,
70 FuLogitechHidPpBootloaderRequest *req,
71 GError **error);
72
73 guint16 fu_logitech_hidpp_bootloader_get_addr_lo (FuLogitechHidPpBootloader *self);
74 guint16 fu_logitech_hidpp_bootloader_get_addr_hi (FuLogitechHidPpBootloader *self);
75 guint16 fu_logitech_hidpp_bootloader_get_blocksize (FuLogitechHidPpBootloader *self);
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <gio/gio.h>
12
13 #include "fu-logitech-hidpp-common.h"
14
15 guint8
16 fu_logitech_hidpp_buffer_read_uint8 (const gchar *str)
17 {
18 guint64 tmp;
19 gchar buf[3] = { 0x0, 0x0, 0x0 };
20 memcpy (buf, str, 2);
21 tmp = g_ascii_strtoull (buf, NULL, 16);
22 return tmp;
23 }
24
25 guint16
26 fu_logitech_hidpp_buffer_read_uint16 (const gchar *str)
27 {
28 guint64 tmp;
29 gchar buf[5] = { 0x0, 0x0, 0x0, 0x0, 0x0 };
30 memcpy (buf, str, 4);
31 tmp = g_ascii_strtoull (buf, NULL, 16);
32 return tmp;
33 }
34
35 gchar *
36 fu_logitech_hidpp_format_version (const gchar *name, guint8 major, guint8 minor, guint16 build)
37 {
38 GString *str = g_string_new (NULL);
39 for (guint i = 0; i < 3; i++) {
40 if (g_ascii_isspace (name[i]))
41 continue;
42 g_string_append_c (str, name[i]);
43 }
44 g_string_append_printf (str, "%02x.%02x_B%04x", major, minor, build);
45 return g_string_free (str, FALSE);
46 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include <glib.h>
9
10 #define FU_UNIFYING_DEVICE_VID 0x046d
11
12 #define FU_UNIFYING_DEVICE_PID_RUNTIME 0xc52b
13 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC 0xaaaa
14 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC_PICO 0xaaae
15 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS 0xaaac
16 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS_PICO 0xaaad
17
18 /* Signed firmware are very long to verify on the device */
19 #define FU_UNIFYING_DEVICE_TIMEOUT_MS 30000
20
21 guint8 fu_logitech_hidpp_buffer_read_uint8 (const gchar *str);
22 guint16 fu_logitech_hidpp_buffer_read_uint16 (const gchar *str);
23
24 gchar *fu_logitech_hidpp_format_version (const gchar *name,
25 guint8 major,
26 guint8 minor,
27 guint16 build);
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-logitech-hidpp-hidpp.h"
11 #include "fu-logitech-hidpp-hidpp-msg.h"
12
13 FuLogitechHidPpHidppMsg *
14 fu_logitech_hidpp_msg_new (void)
15 {
16 return g_new0 (FuLogitechHidPpHidppMsg, 1);
17 }
18
19 const gchar *
20 fu_logitech_hidpp_msg_dev_id_to_string (FuLogitechHidPpHidppMsg *msg)
21 {
22 g_return_val_if_fail (msg != NULL, NULL);
23 if (msg->device_id == HIDPP_DEVICE_ID_WIRED)
24 return "wired";
25 if (msg->device_id == HIDPP_DEVICE_ID_RECEIVER)
26 return "receiver";
27 if (msg->device_id == HIDPP_DEVICE_ID_UNSET)
28 return "unset";
29 return NULL;
30 }
31
32 const gchar *
33 fu_logitech_hidpp_msg_rpt_id_to_string (FuLogitechHidPpHidppMsg *msg)
34 {
35 g_return_val_if_fail (msg != NULL, NULL);
36 if (msg->report_id == HIDPP_REPORT_ID_SHORT)
37 return "short";
38 if (msg->report_id == HIDPP_REPORT_ID_LONG)
39 return "long";
40 if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG)
41 return "very-long";
42 return NULL;
43 }
44
45 gsize
46 fu_logitech_hidpp_msg_get_payload_length (FuLogitechHidPpHidppMsg *msg)
47 {
48 if (msg->report_id == HIDPP_REPORT_ID_SHORT)
49 return 0x07;
50 if (msg->report_id == HIDPP_REPORT_ID_LONG)
51 return 0x14;
52 if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG)
53 return 0x2f;
54 if (msg->report_id == HIDPP_REPORT_NOTIFICATION)
55 return 0x08;
56 return 0x0;
57 }
58
59 const gchar *
60 fu_logitech_hidpp_msg_fcn_id_to_string (FuLogitechHidPpHidppMsg *msg)
61 {
62 g_return_val_if_fail (msg != NULL, NULL);
63 switch (msg->sub_id) {
64 case HIDPP_SUBID_SET_REGISTER:
65 case HIDPP_SUBID_GET_REGISTER:
66 case HIDPP_SUBID_SET_LONG_REGISTER:
67 case HIDPP_SUBID_GET_LONG_REGISTER:
68 case HIDPP_SUBID_SET_VERY_LONG_REGISTER:
69 case HIDPP_SUBID_GET_VERY_LONG_REGISTER:
70 if (msg->function_id == HIDPP_REGISTER_HIDPP_NOTIFICATIONS)
71 return "hidpp-notifications";
72 if (msg->function_id == HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES)
73 return "individual-features";
74 if (msg->function_id == HIDPP_REGISTER_BATTERY_STATUS)
75 return "battery-status";
76 if (msg->function_id == HIDPP_REGISTER_BATTERY_MILEAGE)
77 return "battery-mileage";
78 if (msg->function_id == HIDPP_REGISTER_PROFILE)
79 return "profile";
80 if (msg->function_id == HIDPP_REGISTER_LED_STATUS)
81 return "led-status";
82 if (msg->function_id == HIDPP_REGISTER_LED_INTENSITY)
83 return "led-intensity";
84 if (msg->function_id == HIDPP_REGISTER_LED_COLOR)
85 return "led-color";
86 if (msg->function_id == HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS)
87 return "optical-sensor-settings";
88 if (msg->function_id == HIDPP_REGISTER_CURRENT_RESOLUTION)
89 return "current-resolution";
90 if (msg->function_id == HIDPP_REGISTER_USB_REFRESH_RATE)
91 return "usb-refresh-rate";
92 if (msg->function_id == HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT)
93 return "generic-memory-management";
94 if (msg->function_id == HIDPP_REGISTER_HOT_CONTROL)
95 return "hot-control";
96 if (msg->function_id == HIDPP_REGISTER_READ_MEMORY)
97 return "read-memory";
98 if (msg->function_id == HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION)
99 return "device-connection-disconnection";
100 if (msg->function_id == HIDPP_REGISTER_PAIRING_INFORMATION)
101 return "pairing-information";
102 if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE)
103 return "device-firmware-update-mode";
104 if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION)
105 return "device-firmware-information";
106 break;
107 default:
108 break;
109 }
110 return NULL;
111
112 }
113
114 const gchar *
115 fu_logitech_hidpp_msg_sub_id_to_string (FuLogitechHidPpHidppMsg *msg)
116 {
117 g_return_val_if_fail (msg != NULL, NULL);
118 if (msg->sub_id == HIDPP_SUBID_VENDOR_SPECIFIC_KEYS)
119 return "vendor-specific-keys";
120 if (msg->sub_id == HIDPP_SUBID_POWER_KEYS)
121 return "power-keys";
122 if (msg->sub_id == HIDPP_SUBID_ROLLER)
123 return "roller";
124 if (msg->sub_id == HIDPP_SUBID_MOUSE_EXTRA_BUTTONS)
125 return "mouse-extra-buttons";
126 if (msg->sub_id == HIDPP_SUBID_BATTERY_CHARGING_LEVEL)
127 return "battery-charging-level";
128 if (msg->sub_id == HIDPP_SUBID_USER_INTERFACE_EVENT)
129 return "user-interface-event";
130 if (msg->sub_id == HIDPP_SUBID_F_LOCK_STATUS)
131 return "f-lock-status";
132 if (msg->sub_id == HIDPP_SUBID_CALCULATOR_RESULT)
133 return "calculator-result";
134 if (msg->sub_id == HIDPP_SUBID_MENU_NAVIGATE)
135 return "menu-navigate";
136 if (msg->sub_id == HIDPP_SUBID_FN_KEY)
137 return "fn-key";
138 if (msg->sub_id == HIDPP_SUBID_BATTERY_MILEAGE)
139 return "battery-mileage";
140 if (msg->sub_id == HIDPP_SUBID_UART_RX)
141 return "uart-rx";
142 if (msg->sub_id == HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE)
143 return "backlight-duration-update";
144 if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCONNECTION)
145 return "device-disconnection";
146 if (msg->sub_id == HIDPP_SUBID_DEVICE_CONNECTION)
147 return "device-connection";
148 if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCOVERY)
149 return "device-discovery";
150 if (msg->sub_id == HIDPP_SUBID_PIN_CODE_REQUEST)
151 return "pin-code-request";
152 if (msg->sub_id == HIDPP_SUBID_RECEIVER_WORKING_MODE)
153 return "receiver-working-mode";
154 if (msg->sub_id == HIDPP_SUBID_ERROR_MESSAGE)
155 return "error-message";
156 if (msg->sub_id == HIDPP_SUBID_RF_LINK_CHANGE)
157 return "rf-link-change";
158 if (msg->sub_id == HIDPP_SUBID_HCI)
159 return "hci";
160 if (msg->sub_id == HIDPP_SUBID_LINK_QUALITY)
161 return "link-quality";
162 if (msg->sub_id == HIDPP_SUBID_DEVICE_LOCKING_CHANGED)
163 return "device-locking-changed";
164 if (msg->sub_id == HIDPP_SUBID_WIRELESS_DEVICE_CHANGE)
165 return "wireless-device-change";
166 if (msg->sub_id == HIDPP_SUBID_ACL)
167 return "acl";
168 if (msg->sub_id == HIDPP_SUBID_VOIP_TELEPHONY_EVENT)
169 return "voip-telephony-event";
170 if (msg->sub_id == HIDPP_SUBID_LED)
171 return "led";
172 if (msg->sub_id == HIDPP_SUBID_GESTURE_AND_AIR)
173 return "gesture-and-air";
174 if (msg->sub_id == HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH)
175 return "touchpad-multi-touch";
176 if (msg->sub_id == HIDPP_SUBID_TRACEABILITY)
177 return "traceability";
178 if (msg->sub_id == HIDPP_SUBID_SET_REGISTER)
179 return "set-register";
180 if (msg->sub_id == HIDPP_SUBID_GET_REGISTER)
181 return "get-register";
182 if (msg->sub_id == HIDPP_SUBID_SET_LONG_REGISTER)
183 return "set-long-register";
184 if (msg->sub_id == HIDPP_SUBID_GET_LONG_REGISTER)
185 return "get-long-register";
186 if (msg->sub_id == HIDPP_SUBID_SET_VERY_LONG_REGISTER)
187 return "set-very-long-register";
188 if (msg->sub_id == HIDPP_SUBID_GET_VERY_LONG_REGISTER)
189 return "get-very-long-register";
190 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG)
191 return "error-msg";
192 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20)
193 return "error-msg-v2";
194 return NULL;
195 }
196
197 gboolean
198 fu_logitech_hidpp_msg_is_reply (FuLogitechHidPpHidppMsg *msg1, FuLogitechHidPpHidppMsg *msg2)
199 {
200 g_return_val_if_fail (msg1 != NULL, FALSE);
201 g_return_val_if_fail (msg2 != NULL, FALSE);
202 if (msg1->device_id != msg2->device_id &&
203 msg1->device_id != HIDPP_DEVICE_ID_UNSET &&
204 msg2->device_id != HIDPP_DEVICE_ID_UNSET)
205 return FALSE;
206 if (msg1->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID ||
207 msg2->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID)
208 return TRUE;
209 if (msg1->sub_id != msg2->sub_id)
210 return FALSE;
211 if (msg1->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID ||
212 msg2->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID)
213 return TRUE;
214 if (msg1->function_id != msg2->function_id)
215 return FALSE;
216 return TRUE;
217 }
218
219 /* HID++ error */
220 gboolean
221 fu_logitech_hidpp_msg_is_error (FuLogitechHidPpHidppMsg *msg, GError **error)
222 {
223 g_return_val_if_fail (msg != NULL, FALSE);
224 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG) {
225 switch (msg->data[1]) {
226 case HIDPP_ERR_INVALID_SUBID:
227 g_set_error_literal (error,
228 G_IO_ERROR,
229 G_IO_ERROR_NOT_SUPPORTED,
230 "invalid SubID");
231 break;
232 case HIDPP_ERR_INVALID_ADDRESS:
233 g_set_error_literal (error,
234 G_IO_ERROR,
235 G_IO_ERROR_INVALID_DATA,
236 "invalid address");
237 break;
238 case HIDPP_ERR_INVALID_VALUE:
239 g_set_error_literal (error,
240 G_IO_ERROR,
241 G_IO_ERROR_INVALID_DATA,
242 "invalid value");
243 break;
244 case HIDPP_ERR_CONNECT_FAIL:
245 g_set_error_literal (error,
246 G_IO_ERROR,
247 G_IO_ERROR_FAILED,
248 "connection request failed");
249 break;
250 case HIDPP_ERR_TOO_MANY_DEVICES:
251 g_set_error_literal (error,
252 G_IO_ERROR,
253 G_IO_ERROR_NO_SPACE,
254 "too many devices connected");
255 break;
256 case HIDPP_ERR_ALREADY_EXISTS:
257 g_set_error_literal (error,
258 G_IO_ERROR,
259 G_IO_ERROR_EXISTS,
260 "already exists");
261 break;
262 case HIDPP_ERR_BUSY:
263 g_set_error_literal (error,
264 G_IO_ERROR,
265 G_IO_ERROR_BUSY,
266 "busy");
267 break;
268 case HIDPP_ERR_UNKNOWN_DEVICE:
269 g_set_error_literal (error,
270 G_IO_ERROR,
271 G_IO_ERROR_NOT_FOUND,
272 "unknown device");
273 break;
274 case HIDPP_ERR_RESOURCE_ERROR:
275 g_set_error_literal (error,
276 G_IO_ERROR,
277 G_IO_ERROR_HOST_UNREACHABLE,
278 "resource error");
279 break;
280 case HIDPP_ERR_REQUEST_UNAVAILABLE:
281 g_set_error_literal (error,
282 G_IO_ERROR,
283 G_IO_ERROR_EXISTS,
284 "request not valid in current context");
285 break;
286 case HIDPP_ERR_INVALID_PARAM_VALUE:
287 g_set_error_literal (error,
288 G_IO_ERROR,
289 G_IO_ERROR_INVALID_DATA,
290 "request parameter has unsupported value");
291 break;
292 case HIDPP_ERR_WRONG_PIN_CODE:
293 g_set_error_literal (error,
294 G_IO_ERROR,
295 G_IO_ERROR_CONNECTION_REFUSED,
296 "the pin code was wrong");
297 break;
298 default:
299 g_set_error_literal (error,
300 G_IO_ERROR,
301 G_IO_ERROR_FAILED,
302 "generic failure");
303 }
304 return FALSE;
305 }
306 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20) {
307 switch (msg->data[1]) {
308 case HIDPP_ERROR_CODE_INVALID_ARGUMENT:
309 g_set_error (error,
310 G_IO_ERROR,
311 G_IO_ERROR_INVALID_ARGUMENT,
312 "Invalid argument 0x%02x",
313 msg->data[2]);
314 break;
315 case HIDPP_ERROR_CODE_OUT_OF_RANGE:
316 g_set_error_literal (error,
317 G_IO_ERROR,
318 G_IO_ERROR_INVALID_DATA,
319 "out of range");
320 break;
321 case HIDPP_ERROR_CODE_HW_ERROR:
322 g_set_error_literal (error,
323 G_IO_ERROR,
324 G_IO_ERROR_BROKEN_PIPE,
325 "hardware error");
326 break;
327 case HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX:
328 g_set_error_literal (error,
329 G_IO_ERROR,
330 G_IO_ERROR_INVALID_ARGUMENT,
331 "invalid feature index");
332 break;
333 case HIDPP_ERROR_CODE_INVALID_FUNCTION_ID:
334 g_set_error_literal (error,
335 G_IO_ERROR,
336 G_IO_ERROR_INVALID_ARGUMENT,
337 "invalid function ID");
338 break;
339 case HIDPP_ERROR_CODE_BUSY:
340 g_set_error_literal (error,
341 G_IO_ERROR,
342 G_IO_ERROR_BUSY,
343 "busy");
344 break;
345 case HIDPP_ERROR_CODE_UNSUPPORTED:
346 g_set_error_literal (error,
347 G_IO_ERROR,
348 G_IO_ERROR_NOT_SUPPORTED,
349 "unsupported");
350 break;
351 default:
352 g_set_error_literal (error,
353 G_IO_ERROR,
354 G_IO_ERROR_FAILED,
355 "generic failure");
356 break;
357 }
358 return FALSE;
359 }
360 return TRUE;
361 }
362
363 void
364 fu_logitech_hidpp_msg_copy (FuLogitechHidPpHidppMsg *msg_dst, const FuLogitechHidPpHidppMsg *msg_src)
365 {
366 g_return_if_fail (msg_dst != NULL);
367 g_return_if_fail (msg_src != NULL);
368 memset (msg_dst->data, 0x00, sizeof(msg_dst->data));
369 msg_dst->device_id = msg_src->device_id;
370 msg_dst->sub_id = msg_src->sub_id;
371 msg_dst->function_id = msg_src->function_id;
372 memcpy (msg_dst->data, msg_src->data, sizeof(msg_dst->data));
373 }
374
375 /* filter HID++1.0 messages */
376 gboolean
377 fu_logitech_hidpp_msg_is_hidpp10_compat (FuLogitechHidPpHidppMsg *msg)
378 {
379 g_return_val_if_fail (msg != NULL, FALSE);
380 if (msg->sub_id == 0x40 ||
381 msg->sub_id == 0x41 ||
382 msg->sub_id == 0x49 ||
383 msg->sub_id == 0x4b ||
384 msg->sub_id == 0x8f) {
385 return TRUE;
386 }
387 return FALSE;
388 }
389
390 gboolean
391 fu_logitech_hidpp_msg_verify_swid (FuLogitechHidPpHidppMsg *msg)
392 {
393 g_return_val_if_fail (msg != NULL, FALSE);
394 if ((msg->function_id & 0x0f) != FU_UNIFYING_HIDPP_MSG_SW_ID)
395 return FALSE;
396 return TRUE;
397 }
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include <glib.h>
9
10 typedef enum {
11 FU_UNIFYING_HIDPP_MSG_FLAG_NONE,
12 FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT = 1 << 0,
13 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID = 1 << 1,
14 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID = 1 << 2,
15 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID = 1 << 3,
16 /*< private >*/
17 FU_UNIFYING_HIDPP_MSG_FLAG_LAST
18 } FuLogitechHidPpHidppMsgFlags;
19
20 typedef struct __attribute__((packed)) {
21 guint8 report_id;
22 guint8 device_id;
23 guint8 sub_id;
24 guint8 function_id; /* funcId:software_id */
25 guint8 data[47]; /* maximum supported by Windows XP SP2 */
26 /* not included in the packet sent to the hardware */
27 guint32 flags;
28 guint8 hidpp_version;
29 } FuLogitechHidPpHidppMsg;
30
31 /* this is specific to fwupd */
32 #define FU_UNIFYING_HIDPP_MSG_SW_ID 0x07
33
34 #pragma clang diagnostic push
35 #pragma clang diagnostic ignored "-Wunused-function"
36 G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuLogitechHidPpHidppMsg, g_free);
37 #pragma clang diagnostic pop
38
39 FuLogitechHidPpHidppMsg *fu_logitech_hidpp_msg_new (void);
40 void fu_logitech_hidpp_msg_copy (FuLogitechHidPpHidppMsg *msg_dst,
41 const FuLogitechHidPpHidppMsg *msg_src);
42 gsize fu_logitech_hidpp_msg_get_payload_length (FuLogitechHidPpHidppMsg *msg);
43 gboolean fu_logitech_hidpp_msg_is_reply (FuLogitechHidPpHidppMsg *msg1,
44 FuLogitechHidPpHidppMsg *msg2);
45 gboolean fu_logitech_hidpp_msg_is_hidpp10_compat (FuLogitechHidPpHidppMsg *msg);
46 gboolean fu_logitech_hidpp_msg_is_error (FuLogitechHidPpHidppMsg *msg,
47 GError **error);
48 gboolean fu_logitech_hidpp_msg_verify_swid (FuLogitechHidPpHidppMsg *msg);
49
50 const gchar *fu_logitech_hidpp_msg_dev_id_to_string (FuLogitechHidPpHidppMsg *msg);
51 const gchar *fu_logitech_hidpp_msg_rpt_id_to_string (FuLogitechHidPpHidppMsg *msg);
52 const gchar *fu_logitech_hidpp_msg_sub_id_to_string (FuLogitechHidPpHidppMsg *msg);
53 const gchar *fu_logitech_hidpp_msg_fcn_id_to_string (FuLogitechHidPpHidppMsg *msg);
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include "fu-common.h"
9 #include "fu-logitech-hidpp-common.h"
10 #include "fu-logitech-hidpp-hidpp.h"
11
12 static gchar *
13 fu_logitech_hidpp_msg_to_string (FuLogitechHidPpHidppMsg *msg)
14 {
15 GString *str = g_string_new (NULL);
16 const gchar *tmp;
17 g_autoptr(GError) error = NULL;
18 g_autoptr(GString) flags_str = g_string_new (NULL);
19
20 g_return_val_if_fail (msg != NULL, NULL);
21
22 if (msg->flags == FU_UNIFYING_HIDPP_MSG_FLAG_NONE) {
23 g_string_append (flags_str, "none");
24 } else {
25 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT)
26 g_string_append (flags_str, "longer-timeout,");
27 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID)
28 g_string_append (flags_str, "ignore-sub-id,");
29 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID)
30 g_string_append (flags_str, "ignore-fnct-id,");
31 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID)
32 g_string_append (flags_str, "ignore-swid,");
33 if (str->len > 0)
34 g_string_truncate (str, str->len - 1);
35 }
36 g_string_append_printf (str, "flags: %02x [%s]\n",
37 msg->flags,
38 flags_str->str);
39 g_string_append_printf (str, "report-id: %02x [%s]\n",
40 msg->report_id,
41 fu_logitech_hidpp_msg_rpt_id_to_string (msg));
42 tmp = fu_logitech_hidpp_msg_dev_id_to_string (msg);
43 g_string_append_printf (str, "device-id: %02x [%s]\n",
44 msg->device_id, tmp );
45 g_string_append_printf (str, "sub-id: %02x [%s]\n",
46 msg->sub_id,
47 fu_logitech_hidpp_msg_sub_id_to_string (msg));
48 g_string_append_printf (str, "function-id: %02x [%s]\n",
49 msg->function_id,
50 fu_logitech_hidpp_msg_fcn_id_to_string (msg));
51 if (!fu_logitech_hidpp_msg_is_error (msg, &error)) {
52 g_string_append_printf (str, "error: %s\n",
53 error->message);
54 }
55 return g_string_free (str, FALSE);
56 }
57
58 gboolean
59 fu_logitech_hidpp_send (FuIOChannel *io_channel,
60 FuLogitechHidPpHidppMsg *msg,
61 guint timeout,
62 GError **error)
63 {
64 gsize len = fu_logitech_hidpp_msg_get_payload_length (msg);
65
66 /* only for HID++2.0 */
67 if (msg->hidpp_version >= 2.f)
68 msg->function_id |= FU_UNIFYING_HIDPP_MSG_SW_ID;
69
70 /* detailed debugging */
71 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
72 g_autofree gchar *str = fu_logitech_hidpp_msg_to_string (msg);
73 fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len);
74 g_print ("%s", str);
75 }
76
77 /* HID */
78 if (!fu_io_channel_write_raw (io_channel, (guint8 *) msg, len, 1500,
79 FU_IO_CHANNEL_FLAG_FLUSH_INPUT |
80 FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) {
81 g_prefix_error (error, "failed to send: ");
82 return FALSE;
83 }
84
85 /* success */
86 return TRUE;
87 }
88
89 gboolean
90 fu_logitech_hidpp_receive (FuIOChannel *io_channel,
91 FuLogitechHidPpHidppMsg *msg,
92 guint timeout,
93 GError **error)
94 {
95 gsize read_size = 0;
96
97 if (!fu_io_channel_read_raw (io_channel,
98 (guint8 *) msg,
99 sizeof(FuLogitechHidPpHidppMsg),
100 &read_size,
101 timeout,
102 FU_IO_CHANNEL_FLAG_SINGLE_SHOT,
103 error)) {
104 g_prefix_error (error, "failed to receive: ");
105 return FALSE;
106 }
107
108 /* check long enough, but allow returning oversize packets */
109 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL)
110 fu_common_dump_raw (G_LOG_DOMAIN, "device->host", (guint8 *) msg, read_size);
111 if (read_size < fu_logitech_hidpp_msg_get_payload_length (msg)) {
112 g_set_error (error,
113 G_IO_ERROR,
114 G_IO_ERROR_FAILED,
115 "message length too small, "
116 "got %" G_GSIZE_FORMAT " expected %" G_GSIZE_FORMAT,
117 read_size, fu_logitech_hidpp_msg_get_payload_length (msg));
118 return FALSE;
119 }
120
121 /* detailed debugging */
122 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
123 g_autofree gchar *str = fu_logitech_hidpp_msg_to_string (msg);
124 g_print ("%s", str);
125 }
126
127 /* success */
128 return TRUE;
129 }
130
131 gboolean
132 fu_logitech_hidpp_transfer (FuIOChannel *io_channel, FuLogitechHidPpHidppMsg *msg, GError **error)
133 {
134 guint timeout = FU_UNIFYING_DEVICE_TIMEOUT_MS;
135 guint ignore_cnt = 0;
136 g_autoptr(FuLogitechHidPpHidppMsg) msg_tmp = fu_logitech_hidpp_msg_new ();
137
138 /* increase timeout for some operations */
139 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT)
140 timeout *= 10;
141
142 /* send request */
143 if (!fu_logitech_hidpp_send (io_channel, msg, timeout, error))
144 return FALSE;
145
146 /* keep trying to receive until we get a valid reply */
147 while (1) {
148 msg_tmp->hidpp_version = msg->hidpp_version;
149 if (!fu_logitech_hidpp_receive (io_channel, msg_tmp, timeout, error)) {
150 g_prefix_error (error, "failed to receive: ");
151 return FALSE;
152 }
153
154 /* we don't know how to handle this report packet */
155 if (fu_logitech_hidpp_msg_get_payload_length (msg_tmp) == 0x0) {
156 g_debug ("HID++1.0 report 0x%02x has unknown length, ignoring",
157 msg_tmp->report_id);
158 continue;
159 }
160
161 /* maybe something is also writing to the device? --
162 * we can't use the SwID as this is a HID++2.0 feature */
163 if (!fu_logitech_hidpp_msg_is_error (msg_tmp, error))
164 return FALSE;
165
166 /* is valid reply */
167 if (fu_logitech_hidpp_msg_is_reply (msg, msg_tmp))
168 break;
169
170 /* to ensure compatibility when an HID++ 2.0 device is
171 * connected to an HID++ 1.0 receiver, any feature index
172 * corresponding to an HID++ 1.0 sub-identifier which could be
173 * sent by the receiver, must be assigned to a dummy feature */
174 if (msg->hidpp_version >= 2.f) {
175 if (fu_logitech_hidpp_msg_is_hidpp10_compat (msg_tmp)) {
176 g_debug ("ignoring HID++1.0 reply");
177 continue;
178 }
179
180 /* not us */
181 if ((msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID) == 0) {
182 if (!fu_logitech_hidpp_msg_verify_swid (msg_tmp)) {
183 g_debug ("ignoring reply with SwId 0x%02i, expected 0x%02i",
184 msg_tmp->function_id & 0x0f,
185 FU_UNIFYING_HIDPP_MSG_SW_ID);
186 continue;
187 }
188 }
189 }
190
191 /* hardware not responding */
192 if (ignore_cnt++ > 10) {
193 g_set_error (error,
194 G_IO_ERROR,
195 G_IO_ERROR_FAILED,
196 "too many messages to ignore");
197 return FALSE;
198 }
199
200 g_debug ("ignoring message %u", ignore_cnt);
201 };
202
203 /* copy over data */
204 fu_logitech_hidpp_msg_copy (msg, msg_tmp);
205 return TRUE;
206 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include <gio/gio.h>
9
10 #include "fu-io-channel.h"
11
12 /*
13 * Based on the HID++ documentation provided by Nestor Lopez Casado at:
14 * https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
15 */
16 #define HIDPP_DEVICE_ID_WIRED 0x00
17 #define HIDPP_DEVICE_ID_RECEIVER 0xFF
18 #define HIDPP_DEVICE_ID_UNSET 0xFE
19
20 #define HIDPP_REPORT_NOTIFICATION 0x01
21 #define HIDPP_REPORT_ID_SHORT 0x10
22 #define HIDPP_REPORT_ID_LONG 0x11
23 #define HIDPP_REPORT_ID_VERY_LONG 0x12
24
25 #define HIDPP_SUBID_VENDOR_SPECIFIC_KEYS 0x03
26 #define HIDPP_SUBID_POWER_KEYS 0x04
27 #define HIDPP_SUBID_ROLLER 0x05
28 #define HIDPP_SUBID_MOUSE_EXTRA_BUTTONS 0x06
29 #define HIDPP_SUBID_BATTERY_CHARGING_LEVEL 0x07
30 #define HIDPP_SUBID_USER_INTERFACE_EVENT 0x08
31 #define HIDPP_SUBID_F_LOCK_STATUS 0x09
32 #define HIDPP_SUBID_CALCULATOR_RESULT 0x0A
33 #define HIDPP_SUBID_MENU_NAVIGATE 0x0B
34 #define HIDPP_SUBID_FN_KEY 0x0C
35 #define HIDPP_SUBID_BATTERY_MILEAGE 0x0D
36 #define HIDPP_SUBID_UART_RX 0x0E
37 #define HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE 0x17
38 #define HIDPP_SUBID_DEVICE_DISCONNECTION 0x40
39 #define HIDPP_SUBID_DEVICE_CONNECTION 0x41
40 #define HIDPP_SUBID_DEVICE_DISCOVERY 0x42
41 #define HIDPP_SUBID_PIN_CODE_REQUEST 0x43
42 #define HIDPP_SUBID_RECEIVER_WORKING_MODE 0x44
43 #define HIDPP_SUBID_ERROR_MESSAGE 0x45
44 #define HIDPP_SUBID_RF_LINK_CHANGE 0x46
45 #define HIDPP_SUBID_HCI 0x48
46 #define HIDPP_SUBID_LINK_QUALITY 0x49
47 #define HIDPP_SUBID_DEVICE_LOCKING_CHANGED 0x4a
48 #define HIDPP_SUBID_WIRELESS_DEVICE_CHANGE 0x4B
49 #define HIDPP_SUBID_ACL 0x51
50 #define HIDPP_SUBID_VOIP_TELEPHONY_EVENT 0x5B
51 #define HIDPP_SUBID_LED 0x60
52 #define HIDPP_SUBID_GESTURE_AND_AIR 0x65
53 #define HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH 0x66
54 #define HIDPP_SUBID_TRACEABILITY 0x78
55 #define HIDPP_SUBID_SET_REGISTER 0x80
56 #define HIDPP_SUBID_GET_REGISTER 0x81
57 #define HIDPP_SUBID_SET_LONG_REGISTER 0x82
58 #define HIDPP_SUBID_GET_LONG_REGISTER 0x83
59 #define HIDPP_SUBID_SET_VERY_LONG_REGISTER 0x84
60 #define HIDPP_SUBID_GET_VERY_LONG_REGISTER 0x85
61 #define HIDPP_SUBID_ERROR_MSG 0x8F
62 #define HIDPP_SUBID_ERROR_MSG_20 0xFF
63
64 #define HIDPP_ERR_SUCCESS 0x00
65 #define HIDPP_ERR_INVALID_SUBID 0x01
66 #define HIDPP_ERR_INVALID_ADDRESS 0x02
67 #define HIDPP_ERR_INVALID_VALUE 0x03
68 #define HIDPP_ERR_CONNECT_FAIL 0x04
69 #define HIDPP_ERR_TOO_MANY_DEVICES 0x05
70 #define HIDPP_ERR_ALREADY_EXISTS 0x06
71 #define HIDPP_ERR_BUSY 0x07
72 #define HIDPP_ERR_UNKNOWN_DEVICE 0x08
73 #define HIDPP_ERR_RESOURCE_ERROR 0x09
74 #define HIDPP_ERR_REQUEST_UNAVAILABLE 0x0A
75 #define HIDPP_ERR_INVALID_PARAM_VALUE 0x0B
76 #define HIDPP_ERR_WRONG_PIN_CODE 0x0C
77
78 /*
79 * HID++1.0 registers
80 */
81
82 #define HIDPP_REGISTER_HIDPP_NOTIFICATIONS 0x00
83 #define HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES 0x01
84 #define HIDPP_REGISTER_BATTERY_STATUS 0x07
85 #define HIDPP_REGISTER_BATTERY_MILEAGE 0x0D
86 #define HIDPP_REGISTER_PROFILE 0x0F
87 #define HIDPP_REGISTER_LED_STATUS 0x51
88 #define HIDPP_REGISTER_LED_INTENSITY 0x54
89 #define HIDPP_REGISTER_LED_COLOR 0x57
90 #define HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS 0x61
91 #define HIDPP_REGISTER_CURRENT_RESOLUTION 0x63
92 #define HIDPP_REGISTER_USB_REFRESH_RATE 0x64
93 #define HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT 0xA0
94 #define HIDPP_REGISTER_HOT_CONTROL 0xA1
95 #define HIDPP_REGISTER_READ_MEMORY 0xA2
96 #define HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION 0xB2
97 #define HIDPP_REGISTER_PAIRING_INFORMATION 0xB5
98 #define HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE 0xF0
99 #define HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION 0xF1
100
101 /*
102 * HID++2.0 error codes
103 */
104 #define HIDPP_ERROR_CODE_NO_ERROR 0x00
105 #define HIDPP_ERROR_CODE_UNKNOWN 0x01
106 #define HIDPP_ERROR_CODE_INVALID_ARGUMENT 0x02
107 #define HIDPP_ERROR_CODE_OUT_OF_RANGE 0x03
108 #define HIDPP_ERROR_CODE_HW_ERROR 0x04
109 #define HIDPP_ERROR_CODE_LOGITECH_INTERNAL 0x05
110 #define HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX 0x06
111 #define HIDPP_ERROR_CODE_INVALID_FUNCTION_ID 0x07
112 #define HIDPP_ERROR_CODE_BUSY 0x08
113 #define HIDPP_ERROR_CODE_UNSUPPORTED 0x09
114
115 /*
116 * HID++2.0 features
117 */
118 #define HIDPP_FEATURE_ROOT 0x0000
119 #define HIDPP_FEATURE_I_FEATURE_SET 0x0001
120 #define HIDPP_FEATURE_I_FIRMWARE_INFO 0x0003
121 #define HIDPP_FEATURE_GET_DEVICE_NAME_TYPE 0x0005
122 #define HIDPP_FEATURE_DFU_CONTROL 0x00c1
123 #define HIDPP_FEATURE_DFU_CONTROL_SIGNED 0x00c2
124 #define HIDPP_FEATURE_DFU 0x00d0
125 #define HIDPP_FEATURE_BATTERY_LEVEL_STATUS 0x1000
126 #define HIDPP_FEATURE_KBD_REPROGRAMMABLE_KEYS 0x1b00
127 #define HIDPP_FEATURE_SPECIAL_KEYS_BUTTONS 0x1b04
128 #define HIDPP_FEATURE_MOUSE_POINTER_BASIC 0x2200
129 #define HIDPP_FEATURE_ADJUSTABLE_DPI 0x2201
130 #define HIDPP_FEATURE_ADJUSTABLE_REPORT_RATE 0x8060
131 #define HIDPP_FEATURE_COLOR_LED_EFFECTS 0x8070
132 #define HIDPP_FEATURE_ONBOARD_PROFILES 0x8100
133 #define HIDPP_FEATURE_MOUSE_BUTTON_SPY 0x8110
134
135 #include "fu-logitech-hidpp-hidpp-msg.h"
136
137 gboolean fu_logitech_hidpp_send (FuIOChannel *self,
138 FuLogitechHidPpHidppMsg *msg,
139 guint timeout,
140 GError **error);
141 gboolean fu_logitech_hidpp_receive (FuIOChannel *self,
142 FuLogitechHidPpHidppMsg *msg,
143 guint timeout,
144 GError **error);
145 gboolean fu_logitech_hidpp_transfer (FuIOChannel *self,
146 FuLogitechHidPpHidppMsg *msg,
147 GError **error);
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-logitech-hidpp-common.h"
11 #include "fu-logitech-hidpp-peripheral.h"
12 #include "fu-logitech-hidpp-hidpp.h"
13
14 struct _FuLogitechHidPpPeripheral
15 {
16 FuUdevDevice parent_instance;
17 guint8 battery_level;
18 guint8 cached_fw_entity;
19 guint8 hidpp_id;
20 guint8 hidpp_version;
21 gboolean is_updatable;
22 gboolean is_active;
23 FuIOChannel *io_channel;
24 GPtrArray *feature_index; /* of FuLogitechHidPpHidppMap */
25 };
26
27 typedef struct {
28 guint8 idx;
29 guint16 feature;
30 } FuLogitechHidPpHidppMap;
31
32 G_DEFINE_TYPE (FuLogitechHidPpPeripheral, fu_logitech_hidpp_peripheral, FU_TYPE_UDEV_DEVICE)
33
34 typedef enum {
35 FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD,
36 FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL,
37 FU_UNIFYING_PERIPHERAL_KIND_NUMPAD,
38 FU_UNIFYING_PERIPHERAL_KIND_MOUSE,
39 FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD,
40 FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL,
41 FU_UNIFYING_PERIPHERAL_KIND_PRESENTER,
42 FU_UNIFYING_PERIPHERAL_KIND_RECEIVER,
43 FU_UNIFYING_PERIPHERAL_KIND_LAST
44 } FuLogitechHidPpPeripheralKind;
45
46 static const gchar *
47 fu_logitech_hidpp_peripheral_get_icon (FuLogitechHidPpPeripheralKind kind)
48 {
49 if (kind == FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD)
50 return "input-keyboard";
51 if (kind == FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL)
52 return "pda"; // ish
53 if (kind == FU_UNIFYING_PERIPHERAL_KIND_NUMPAD)
54 return "input-dialpad";
55 if (kind == FU_UNIFYING_PERIPHERAL_KIND_MOUSE)
56 return "input-mouse";
57 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD)
58 return "input-touchpad";
59 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL)
60 return "input-mouse"; // ish
61 if (kind == FU_UNIFYING_PERIPHERAL_KIND_PRESENTER)
62 return "pda"; // ish
63 if (kind == FU_UNIFYING_PERIPHERAL_KIND_RECEIVER)
64 return "preferences-desktop-keyboard";
65 return NULL;
66 }
67
68 static const gchar *
69 fu_logitech_hidpp_peripheral_get_summary (FuLogitechHidPpPeripheralKind kind)
70 {
71 if (kind == FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD)
72 return "Unifying Keyboard";
73 if (kind == FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL)
74 return "Unifying Remote Control";
75 if (kind == FU_UNIFYING_PERIPHERAL_KIND_NUMPAD)
76 return "Unifying Number Pad";
77 if (kind == FU_UNIFYING_PERIPHERAL_KIND_MOUSE)
78 return "Unifying Mouse";
79 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD)
80 return "Unifying Touchpad";
81 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL)
82 return "Unifying Trackball";
83 if (kind == FU_UNIFYING_PERIPHERAL_KIND_PRESENTER)
84 return "Unifying Presenter";
85 if (kind == FU_UNIFYING_PERIPHERAL_KIND_RECEIVER)
86 return "Unifying Receiver";
87 return NULL;
88 }
89
90 static const gchar *
91 fu_logitech_hidpp_feature_to_string (guint16 feature)
92 {
93 if (feature == HIDPP_FEATURE_ROOT)
94 return "Root";
95 if (feature == HIDPP_FEATURE_I_FIRMWARE_INFO)
96 return "IFirmwareInfo";
97 if (feature == HIDPP_FEATURE_GET_DEVICE_NAME_TYPE)
98 return "GetDevicenameType";
99 if (feature == HIDPP_FEATURE_BATTERY_LEVEL_STATUS)
100 return "BatteryLevelStatus";
101 if (feature == HIDPP_FEATURE_DFU_CONTROL)
102 return "DfuControl";
103 if (feature == HIDPP_FEATURE_DFU_CONTROL_SIGNED)
104 return "DfuControlSigned";
105 if (feature == HIDPP_FEATURE_DFU)
106 return "Dfu";
107 return NULL;
108 }
109
110 static void
111 fu_logitech_hidpp_peripheral_refresh_updatable (FuLogitechHidPpPeripheral *self)
112 {
113 /* device can only be upgraded if it is capable, and active */
114 if (self->is_updatable && self->is_active) {
115 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
116 return;
117 }
118 fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
119 }
120
121 static gboolean
122 fu_logitech_hidpp_peripheral_ping (FuLogitechHidPpPeripheral *self, GError **error)
123 {
124 gdouble version;
125 g_autoptr(GError) error_local = NULL;
126 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
127
128 /* handle failure */
129 msg->report_id = HIDPP_REPORT_ID_SHORT;
130 msg->device_id = self->hidpp_id;
131 msg->sub_id = 0x00; /* rootIndex */
132 msg->function_id = 0x01 << 4; /* ping */
133 msg->data[0] = 0x00;
134 msg->data[1] = 0x00;
135 msg->data[2] = 0xaa; /* user-selected value */
136 msg->hidpp_version = self->hidpp_version;
137 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, &error_local)) {
138 if (g_error_matches (error_local,
139 G_IO_ERROR,
140 G_IO_ERROR_NOT_SUPPORTED)) {
141 self->hidpp_version = 1;
142 return TRUE;
143 }
144 if (g_error_matches (error_local,
145 G_IO_ERROR,
146 G_IO_ERROR_HOST_UNREACHABLE)) {
147 self->is_active = FALSE;
148 fu_logitech_hidpp_peripheral_refresh_updatable (self);
149 return TRUE;
150 }
151 g_set_error (error,
152 G_IO_ERROR,
153 G_IO_ERROR_FAILED,
154 "failed to ping %s: %s",
155 fu_device_get_name (FU_DEVICE (self)),
156 error_local->message);
157 return FALSE;
158 }
159
160 /* device no longer asleep */
161 self->is_active = TRUE;
162 fu_logitech_hidpp_peripheral_refresh_updatable (self);
163
164 /* if the HID++ ID is unset, grab it from the reply */
165 if (self->hidpp_id == HIDPP_DEVICE_ID_UNSET) {
166 self->hidpp_id = msg->device_id;
167 g_debug ("HID++ ID is %02x", self->hidpp_id);
168 }
169
170 /* format version in BCD format */
171 version = (gdouble) msg->data[0] + ((gdouble) msg->data[1]) / 100.f;
172 self->hidpp_version = (guint) version;
173
174 /* success */
175 return TRUE;
176 }
177
178 static gboolean
179 fu_logitech_hidpp_peripheral_close (FuDevice *device, GError **error)
180 {
181 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
182 if (!fu_io_channel_shutdown (self->io_channel, error))
183 return FALSE;
184 g_clear_object (&self->io_channel);
185 return TRUE;
186 }
187
188 static gboolean
189 fu_logitech_hidpp_peripheral_poll (FuDevice *device, GError **error)
190 {
191 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
192 const guint timeout = 1; /* ms */
193 g_autoptr(GError) error_local = NULL;
194 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
195 g_autoptr(FuDeviceLocker) locker = NULL;
196
197 /* open */
198 locker = fu_device_locker_new (self, error);
199 if (locker == NULL)
200 return FALSE;
201
202 /* flush pending data */
203 msg->device_id = self->hidpp_id;
204 msg->hidpp_version = self->hidpp_version;
205 if (!fu_logitech_hidpp_receive (self->io_channel, msg, timeout, &error_local)) {
206 if (!g_error_matches (error_local,
207 G_IO_ERROR,
208 G_IO_ERROR_TIMED_OUT)) {
209 g_warning ("failed to get pending read: %s", error_local->message);
210 return TRUE;
211 }
212 /* no data to receive */
213 g_clear_error (&error_local);
214 }
215
216 /* just ping */
217 if (!fu_logitech_hidpp_peripheral_ping (self, &error_local)) {
218 g_warning ("failed to ping device: %s", error_local->message);
219 return TRUE;
220 }
221
222 /* this is the first time the device has been active */
223 if (self->feature_index->len == 0) {
224 fu_device_probe_invalidate (FU_DEVICE (self));
225 if (!fu_device_setup (FU_DEVICE (self), error))
226 return FALSE;
227 }
228
229 /* success */
230 return TRUE;
231 }
232
233 static gboolean
234 fu_logitech_hidpp_peripheral_open (FuDevice *device, GError **error)
235 {
236 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
237 GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
238 const gchar *devpath = g_udev_device_get_device_file (udev_device);
239
240 /* open */
241 self->io_channel = fu_io_channel_new_file (devpath, error);
242 if (self->io_channel == NULL)
243 return FALSE;
244
245 return TRUE;
246 }
247
248 static void
249 fu_logitech_hidpp_map_to_string (FuLogitechHidPpHidppMap *map, guint idt, GString *str)
250 {
251 g_autofree gchar *title = g_strdup_printf ("Feature%02x", map->idx);
252 g_autofree gchar *tmp = g_strdup_printf ("%s [0x%04x]",
253 fu_logitech_hidpp_feature_to_string (map->feature),
254 map->feature);
255 fu_common_string_append_kv (str, idt, title, tmp);
256 }
257
258 static void
259 fu_logitech_hidpp_peripheral_to_string (FuDevice *device, guint idt, GString *str)
260 {
261 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
262 fu_common_string_append_ku (str, idt, "HidppVersion", self->hidpp_version);
263 fu_common_string_append_kx (str, idt, "HidppId", self->hidpp_id);
264 fu_common_string_append_ku (str, idt, "BatteryLevel", self->battery_level);
265 fu_common_string_append_kb (str, idt, "IsUpdatable", self->is_updatable);
266 fu_common_string_append_kb (str, idt, "IsActive", self->is_active);
267 for (guint i = 0; i < self->feature_index->len; i++) {
268 FuLogitechHidPpHidppMap *map = g_ptr_array_index (self->feature_index, i);
269 fu_logitech_hidpp_map_to_string (map, idt, str);
270 }
271 }
272
273 static guint8
274 fu_logitech_hidpp_peripheral_feature_get_idx (FuLogitechHidPpPeripheral *self, guint16 feature)
275 {
276 for (guint i = 0; i < self->feature_index->len; i++) {
277 FuLogitechHidPpHidppMap *map = g_ptr_array_index (self->feature_index, i);
278 if (map->feature == feature)
279 return map->idx;
280 }
281 return 0x00;
282 }
283
284 static gboolean
285 fu_logitech_hidpp_peripheral_fetch_firmware_info (FuLogitechHidPpPeripheral *self, GError **error)
286 {
287 guint8 idx;
288 guint8 entity_count;
289 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
290
291 /* get the feature index */
292 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_I_FIRMWARE_INFO);
293 if (idx == 0x00)
294 return TRUE;
295
296 /* get the entity count */
297 msg->report_id = HIDPP_REPORT_ID_SHORT;
298 msg->device_id = self->hidpp_id;
299 msg->sub_id = idx;
300 msg->function_id = 0x00 << 4; /* getCount */
301 msg->hidpp_version = self->hidpp_version;
302 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
303 g_prefix_error (error, "failed to get firmware count: ");
304 return FALSE;
305 }
306 entity_count = msg->data[0];
307 g_debug ("firmware entity count is %u", entity_count);
308
309 /* get firmware, bootloader, hardware versions */
310 for (guint8 i = 0; i < entity_count; i++) {
311 guint16 build;
312 g_autofree gchar *version = NULL;
313 g_autofree gchar *name = NULL;
314
315 msg->report_id = HIDPP_REPORT_ID_SHORT;
316 msg->device_id = self->hidpp_id;
317 msg->sub_id = idx;
318 msg->function_id = 0x01 << 4; /* getInfo */
319 msg->data[0] = i;
320 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
321 g_prefix_error (error, "failed to get firmware info: ");
322 return FALSE;
323 }
324 if (msg->data[1] == 0x00 &&
325 msg->data[2] == 0x00 &&
326 msg->data[3] == 0x00 &&
327 msg->data[4] == 0x00 &&
328 msg->data[5] == 0x00 &&
329 msg->data[6] == 0x00 &&
330 msg->data[7] == 0x00) {
331 g_debug ("no version set for entity %u", i);
332 continue;
333 }
334 name = g_strdup_printf ("%c%c%c",
335 msg->data[1],
336 msg->data[2],
337 msg->data[3]);
338 build = ((guint16) msg->data[6]) << 8 | msg->data[7];
339 version = fu_logitech_hidpp_format_version (name,
340 msg->data[4],
341 msg->data[5],
342 build);
343 g_debug ("firmware entity 0x%02x version is %s", i, version);
344 if (msg->data[0] == 0) {
345 fu_device_set_version (FU_DEVICE (self), version,
346 FWUPD_VERSION_FORMAT_PLAIN);
347 self->cached_fw_entity = i;
348 } else if (msg->data[0] == 1) {
349 fu_device_set_version_bootloader (FU_DEVICE (self), version);
350 } else if (msg->data[0] == 2) {
351 fu_device_set_metadata (FU_DEVICE (self), "version-hw", version);
352 }
353 }
354
355 /* not an error, the device just doesn't support this */
356 return TRUE;
357 }
358
359 static gboolean
360 fu_logitech_hidpp_peripheral_fetch_battery_level (FuLogitechHidPpPeripheral *self, GError **error)
361 {
362 /* try using HID++2.0 */
363 if (self->hidpp_version >= 2.f) {
364 guint8 idx;
365 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_BATTERY_LEVEL_STATUS);
366 if (idx != 0x00) {
367 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
368 msg->report_id = HIDPP_REPORT_ID_SHORT;
369 msg->device_id = self->hidpp_id;
370 msg->sub_id = idx;
371 msg->function_id = 0x00; /* GetBatteryLevelStatus */
372 msg->hidpp_version = self->hidpp_version;
373 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
374 g_prefix_error (error, "failed to get battery info: ");
375 return FALSE;
376 }
377 if (msg->data[0] != 0x00)
378 self->battery_level = msg->data[0];
379 return TRUE;
380 }
381 }
382
383 /* try HID++1.0 battery mileage */
384 if (self->hidpp_version == 1.f) {
385 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
386 msg->report_id = HIDPP_REPORT_ID_SHORT;
387 msg->device_id = self->hidpp_id;
388 msg->sub_id = HIDPP_SUBID_GET_REGISTER;
389 msg->function_id = HIDPP_REGISTER_BATTERY_MILEAGE;
390 msg->hidpp_version = self->hidpp_version;
391 if (fu_logitech_hidpp_transfer (self->io_channel, msg, NULL)) {
392 if (msg->data[0] != 0x00)
393 self->battery_level = msg->data[0];
394 return TRUE;
395 }
396
397 /* try HID++1.0 battery status instead */
398 msg->function_id = HIDPP_REGISTER_BATTERY_STATUS;
399 if (fu_logitech_hidpp_transfer (self->io_channel, msg, NULL)) {
400 switch (msg->data[0]) {
401 case 1: /* 0 - 10 */
402 self->battery_level = 5;
403 break;
404 case 3: /* 11 - 30 */
405 self->battery_level = 20;
406 break;
407 case 5: /* 31 - 80 */
408 self->battery_level = 55;
409 break;
410 case 7: /* 81 - 100 */
411 self->battery_level = 90;
412 break;
413 default:
414 g_warning ("unknown battery percentage: 0x%02x",
415 msg->data[0]);
416 break;
417 }
418 return TRUE;
419 }
420 }
421
422 /* not an error, the device just doesn't support any of the methods */
423 return TRUE;
424 }
425
426 static gboolean
427 fu_logitech_hidpp_feature_search (FuDevice *device, guint16 feature, GError **error)
428 {
429 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
430 FuLogitechHidPpHidppMap *map;
431 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
432
433 /* find the idx for the feature */
434 msg->report_id = HIDPP_REPORT_ID_SHORT;
435 msg->device_id = self->hidpp_id;
436 msg->sub_id = 0x00; /* rootIndex */
437 msg->function_id = 0x00 << 4; /* getFeature */
438 msg->data[0] = feature >> 8;
439 msg->data[1] = feature;
440 msg->data[2] = 0x00;
441 msg->hidpp_version = self->hidpp_version;
442 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
443 g_prefix_error (error,
444 "failed to get idx for feature %s [0x%04x]: ",
445 fu_logitech_hidpp_feature_to_string (feature), feature);
446 return FALSE;
447 }
448
449 /* zero index */
450 if (msg->data[0] == 0x00) {
451 g_set_error (error,
452 G_IO_ERROR,
453 G_IO_ERROR_NOT_SUPPORTED,
454 "feature %s [0x%04x] not found",
455 fu_logitech_hidpp_feature_to_string (feature), feature);
456 return FALSE;
457 }
458
459 /* add to map */
460 map = g_new0 (FuLogitechHidPpHidppMap, 1);
461 map->idx = msg->data[0];
462 map->feature = feature;
463 g_ptr_array_add (self->feature_index, map);
464 g_debug ("added feature %s [0x%04x] as idx %02x",
465 fu_logitech_hidpp_feature_to_string (feature), feature, map->idx);
466 return TRUE;
467 }
468
469 static gboolean
470 fu_logitech_hidpp_peripheral_probe (FuUdevDevice *device, GError **error)
471 {
472 g_autofree gchar *devid = NULL;
473
474 /* set the physical ID */
475 if (!fu_udev_device_set_physical_id (device, "hid", error))
476 return FALSE;
477
478 /* nearly... */
479 fu_device_set_vendor_id (FU_DEVICE (device), "USB:0x046D");
480
481 /* this is a non-standard extension */
482 devid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X",
483 fu_udev_device_get_vendor (device),
484 fu_udev_device_get_model (device));
485 fu_device_add_instance_id (FU_DEVICE (device), devid);
486 return TRUE;
487 }
488
489 static gboolean
490 fu_logitech_hidpp_peripheral_setup (FuDevice *device, GError **error)
491 {
492 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
493 guint8 idx;
494 const guint16 map_features[] = {
495 HIDPP_FEATURE_GET_DEVICE_NAME_TYPE,
496 HIDPP_FEATURE_I_FIRMWARE_INFO,
497 HIDPP_FEATURE_BATTERY_LEVEL_STATUS,
498 HIDPP_FEATURE_DFU_CONTROL,
499 HIDPP_FEATURE_DFU_CONTROL_SIGNED,
500 HIDPP_FEATURE_DFU,
501 HIDPP_FEATURE_ROOT };
502
503 /* ping device to get HID++ version */
504 if (!fu_logitech_hidpp_peripheral_ping (self, error))
505 return FALSE;
506
507 /* add known root for HID++2.0 */
508 g_ptr_array_set_size (self->feature_index, 0);
509 if (self->hidpp_version >= 2.f) {
510 FuLogitechHidPpHidppMap *map = g_new0 (FuLogitechHidPpHidppMap, 1);
511 map->idx = 0x00;
512 map->feature = HIDPP_FEATURE_ROOT;
513 g_ptr_array_add (self->feature_index, map);
514 }
515
516 /* map some *optional* HID++2.0 features we might use */
517 for (guint i = 0; map_features[i] != HIDPP_FEATURE_ROOT; i++) {
518 g_autoptr(GError) error_local = NULL;
519 if (!fu_logitech_hidpp_feature_search (device,
520 map_features[i],
521 &error_local)) {
522 g_debug ("%s", error_local->message);
523 if (g_error_matches (error_local,
524 G_IO_ERROR,
525 G_IO_ERROR_TIMED_OUT) ||
526 g_error_matches (error_local,
527 G_IO_ERROR,
528 G_IO_ERROR_HOST_UNREACHABLE)) {
529 /* timed out, so not trying any more */
530 break;
531 }
532 }
533 }
534
535 /* get the firmware information */
536 if (!fu_logitech_hidpp_peripheral_fetch_firmware_info (self, error))
537 return FALSE;
538
539 /* get the battery level */
540 if (!fu_logitech_hidpp_peripheral_fetch_battery_level (self, error))
541 return FALSE;
542
543 /* try using HID++2.0 */
544 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_GET_DEVICE_NAME_TYPE);
545 if (idx != 0x00) {
546 const gchar *tmp;
547 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
548 msg->report_id = HIDPP_REPORT_ID_SHORT;
549 msg->device_id = self->hidpp_id;
550 msg->sub_id = idx;
551 msg->function_id = 0x02 << 4; /* getDeviceType */
552 msg->hidpp_version = self->hidpp_version;
553 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
554 g_prefix_error (error, "failed to get device type: ");
555 return FALSE;
556 }
557
558 /* add nice-to-have data */
559 tmp = fu_logitech_hidpp_peripheral_get_summary (msg->data[0]);
560 if (tmp != NULL)
561 fu_device_set_summary (FU_DEVICE (device), tmp);
562 tmp = fu_logitech_hidpp_peripheral_get_icon (msg->data[0]);
563 if (tmp != NULL)
564 fu_device_add_icon (FU_DEVICE (device), tmp);
565 }
566 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL);
567 if (idx != 0x00) {
568 self->is_updatable = TRUE;
569 fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
570 }
571 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED);
572 if (idx != 0x00) {
573 /* check the feature is available */
574 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
575 msg->report_id = HIDPP_REPORT_ID_SHORT;
576 msg->device_id = self->hidpp_id;
577 msg->sub_id = idx;
578 msg->function_id = 0x00 << 4; /* getDfuStatus */
579 msg->hidpp_version = self->hidpp_version;
580 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
581 g_prefix_error (error, "failed to get DFU status: ");
582 return FALSE;
583 }
584 if ((msg->data[2] & 0x01) > 0) {
585 g_warning ("DFU mode not available");
586 } else {
587 self->is_updatable = TRUE;
588 fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
589 }
590 }
591 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
592 if (idx != 0x00) {
593 self->is_updatable = TRUE;
594 fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
595 if (fu_device_get_version (device) == NULL) {
596 g_debug ("repairing device in bootloader mode");
597 fu_device_set_version (FU_DEVICE (device),
598 "MPK00.00_B0000",
599 FWUPD_VERSION_FORMAT_PLAIN);
600 }
601 }
602
603 /* this device may have changed state */
604 fu_logitech_hidpp_peripheral_refresh_updatable (self);
605
606 /* poll for pings to track active state */
607 fu_device_set_poll_interval (device, 30000);
608 return TRUE;
609 }
610
611 static gboolean
612 fu_logitech_hidpp_peripheral_detach (FuDevice *device, GError **error)
613 {
614 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
615 guint8 idx;
616 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
617
618 /* this requires user action */
619 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL);
620 if (idx != 0x00) {
621 msg->report_id = HIDPP_REPORT_ID_LONG;
622 msg->device_id = self->hidpp_id;
623 msg->sub_id = idx;
624 msg->function_id = 0x01 << 4; /* setDfuControl */
625 msg->data[0] = 0x01; /* enterDfu */
626 msg->data[1] = 0x00; /* dfuControlParam */
627 msg->data[2] = 0x00; /* unused */
628 msg->data[3] = 0x00; /* unused */
629 msg->data[4] = 'D';
630 msg->data[5] = 'F';
631 msg->data[6] = 'U';
632 msg->hidpp_version = self->hidpp_version;
633 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID |
634 FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
635 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
636 g_prefix_error (error, "failed to put device into DFU mode: ");
637 return FALSE;
638 }
639 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
640 g_set_error (error,
641 FWUPD_ERROR,
642 FWUPD_ERROR_NEEDS_USER_ACTION,
643 "%s needs to be manually restarted to complete the update."
644 "Please unplug and reconnect the device and re-run the update",
645 fu_device_get_name (device));
646 return FALSE;
647 }
648
649 /* this can reboot all by itself */
650 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED);
651 if (idx != 0x00) {
652 msg->report_id = HIDPP_REPORT_ID_LONG;
653 msg->device_id = self->hidpp_id;
654 msg->sub_id = idx;
655 msg->function_id = 0x01 << 4; /* setDfuControl */
656 msg->data[0] = 0x01; /* startDfu */
657 msg->data[1] = 0x00; /* dfuControlParam */
658 msg->data[2] = 0x00; /* unused */
659 msg->data[3] = 0x00; /* unused */
660 msg->data[4] = 'D';
661 msg->data[5] = 'F';
662 msg->data[6] = 'U';
663 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID;
664 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
665 g_prefix_error (error, "failed to put device into DFU mode: ");
666 return FALSE;
667 }
668 return fu_logitech_hidpp_peripheral_setup (FU_DEVICE (self), error);
669 }
670
671 /* we don't know how */
672 g_set_error (error,
673 G_IO_ERROR,
674 G_IO_ERROR_FAILED,
675 "no method to detach");
676 return FALSE;
677 }
678
679 static gboolean
680 fu_logitech_hidpp_peripheral_check_status (guint8 status, GError **error)
681 {
682 switch (status & 0x7f) {
683 case 0x00:
684 g_set_error (error,
685 G_IO_ERROR,
686 G_IO_ERROR_FAILED,
687 "invalid status value 0x%02x",
688 status);
689 break;
690 case 0x01: /* packet success */
691 case 0x02: /* DFU success */
692 case 0x05: /* DFU success: entity restart required */
693 case 0x06: /* DFU success: system restart required */
694 /* success */
695 return TRUE;
696 break;
697 case 0x03:
698 g_set_error_literal (error,
699 G_IO_ERROR,
700 G_IO_ERROR_PENDING,
701 "wait for event (command in progress)");
702 break;
703 case 0x04:
704 case 0x10: /* unknown */
705 g_set_error_literal (error,
706 G_IO_ERROR,
707 G_IO_ERROR_FAILED,
708 "generic error");
709 break;
710 case 0x11:
711 g_set_error_literal (error,
712 G_IO_ERROR,
713 G_IO_ERROR_FAILED,
714 "bad voltage (power too low?)");
715 break;
716 case 0x12:
717 case 0x14: /* bad magic string */
718 case 0x21: /* bad firmware */
719 g_set_error_literal (error,
720 G_IO_ERROR,
721 G_IO_ERROR_FAILED,
722 "unsupported firmware");
723 break;
724 case 0x13:
725 g_set_error_literal (error,
726 G_IO_ERROR,
727 G_IO_ERROR_FAILED,
728 "unsupported encryption mode");
729 break;
730 case 0x15:
731 g_set_error_literal (error,
732 G_IO_ERROR,
733 G_IO_ERROR_FAILED,
734 "erase failure");
735 break;
736 case 0x16:
737 g_set_error_literal (error,
738 G_IO_ERROR,
739 G_IO_ERROR_FAILED,
740 "DFU not started");
741 break;
742 case 0x17:
743 g_set_error_literal (error,
744 G_IO_ERROR,
745 G_IO_ERROR_FAILED,
746 "bad sequence number");
747 break;
748 case 0x18:
749 g_set_error_literal (error,
750 G_IO_ERROR,
751 G_IO_ERROR_FAILED,
752 "unsupported command");
753 break;
754 case 0x19:
755 g_set_error_literal (error,
756 G_IO_ERROR,
757 G_IO_ERROR_FAILED,
758 "command in progress");
759 break;
760 case 0x1a:
761 g_set_error_literal (error,
762 G_IO_ERROR,
763 G_IO_ERROR_FAILED,
764 "address out of range");
765 break;
766 case 0x1b:
767 g_set_error_literal (error,
768 G_IO_ERROR,
769 G_IO_ERROR_FAILED,
770 "unaligned address");
771 break;
772 case 0x1c:
773 g_set_error_literal (error,
774 G_IO_ERROR,
775 G_IO_ERROR_FAILED,
776 "bad size");
777 break;
778 case 0x1d:
779 g_set_error_literal (error,
780 G_IO_ERROR,
781 G_IO_ERROR_FAILED,
782 "missing program data");
783 break;
784 case 0x1e:
785 g_set_error_literal (error,
786 G_IO_ERROR,
787 G_IO_ERROR_FAILED,
788 "missing check data");
789 break;
790 case 0x1f:
791 g_set_error_literal (error,
792 G_IO_ERROR,
793 G_IO_ERROR_FAILED,
794 "program failed to write");
795 break;
796 case 0x20:
797 g_set_error_literal (error,
798 G_IO_ERROR,
799 G_IO_ERROR_FAILED,
800 "program failed to verify");
801 break;
802 case 0x22:
803 g_set_error_literal (error,
804 G_IO_ERROR,
805 G_IO_ERROR_FAILED,
806 "firmware check failure");
807 break;
808 case 0x23:
809 g_set_error_literal (error,
810 G_IO_ERROR,
811 G_IO_ERROR_FAILED,
812 "blocked command (restart required)");
813 break;
814 default:
815 g_set_error (error,
816 G_IO_ERROR,
817 G_IO_ERROR_FAILED,
818 "unhandled status value 0x%02x",
819 status);
820 break;
821 }
822 return FALSE;
823 }
824
825 static gboolean
826 fu_logitech_hidpp_peripheral_write_firmware_pkt (FuLogitechHidPpPeripheral *self,
827 guint8 idx,
828 guint8 cmd,
829 const guint8 *data,
830 GError **error)
831 {
832 guint32 packet_cnt;
833 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
834 g_autoptr(GError) error_local = NULL;
835
836 /* send firmware data */
837 msg->report_id = HIDPP_REPORT_ID_LONG;
838 msg->device_id = self->hidpp_id;
839 msg->sub_id = idx;
840 msg->function_id = cmd << 4; /* dfuStart or dfuCmdDataX */
841 msg->hidpp_version = self->hidpp_version;
842 memcpy (msg->data, data, 16);
843 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, &error_local)) {
844 g_prefix_error (error, "failed to supply program data: ");
845 return FALSE;
846 }
847
848 /* check error */
849 packet_cnt = fu_common_read_uint32 (msg->data, G_BIG_ENDIAN);
850 g_debug ("packet_cnt=0x%04x", packet_cnt);
851 if (fu_logitech_hidpp_peripheral_check_status (msg->data[4], &error_local))
852 return TRUE;
853
854 /* fatal error */
855 if (!g_error_matches (error_local,
856 G_IO_ERROR,
857 G_IO_ERROR_PENDING)) {
858 g_set_error_literal (error,
859 G_IO_ERROR,
860 G_IO_ERROR_FAILED,
861 error_local->message);
862 return FALSE;
863 }
864
865 /* wait for the HID++ notification */
866 g_debug ("ignoring: %s", error_local->message);
867 for (guint retry = 0; retry < 10; retry++) {
868 g_autoptr(FuLogitechHidPpHidppMsg) msg2 = fu_logitech_hidpp_msg_new ();
869 msg2->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID;
870 if (!fu_logitech_hidpp_receive (self->io_channel, msg2, 15000, error))
871 return FALSE;
872 if (fu_logitech_hidpp_msg_is_reply (msg, msg2)) {
873 g_autoptr(GError) error2 = NULL;
874 if (!fu_logitech_hidpp_peripheral_check_status (msg2->data[4], &error2)) {
875 g_debug ("got %s, waiting a bit longer", error2->message);
876 continue;
877 }
878 return TRUE;
879 } else {
880 g_debug ("got wrong packet, continue to wait...");
881 }
882 }
883
884 /* nothing in the queue */
885 g_set_error_literal (error,
886 G_IO_ERROR,
887 G_IO_ERROR_FAILED,
888 "failed to get event after timeout");
889 return FALSE;
890 }
891
892 static gboolean
893 fu_logitech_hidpp_peripheral_write_firmware (FuDevice *device,
894 FuFirmware *firmware,
895 FwupdInstallFlags flags,
896 GError **error)
897 {
898 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
899 gsize sz = 0;
900 const guint8 *data;
901 guint8 cmd = 0x04;
902 guint8 idx;
903 g_autoptr(GBytes) fw = NULL;
904
905 /* if we're in bootloader mode, we should be able to get this feature */
906 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
907 if (idx == 0x00) {
908 g_set_error (error,
909 G_IO_ERROR,
910 G_IO_ERROR_FAILED,
911 "no DFU feature available");
912 return FALSE;
913 }
914
915 /* get default image */
916 fw = fu_firmware_get_image_default_bytes (firmware, error);
917 if (fw == NULL)
918 return FALSE;
919
920 /* flash hardware */
921 data = g_bytes_get_data (fw, &sz);
922 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
923 for (gsize i = 0; i < sz / 16; i++) {
924
925 /* send packet and wait for reply */
926 g_debug ("send data at addr=0x%04x", (guint) i * 16);
927 if (!fu_logitech_hidpp_peripheral_write_firmware_pkt (self,
928 idx,
929 cmd,
930 data + (i * 16),
931 error)) {
932 g_prefix_error (error,
933 "failed to write @0x%04x: ",
934 (guint) i * 16);
935 return FALSE;
936 }
937
938 /* use sliding window */
939 cmd = (cmd + 1) % 4;
940
941 /* update progress-bar */
942 fu_device_set_progress_full (device, i * 16, sz);
943 }
944
945 return TRUE;
946 }
947
948 static gboolean
949 fu_logitech_hidpp_peripheral_attach (FuDevice *device, GError **error)
950 {
951 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
952 guint8 idx;
953 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
954
955 /* if we're in bootloader mode, we should be able to get this feature */
956 idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
957 if (idx == 0x00) {
958 g_set_error (error,
959 G_IO_ERROR,
960 G_IO_ERROR_FAILED,
961 "no DFU feature available");
962 return FALSE;
963 }
964
965 /* reboot back into firmware mode */
966 msg->report_id = HIDPP_REPORT_ID_SHORT;
967 msg->device_id = self->hidpp_id;
968 msg->sub_id = idx;
969 msg->function_id = 0x05 << 4; /* restart */
970 msg->data[0] = self->cached_fw_entity; /* fwEntity */
971 msg->hidpp_version = self->hidpp_version;
972 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID |
973 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred?
974 FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
975 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
976 g_prefix_error (error, "failed to restart device: ");
977 return FALSE;
978 }
979
980 /* reprobe */
981 if (!fu_logitech_hidpp_peripheral_setup (device, error))
982 return FALSE;
983
984 /* success */
985 return TRUE;
986 }
987
988 static void
989 fu_logitech_hidpp_peripheral_finalize (GObject *object)
990 {
991 FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (object);
992 g_ptr_array_unref (self->feature_index);
993 G_OBJECT_CLASS (fu_logitech_hidpp_peripheral_parent_class)->finalize (object);
994 }
995
996 static void
997 fu_logitech_hidpp_peripheral_class_init (FuLogitechHidPpPeripheralClass *klass)
998 {
999 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
1000 FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass);
1001 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1002
1003 object_class->finalize = fu_logitech_hidpp_peripheral_finalize;
1004 klass_device->setup = fu_logitech_hidpp_peripheral_setup;
1005 klass_device->open = fu_logitech_hidpp_peripheral_open;
1006 klass_device->close = fu_logitech_hidpp_peripheral_close;
1007 klass_device->write_firmware = fu_logitech_hidpp_peripheral_write_firmware;
1008 klass_device->attach = fu_logitech_hidpp_peripheral_attach;
1009 klass_device->detach = fu_logitech_hidpp_peripheral_detach;
1010 klass_device->poll = fu_logitech_hidpp_peripheral_poll;
1011 klass_device->to_string = fu_logitech_hidpp_peripheral_to_string;
1012 klass_device_udev->probe = fu_logitech_hidpp_peripheral_probe;
1013 }
1014
1015 static void
1016 fu_logitech_hidpp_peripheral_init (FuLogitechHidPpPeripheral *self)
1017 {
1018 self->hidpp_id = HIDPP_DEVICE_ID_UNSET;
1019 self->feature_index = g_ptr_array_new_with_free_func (g_free);
1020 fu_device_add_parent_guid (FU_DEVICE (self), "HIDRAW\\VEN_046D&DEV_C52B");
1021 fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
1022
1023 /* there are a lot of unifying peripherals, but not all respond
1024 * well to opening -- so limit to ones with issued updates */
1025 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ONLY_SUPPORTED);
1026 }
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-udev-device.h"
9
10 #define FU_TYPE_UNIFYING_PERIPHERAL (fu_logitech_hidpp_peripheral_get_type ())
11 G_DECLARE_FINAL_TYPE (FuLogitechHidPpPeripheral, fu_logitech_hidpp_peripheral, FU, UNIFYING_PERIPHERAL, FuUdevDevice)
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-logitech-hidpp-common.h"
11 #include "fu-logitech-hidpp-runtime.h"
12 #include "fu-logitech-hidpp-hidpp.h"
13
14 struct _FuLogitechHidPpRuntime
15 {
16 FuUdevDevice parent_instance;
17 guint8 version_bl_major;
18 gboolean signed_firmware;
19 FuIOChannel *io_channel;
20 };
21
22 G_DEFINE_TYPE (FuLogitechHidPpRuntime, fu_logitech_hidpp_runtime, FU_TYPE_UDEV_DEVICE)
23
24 static void
25 fu_logitech_hidpp_runtime_to_string (FuDevice *device, guint idt, GString *str)
26 {
27 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
28 fu_common_string_append_kb (str, idt, "SignedFirmware", self->signed_firmware);
29 }
30
31 static gboolean
32 fu_logitech_hidpp_runtime_enable_notifications (FuLogitechHidPpRuntime *self, GError **error)
33 {
34 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
35 msg->report_id = HIDPP_REPORT_ID_SHORT;
36 msg->device_id = HIDPP_DEVICE_ID_RECEIVER;
37 msg->sub_id = HIDPP_SUBID_SET_REGISTER;
38 msg->function_id = HIDPP_REGISTER_HIDPP_NOTIFICATIONS;
39 msg->data[0] = 0x00;
40 msg->data[1] = 0x05; /* Wireless + SoftwarePresent */
41 msg->data[2] = 0x00;
42 msg->hidpp_version = 1;
43 return fu_logitech_hidpp_transfer (self->io_channel, msg, error);
44 }
45
46 static gboolean
47 fu_logitech_hidpp_runtime_close (FuDevice *device, GError **error)
48 {
49 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
50 if (!fu_io_channel_shutdown (self->io_channel, error))
51 return FALSE;
52 g_clear_object (&self->io_channel);
53 return TRUE;
54 }
55
56 static gboolean
57 fu_logitech_hidpp_runtime_poll (FuDevice *device, GError **error)
58 {
59 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
60 const guint timeout = 1; /* ms */
61 g_autoptr(GError) error_local = NULL;
62 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
63 g_autoptr(FuDeviceLocker) locker = NULL;
64
65 /* open */
66 locker = fu_device_locker_new (self, error);
67 if (locker == NULL)
68 return FALSE;
69
70 /* is there any pending data to read */
71 msg->hidpp_version = 1;
72 if (!fu_logitech_hidpp_receive (self->io_channel, msg, timeout, &error_local)) {
73 if (g_error_matches (error_local,
74 G_IO_ERROR,
75 G_IO_ERROR_TIMED_OUT)) {
76 return TRUE;
77 }
78 g_warning ("failed to get pending read: %s", error_local->message);
79 return TRUE;
80 }
81
82 /* HID++1.0 error */
83 if (!fu_logitech_hidpp_msg_is_error (msg, &error_local)) {
84 g_warning ("failed to get pending read: %s", error_local->message);
85 return TRUE;
86 }
87
88 /* unifying receiver notification */
89 if (msg->report_id == HIDPP_REPORT_ID_SHORT) {
90 switch (msg->sub_id) {
91 case HIDPP_SUBID_DEVICE_CONNECTION:
92 case HIDPP_SUBID_DEVICE_DISCONNECTION:
93 case HIDPP_SUBID_DEVICE_LOCKING_CHANGED:
94 g_debug ("device connection event, do something");
95 break;
96 case HIDPP_SUBID_LINK_QUALITY:
97 g_debug ("ignoring link quality message");
98 break;
99 case HIDPP_SUBID_ERROR_MSG:
100 g_debug ("ignoring link quality message");
101 break;
102 default:
103 g_debug ("unknown SubID %02x", msg->sub_id);
104 break;
105 }
106 }
107 return TRUE;
108 }
109
110 static gboolean
111 fu_logitech_hidpp_runtime_open (FuDevice *device, GError **error)
112 {
113 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
114 GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
115 const gchar *devpath = g_udev_device_get_device_file (udev_device);
116
117 /* open, but don't block */
118 self->io_channel = fu_io_channel_new_file (devpath, error);
119 if (self->io_channel == NULL)
120 return FALSE;
121
122 /* poll for notifications */
123 fu_device_set_poll_interval (device, 5000);
124
125 /* success */
126 return TRUE;
127 }
128
129 static gboolean
130 fu_logitech_hidpp_runtime_probe (FuUdevDevice *device, GError **error)
131 {
132 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
133 GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
134 guint16 release = 0xffff;
135 g_autoptr(GUdevDevice) udev_parent = NULL;
136
137 /* set the physical ID */
138 if (!fu_udev_device_set_physical_id (device, "usb", error))
139 return FALSE;
140
141 /* generate bootloader-specific GUID */
142 udev_parent = g_udev_device_get_parent_with_subsystem (udev_device,
143 "usb", "usb_device");
144 if (udev_parent != NULL) {
145 const gchar *release_str;
146 release_str = g_udev_device_get_property (udev_parent, "ID_REVISION");
147 if (release_str != NULL)
148 release = g_ascii_strtoull (release_str, NULL, 16);
149 }
150 if (release != 0xffff) {
151 g_autofree gchar *devid2 = NULL;
152 switch (release &= 0xff00) {
153 case 0x1200:
154 /* Nordic */
155 devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
156 (guint) FU_UNIFYING_DEVICE_VID,
157 (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC);
158 fu_device_add_counterpart_guid (FU_DEVICE (device), devid2);
159 self->version_bl_major = 0x01;
160 break;
161 case 0x2400:
162 /* Texas */
163 devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
164 (guint) FU_UNIFYING_DEVICE_VID,
165 (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS);
166 fu_device_add_counterpart_guid (FU_DEVICE (device), devid2);
167 self->version_bl_major = 0x03;
168 break;
169 default:
170 g_warning ("bootloader release %04x invalid", release);
171 break;
172 }
173 }
174 return TRUE;
175 }
176
177 static gboolean
178 fu_logitech_hidpp_runtime_setup_internal (FuDevice *device, GError **error)
179 {
180 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
181 guint8 config[10];
182 g_autofree gchar *version_fw = NULL;
183
184 /* read all 10 bytes of the version register */
185 memset (config, 0x00, sizeof (config));
186 for (guint i = 0x01; i < 0x05; i++) {
187 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
188
189 /* workaround a bug in the 12.01 firmware, which fails with
190 * INVALID_VALUE when reading MCU1_HW_VERSION */
191 if (i == 0x03)
192 continue;
193
194 msg->report_id = HIDPP_REPORT_ID_SHORT;
195 msg->device_id = HIDPP_DEVICE_ID_RECEIVER;
196 msg->sub_id = HIDPP_SUBID_GET_REGISTER;
197 msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION;
198 msg->data[0] = i;
199 msg->hidpp_version = 1;
200 if (!fu_logitech_hidpp_transfer (self->io_channel, msg, error)) {
201 g_prefix_error (error, "failed to read device config: ");
202 return FALSE;
203 }
204 if (!fu_memcpy_safe (config, sizeof(config), i * 2, /* dst */
205 msg->data, sizeof(msg->data), 0x1, /* src */
206 2, error))
207 return FALSE;
208 }
209
210 /* get firmware version */
211 version_fw = fu_logitech_hidpp_format_version ("RQR",
212 config[2],
213 config[3],
214 (guint16) config[4] << 8 |
215 config[5]);
216 fu_device_set_version (device, version_fw, FWUPD_VERSION_FORMAT_PLAIN);
217
218 /* get bootloader version */
219 if (self->version_bl_major > 0) {
220 g_autofree gchar *version_bl = NULL;
221 version_bl = fu_logitech_hidpp_format_version ("BOT",
222 self->version_bl_major,
223 config[8],
224 config[9]);
225 fu_device_set_version_bootloader (FU_DEVICE (device), version_bl);
226
227 /* is the dongle expecting signed firmware */
228 if ((self->version_bl_major == 0x01 && config[8] >= 0x04) ||
229 (self->version_bl_major == 0x03 && config[8] >= 0x02)) {
230 self->signed_firmware = TRUE;
231 }
232 }
233
234 /* enable HID++ notifications */
235 if (!fu_logitech_hidpp_runtime_enable_notifications (self, error)) {
236 g_prefix_error (error, "failed to enable notifications: ");
237 return FALSE;
238 }
239
240 /* success */
241 return TRUE;
242 }
243
244 static gboolean
245 fu_logitech_hidpp_runtime_setup (FuDevice *device, GError **error)
246 {
247 g_autoptr(GError) error_local = NULL;
248 for (guint i = 0; i < 5; i++) {
249 /* HID++1.0 devices have to sleep to allow Solaar to talk to
250 * the device first -- we can't use the SwID as this is a
251 * HID++2.0 feature */
252 g_usleep (200*1000);
253 if (fu_logitech_hidpp_runtime_setup_internal (device, &error_local))
254 return TRUE;
255 if (!g_error_matches (error_local,
256 G_IO_ERROR,
257 G_IO_ERROR_INVALID_DATA)) {
258 g_propagate_error (error, g_steal_pointer (&error_local));
259 return FALSE;
260 }
261 g_clear_error (&error_local);
262 }
263 g_propagate_error (error, g_steal_pointer (&error_local));
264 return FALSE;
265 }
266
267 static gboolean
268 fu_logitech_hidpp_runtime_detach (FuDevice *device, GError **error)
269 {
270 FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device);
271 g_autoptr(FuLogitechHidPpHidppMsg) msg = fu_logitech_hidpp_msg_new ();
272 msg->report_id = HIDPP_REPORT_ID_SHORT;
273 msg->device_id = HIDPP_DEVICE_ID_RECEIVER;
274 msg->sub_id = HIDPP_SUBID_SET_REGISTER;
275 msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE;
276 msg->data[0] = 'I';
277 msg->data[1] = 'C';
278 msg->data[2] = 'P';
279 msg->hidpp_version = 1;
280 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
281 if (!fu_logitech_hidpp_send (self->io_channel, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) {
282 g_prefix_error (error, "failed to detach to bootloader: ");
283 return FALSE;
284 }
285 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
286 return TRUE;
287 }
288
289 static void
290 fu_logitech_hidpp_runtime_finalize (GObject *object)
291 {
292 G_OBJECT_CLASS (fu_logitech_hidpp_runtime_parent_class)->finalize (object);
293 }
294
295 static void
296 fu_logitech_hidpp_runtime_class_init (FuLogitechHidPpRuntimeClass *klass)
297 {
298 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
299 FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass);
300 GObjectClass *object_class = G_OBJECT_CLASS (klass);
301
302 object_class->finalize = fu_logitech_hidpp_runtime_finalize;
303 klass_device->open = fu_logitech_hidpp_runtime_open;
304 klass_device_udev->probe = fu_logitech_hidpp_runtime_probe;
305 klass_device->setup = fu_logitech_hidpp_runtime_setup;
306 klass_device->close = fu_logitech_hidpp_runtime_close;
307 klass_device->detach = fu_logitech_hidpp_runtime_detach;
308 klass_device->poll = fu_logitech_hidpp_runtime_poll;
309 klass_device->to_string = fu_logitech_hidpp_runtime_to_string;
310 }
311
312 static void
313 fu_logitech_hidpp_runtime_init (FuLogitechHidPpRuntime *self)
314 {
315 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
316 fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard");
317 fu_device_set_name (FU_DEVICE (self), "Unifying Receiver");
318 fu_device_set_summary (FU_DEVICE (self), "A miniaturised USB wireless receiver");
319 fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
320 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-udev-device.h"
9
10 #define FU_TYPE_UNIFYING_RUNTIME (fu_logitech_hidpp_runtime_get_type ())
11 G_DECLARE_FINAL_TYPE (FuLogitechHidPpRuntime, fu_logitech_hidpp_runtime, FU, UNIFYING_RUNTIME, FuUdevDevice)
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <fwupd.h>
9 #include <glib-object.h>
10
11 #include "fu-logitech-hidpp-common.h"
12
13 static void
14 fu_logitech_hidpp_common (void)
15 {
16 guint8 u8;
17 guint16 u16;
18 g_autofree gchar *ver1 = NULL;
19
20 u8 = fu_logitech_hidpp_buffer_read_uint8 ("12");
21 g_assert_cmpint (u8, ==, 0x12);
22 u16 = fu_logitech_hidpp_buffer_read_uint16 ("1234");
23 g_assert_cmpint (u16, ==, 0x1234);
24
25 ver1 = fu_logitech_hidpp_format_version (" A ", 0x87, 0x65, 0x4321);
26 g_assert_cmpstr (ver1, ==, "A87.65_B4321");
27 }
28
29 int
30 main (int argc, char **argv)
31 {
32 g_test_init (&argc, &argv, NULL);
33
34 /* only critical and error are fatal */
35 g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
36
37 /* tests go here */
38 g_test_add_func ("/unifying/common", fu_logitech_hidpp_common);
39 return g_test_run ();
40 }
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <fwupd.h>
9
10 #include "fu-plugin-vfuncs.h"
11
12 #include "fu-logitech-hidpp-bootloader-nordic.h"
13 #include "fu-logitech-hidpp-bootloader-texas.h"
14 #include "fu-logitech-hidpp-common.h"
15 #include "fu-logitech-hidpp-peripheral.h"
16 #include "fu-logitech-hidpp-runtime.h"
17
18 gboolean
19 fu_plugin_startup (FuPlugin *plugin, GError **error)
20 {
21 /* check the kernel has CONFIG_HIDRAW */
22 if (!g_file_test ("/sys/class/hidraw", G_FILE_TEST_IS_DIR)) {
23 g_set_error_literal (error,
24 FWUPD_ERROR,
25 FWUPD_ERROR_NOT_SUPPORTED,
26 "no kernel support for CONFIG_HIDRAW");
27 return FALSE;
28 }
29 return TRUE;
30 }
31
32 void
33 fu_plugin_init (FuPlugin *plugin)
34 {
35 fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
36 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying");
37 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned");
38 fu_plugin_add_udev_subsystem (plugin, "hidraw");
39 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_CONFLICTS, "unifying");
40
41 /* register the custom types */
42 g_type_ensure (FU_TYPE_UNIFYING_BOOTLOADER_NORDIC);
43 g_type_ensure (FU_TYPE_UNIFYING_BOOTLOADER_TEXAS);
44 g_type_ensure (FU_TYPE_UNIFYING_PERIPHERAL);
45 g_type_ensure (FU_TYPE_UNIFYING_RUNTIME);
46 }
0 # Unifying Receiver
1 [DeviceInstanceId=HIDRAW\VEN_046D&DEV_C52B]
2 Plugin = logitech_hidpp
3 GType = FuLogitechHidPpRuntime
4 VendorId=USB:0x046D
5 InstallDuration = 30
6
7 # Nordic
8 [DeviceInstanceId=USB\VID_046D&PID_AAAA]
9 Plugin = logitech_hidpp
10 GType = FuLogitechHidPpBootloaderNordic
11 FirmwareSizeMin = 0x4000
12 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
13 InstallDuration = 30
14
15 # Nordic Pico
16 [DeviceInstanceId=USB\VID_046D&PID_AAAE]
17 Plugin = logitech_hidpp
18 GType = FuLogitechHidPpBootloaderNordic
19 FirmwareSizeMin = 0x4000
20 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
21 InstallDuration = 30
22
23 # Texas
24 [DeviceInstanceId=USB\VID_046D&PID_AAAC]
25 Plugin = logitech_hidpp
26 GType = FuLogitechHidPpBootloaderTexas
27 FirmwareSizeMin = 0x4000
28 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
29 InstallDuration = 18
30
31 # Texas Pico
32 [DeviceInstanceId=USB\VID_046D&PID_AAAD]
33 Plugin = logitech_hidpp
34 GType = FuLogitechHidPpBootloaderTexas
35 FirmwareSizeMin = 0x4000
36 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
37 InstallDuration = 18
38
39 # Possible HID++ v2.0 peripheral device
40 [DeviceInstanceId=HIDRAW\VEN_046D]
41 Plugin = logitech_hidpp
42 GType = FuLogitechHidPpPeripheral
0 cargs = ['-DG_LOG_DOMAIN="FuPluginLogitechHidPp"']
1
2 install_data([
3 'logitech-hidpp.quirk',
4 ],
5 install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
6 )
7
8
9 shared_module('fu_plugin_logitech_hidpp',
10 fu_hash,
11 sources : [
12 'fu-plugin-logitech-hidpp.c',
13 'fu-logitech-hidpp-bootloader.c',
14 'fu-logitech-hidpp-bootloader-nordic.c',
15 'fu-logitech-hidpp-bootloader-texas.c',
16 'fu-logitech-hidpp-common.c',
17 'fu-logitech-hidpp-hidpp.c',
18 'fu-logitech-hidpp-hidpp-msg.c',
19 'fu-logitech-hidpp-peripheral.c',
20 'fu-logitech-hidpp-runtime.c',
21 ],
22 include_directories : [
23 include_directories('../..'),
24 include_directories('../../src'),
25 include_directories('../../libfwupd'),
26 ],
27 install : true,
28 install_dir: plugin_dir,
29 link_with : [
30 libfwupdprivate,
31 ],
32 c_args : cargs,
33 dependencies : [
34 plugin_deps,
35 ],
36 )
37
38 if get_option('tests')
39 e = executable(
40 'logitech-hidpp-self-test',
41 fu_hash,
42 sources : [
43 'fu-logitech-hidpp-self-test.c',
44 'fu-logitech-hidpp-common.c',
45 ],
46 include_directories : [
47 include_directories('../..'),
48 include_directories('../../libfwupd'),
49 ],
50 dependencies : [
51 plugin_deps,
52 ],
53 link_with : [
54 libfwupdprivate,
55 ],
56 c_args : cargs,
57 )
58 test('logitech-hidpp-self-test', e)
59 endif
66 subdir('jabra')
77 subdir('steelseries')
88 subdir('dell-dock')
9 subdir('logitech-hidpp')
910 subdir('nitrokey')
1011 subdir('optionrom')
1112 subdir('rts54hid')
1516 subdir('synaptics-prometheus')
1617 subdir('test')
1718 subdir('thelio-io')
18 subdir('unifying')
1919 subdir('upower')
2020 subdir('wacom-raw')
2121 subdir('wacom-usb')
1313 #include "fu-device-private.h"
1414 #include "fu-mm-utils.h"
1515 #include "fu-qmi-pdc-updater.h"
16
17 /* Amount of time for the modem to boot in fastboot mode. */
18 #define FU_MM_DEVICE_REMOVE_DELAY_RE_ENUMERATE 20000 /* ms */
1619
1720 /* Amount of time for the modem to be re-probed and exposed in MM after being
1821 * uninhibited. The timeout is long enough to cover the worst case, where the
232235 fu_device_set_vendor (device, mm_modem_get_manufacturer (modem));
233236 if (mm_modem_get_model (modem) != NULL)
234237 fu_device_set_name (device, mm_modem_get_model (modem));
235 fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_UNKNOWN);
238 fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_PLAIN);
236239 for (guint i = 0; device_ids[i] != NULL; i++)
237240 fu_device_add_instance_id (device, device_ids[i]);
238241
372375 }
373376
374377 /* success */
375 fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
378 fu_device_set_remove_delay (device, FU_MM_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
376379 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
377380 return TRUE;
378381 }
482485 return (g_strstr_len (version, -1, carrier_id) != NULL);
483486 }
484487
485 static void
488 static gboolean
486489 fu_mm_qmi_pdc_archive_iterate_mcfg (FuArchive *archive,
487490 const gchar *filename,
488491 GBytes *bytes,
489 gpointer user_data)
492 gpointer user_data,
493 GError **error)
490494 {
491495 FuMmArchiveIterateCtx *ctx = user_data;
492496 FuMmFileInfo *file_info;
493497
494498 /* filenames should be named as 'mcfg.*.mbn', e.g.: mcfg.A2.018.mbn */
495499 if (!g_str_has_prefix (filename, "mcfg.") || !g_str_has_suffix (filename, ".mbn"))
496 return;
500 return TRUE;
497501
498502 file_info = g_new0 (FuMmFileInfo, 1);
499503 file_info->filename = g_strdup (filename);
501505 file_info->active = fu_mm_should_be_active (fu_device_get_version (FU_DEVICE (ctx->device)), filename);
502506 g_ptr_array_add (ctx->file_infos, file_info);
503507 ctx->total_bytes += g_bytes_get_size (file_info->bytes);
508 return TRUE;
504509 }
505510
506511 static gboolean
558563 return FALSE;
559564
560565 /* process the list of MCFG files to write */
561 fu_archive_iterate (archive, fu_mm_qmi_pdc_archive_iterate_mcfg, &archive_context);
566 if (!fu_archive_iterate (archive,
567 fu_mm_qmi_pdc_archive_iterate_mcfg,
568 &archive_context,
569 error))
570 return FALSE;
562571
563572 for (guint i = 0; i < file_infos->len; i++) {
564573 FuMmFileInfo *file_info = g_ptr_array_index (file_infos, i);
794803 fu_device_set_physical_id (FU_DEVICE (self), info->physical_id);
795804 fu_device_set_vendor (FU_DEVICE (self), info->vendor);
796805 fu_device_set_name (FU_DEVICE (self), info->name);
797 fu_device_set_version (FU_DEVICE (self), info->version, FWUPD_VERSION_FORMAT_UNKNOWN);
806 fu_device_set_version (FU_DEVICE (self), info->version, FWUPD_VERSION_FORMAT_PLAIN);
798807 self->update_methods = info->update_methods;
799808 self->detach_fastboot_at = g_strdup (info->detach_fastboot_at);
800809 self->port_at_ifnum = info->port_at_ifnum;
66 #include "config.h"
77
88 #include <gio/gio.h>
9
10 #include "fu-udev-device.h"
11
912 #include "fu-mm-utils.h"
1013
1114 gboolean
99 #include "config.h"
1010 #include <gudev/gudev.h>
1111
12 #ifndef HAVE_GUDEV_232
13 #pragma clang diagnostic push
14 #pragma clang diagnostic ignored "-Wunused-function"
15 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref)
16 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
17 #pragma clang diagnostic pop
18 #endif
19
2012 gboolean fu_mm_utils_get_udev_port_info (GUdevDevice *dev,
2113 gchar **device_sysfs_path,
2214 gint *port_ifnum,
88 Summary = Dell DW5821e LTE modem (fastboot)
99 CounterpartGuid = USB\VID_413C&PID_81D7
1010
11 # DW5821e/eSIM
12 [DeviceInstanceId=USB\VID_413C&PID_81E0]
13 Summary = Dell DW5821e/eSIM LTE modem
14 CounterpartGuid = USB\VID_413C&PID_81E1
15
16 # DW5821e/eSIM in fastboot mode
17 [DeviceInstanceId=USB\VID_413C&PID_81E1]
18 Summary = Dell DW5821e/eSIM LTE modem (fastboot)
19 CounterpartGuid = USB\VID_413C&PID_81E0
20
21 # T77W968
22 [DeviceInstanceId=USB\VID_0489&PID_E0B4]
23 Summary = Foxconn T77w968 LTE modem
24 CounterpartGuid = USB\VID_0489&PID_E0B7
25
26 # T77W968 in fastboot mode
27 [DeviceInstanceId=USB\VID_0489&PID_E0B7]
28 Summary = Foxconn T77w968 LTE modem (fastboot)
29 CounterpartGuid = USB\VID_0489&PID_E0B4
30
31 # T77W968/eSIM
32 [DeviceInstanceId=USB\VID_0489&PID_E0B5]
33 Summary = Foxconn T77w968/eSIM LTE modem
34 CounterpartGuid = USB\VID_0489&PID_E0B8
35
36 # T77W968/eSIM in fastboot mode
37 [DeviceInstanceId=USB\VID_0489&PID_E0B8]
38 Summary = Foxconn T77w968/eSIM LTE modem (fastboot)
39 CounterpartGuid = USB\VID_0489&PID_E0B5
2121 };
2222
2323 G_DEFINE_TYPE (FuNvmeDevice, fu_nvme_device, FU_TYPE_UDEV_DEVICE)
24
25 #ifndef HAVE_GUDEV_232
26 #pragma clang diagnostic push
27 #pragma clang diagnostic ignored "-Wunused-function"
28 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
29 #pragma clang diagnostic pop
30 #endif
3124
3225 static void
3326 fu_nvme_device_to_string (FuDevice *device, guint idt, GString *str)
469469 }
470470
471471 /* verify the signature and reboot back to runtime */
472 fw_sig = fu_firmware_get_image_by_id_bytes (firmware, "signature", error);
472 fw_sig = fu_firmware_get_image_by_id_bytes (firmware,
473 FU_FIRMWARE_IMAGE_ID_SIGNATURE,
474 error);
473475 if (fw_sig == NULL)
474476 return FALSE;
475477 return fu_solokey_device_verify (self, fw_sig, error);
8787 g_string_append (base64_websafe, "==");
8888 fw_sig = _g_base64_decode_to_bytes (base64_websafe->str);
8989 fu_firmware_image_set_bytes (img_sig, fw_sig);
90 fu_firmware_image_set_id (img_sig, "signature");
90 fu_firmware_image_set_id (img_sig, FU_FIRMWARE_IMAGE_ID_SIGNATURE);
9191 fu_firmware_add_image (firmware, img_sig);
9292 return TRUE;
9393 }
4444 /* create IT89xx or IT89xx */
4545 if (id >> 8 == 0x85) {
4646 dev = g_object_new (FU_TYPE_SUPERIO_IT85_DEVICE,
47 "device-file", "/dev/port",
4748 "chipset", chipset,
4849 "id", id,
4950 "port", port,
5051 NULL);
5152 } else if (id >> 8 == 0x89) {
5253 dev = g_object_new (FU_TYPE_SUPERIO_IT89_DEVICE,
54 "device-file", "/dev/port",
5355 "chipset", chipset,
5456 "id", id,
5557 "port", port,
1919 guint16 id;
2020 } FuSuperioDevicePrivate;
2121
22 G_DEFINE_TYPE_WITH_PRIVATE (FuSuperioDevice, fu_superio_device, FU_TYPE_DEVICE)
22 G_DEFINE_TYPE_WITH_PRIVATE (FuSuperioDevice, fu_superio_device, FU_TYPE_UDEV_DEVICE)
2323
2424 #define GET_PRIVATE(o) (fu_superio_device_get_instance_private (o))
2525
262262 FuSuperioDeviceClass *klass = FU_SUPERIO_DEVICE_GET_CLASS (device);
263263 FuSuperioDevice *self = FU_SUPERIO_DEVICE (device);
264264 FuSuperioDevicePrivate *priv = GET_PRIVATE (self);
265 guint8 tmp = 0x0;
266
267 /* check port is valid */
268 if (!fu_udev_device_pread (FU_UDEV_DEVICE (self), priv->pm1_iobad0, &tmp, error))
269 return FALSE;
270 if (tmp != 0xff) {
271 g_set_error_literal (error,
272 FWUPD_ERROR,
273 FWUPD_ERROR_NOT_SUPPORTED,
274 "check port!");
275 return FALSE;
276 }
277265
278266 /* check ID is correct */
279267 if (!fu_superio_device_check_id (self, error)) {
88 #include "fu-plugin.h"
99
1010 #define FU_TYPE_SUPERIO_DEVICE (fu_superio_device_get_type ())
11 G_DECLARE_DERIVABLE_TYPE (FuSuperioDevice, fu_superio_device, FU, SUPERIO_DEVICE, FuDevice)
11 G_DECLARE_DERIVABLE_TYPE (FuSuperioDevice, fu_superio_device, FU, SUPERIO_DEVICE, FuUdevDevice)
1212
1313 struct _FuSuperioDeviceClass
1414 {
15 FuDeviceClass parent_class;
15 FuUdevDeviceClass parent_class;
1616 gboolean (*setup) (FuSuperioDevice *self,
1717 GError **error);
1818 };
619619 g_debug ("ignoring: %s", error_local->message);
620620 }
621621
622 fu_udev_device_set_fd (device, -1);
622623 g_clear_object (&priv->io_channel);
623624 return TRUE;
624625 }
2626 gsize bufsz = 0;
2727 g_autofree gchar *buf = NULL;
2828 g_auto(GStrv) lines = NULL;
29
30 /* no module support in the kernel, we can't test for amdgpu module */
31 if (!g_file_test ("/proc/modules", G_FILE_TEST_EXISTS))
32 return TRUE;
2933
3034 if (!g_file_get_contents ("/proc/modules", &buf, &bufsz, error))
3135 return FALSE;
10461046 return FALSE;
10471047 }
10481048 self->chip_id = (buf_ver[0] << 8) | (buf_ver[1]);
1049 if (self->chip_id == 0) {
1050 g_set_error_literal (error,
1051 G_IO_ERROR,
1052 G_IO_ERROR_INVALID_DATA,
1053 "invalid chip ID");
1054 return FALSE;
1055 }
10491056 self->family = fu_synapticsmst_family_from_chip_id (self->chip_id);
10501057
10511058 /* check the active bank for debugging */
1818 #include "fu-device-metadata.h"
1919 #include "fu-thunderbolt-image.h"
2020
21 #ifndef HAVE_GUDEV_232
22 #pragma clang diagnostic push
23 #pragma clang diagnostic ignored "-Wunused-function"
24 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
25 #pragma clang diagnostic pop
26 #endif
27
2821 #define TBT_NVM_RETRY_TIMEOUT 200 /* ms */
2922 #define FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT 60000 /* ms */
3023
9891 g_set_error (error,
9992 FWUPD_ERROR,
10093 FWUPD_ERROR_INTERNAL,
101 "failed get id %s for %s", name, sysfs);
94 "missing sysfs attribute %s", name);
10295 return FALSE;
10396 }
10497
1616 #define BOLT_DBUS_SERVICE "org.freedesktop.bolt"
1717 #define BOLT_DBUS_PATH "/org/freedesktop/bolt"
1818 #define BOLT_DBUS_INTERFACE "org.freedesktop.bolt1.Power"
19
20 #ifndef HAVE_GUDEV_232
21 #pragma clang diagnostic push
22 #pragma clang diagnostic ignored "-Wunused-function"
23 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
24 #pragma clang diagnostic pop
25 #endif
2619
2720 /* empirically measured amount of time for the TBT device to come and go */
2821 #define TBT_NEW_DEVICE_TIMEOUT 2 /* s */
00 #!/bin/sh
11 output=$2
2 objcopy_cmd=$(which objcopy)
3 genpeimg_cmd=$(which genpeimg)
2 objcopy_cmd=$(command -v objcopy)
3 genpeimg_cmd=$(command -v genpeimg)
44
5 $objcopy_cmd -j .text \
5 "$objcopy_cmd" -j .text \
66 -j .sdata \
77 -j .data \
88 -j .dynamic \
99 -j .dynsym \
10 -j .rel \
11 -j .rela \
12 -j .reloc \
13 $*
10 -j '.rel*' \
11 "$@"
1412
1513 if [ -n "${genpeimg_cmd}" ]; then
1614 $genpeimg_cmd -d \
1917 +n \
2018 -d \
2119 +s \
22 $output
20 "$output"
2321 fi
9494 efi_load_option *loadopt = NULL;
9595 gchar *name = NULL;
9696 gint rc;
97 gint set_entries[0x10000 / sizeof(gint)] = {0,};
9897 gsize var_data_size = 0;
99 guint16 real_boot16;
10098 guint32 attr;
101 guint32 boot_next = 0x10000;
99 guint16 boot_next = G_MAXUINT16;
102100 g_autofree guint8 *var_data = NULL;
101 g_autofree guint8 *set_entries = g_malloc0 (G_MAXUINT16);
103102
104103 while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) {
105104 const gchar *desc;
106 gint div, mod;
107105 gint scanned = 0;
108106 guint16 entry = 0;
109107 g_autofree guint8 *var_data_tmp = NULL;
123121 if (scanned != 8)
124122 continue;
125123
126 div = entry / (sizeof(set_entries[0]) * 8);
127 mod = entry % (sizeof(set_entries[0]) * 8);
128
129 set_entries[div] |= 1 << mod;
124 /* mark this as used */
125 set_entries[entry] = 1;
130126
131127 rc = efi_get_variable (*guid, name, &var_data_tmp, &var_data_size, &attr);
132128 if (rc < 0) {
179175 /* create a new one */
180176 } else {
181177 g_autofree gchar *boot_next_name = NULL;
182 for (guint32 value = 0; value < 0x10000; value++) {
183 gint div = value / (sizeof(set_entries[0]) * 8);
184 gint mod = value % (sizeof(set_entries[0]) * 8);
185 if (set_entries[div] & (1 << mod))
178 for (guint16 value = 0; value < G_MAXUINT16; value++) {
179 if (set_entries[value])
186180 continue;
187181 boot_next = value;
188182 break;
189183 }
190 if (boot_next >= 0x10000) {
184 if (boot_next == G_MAXUINT16) {
191185 g_set_error (error,
192186 G_IO_ERROR,
193187 G_IO_ERROR_FAILED,
195189 boot_next);
196190 return FALSE;
197191 }
198 boot_next_name = g_strdup_printf ("Boot%04X",
199 (guint) (boot_next & 0xffff));
192 boot_next_name = g_strdup_printf ("Boot%04X", (guint) boot_next);
200193 rc = efi_set_variable (efi_guid_global, boot_next_name, opt, opt_size,
201194 EFI_VARIABLE_NON_VOLATILE |
202195 EFI_VARIABLE_BOOTSERVICE_ACCESS |
217210 return FALSE;
218211
219212 /* set the boot next */
220 real_boot16 = boot_next;
221 rc = efi_set_variable (efi_guid_global, "BootNext", (guint8 *)&real_boot16, 2,
213 rc = efi_set_variable (efi_guid_global, "BootNext", (guint8 *)&boot_next, 2,
222214 EFI_VARIABLE_NON_VOLATILE |
223215 EFI_VARIABLE_BOOTSERVICE_ACCESS |
224216 EFI_VARIABLE_RUNTIME_ACCESS,
228220 G_IO_ERROR,
229221 G_IO_ERROR_FAILED,
230222 "could not set BootNext(%" G_GUINT16_FORMAT ")",
231 real_boot16);
223 boot_next);
232224 return FALSE;
233225 }
234226 return TRUE;
241241 }
242242
243243 gchar *
244 fu_uefi_get_esp_path_for_os (const gchar *esp_path)
245 {
244 fu_uefi_get_esp_path_for_os (const gchar *base)
245 {
246 #ifndef EFI_OS_DIR
246247 const gchar *os_release_id = NULL;
247 #ifndef EFI_OS_DIR
248 const gchar *id_like_id;
249 g_autofree gchar *esp_path = NULL;
248250 g_autoptr(GError) error_local = NULL;
249251 g_autoptr(GHashTable) os_release = fwupd_get_os_release (&error_local);
252 /* try to lookup /etc/os-release ID key */
250253 if (os_release != NULL) {
251254 os_release_id = g_hash_table_lookup (os_release, "ID");
252255 } else {
254257 }
255258 if (os_release_id == NULL)
256259 os_release_id = "unknown";
260 /* if ID key points at something existing return it */
261 esp_path = g_build_filename (base, "EFI", os_release_id, NULL);
262 if (g_file_test (esp_path, G_FILE_TEST_IS_DIR) || os_release == NULL)
263 return g_steal_pointer (&esp_path);
264 /* if ID key doesn't exist, try ID_LIKE */
265 id_like_id = g_hash_table_lookup (os_release, "ID_LIKE");
266 if (id_like_id != NULL) {
267 g_autofree gchar* id_like_path = g_build_filename (base, "EFI", id_like_id, NULL);
268 if (g_file_test (id_like_path, G_FILE_TEST_IS_DIR)) {
269 g_debug ("Using ID_LIKE key from os-release");
270 return g_steal_pointer (&id_like_path);
271 }
272 }
273 return g_steal_pointer (&esp_path);
257274 #else
258 os_release_id = EFI_OS_DIR;
275 return g_build_filename (base, "EFI", EFI_OS_DIR, NULL);
259276 #endif
260 return g_build_filename (esp_path, "EFI", os_release_id, NULL);
261277 }
262278
263279 guint64
+0
-54
plugins/unifying/README.md less more
0 Unifying Support
1 ================
2
3 Introduction
4 ------------
5
6 This plugin can flash the firmware on Logitech Unifying dongles, both the
7 Nordic (U0007) device and the Texas Instruments (U0008) version.
8
9 This plugin will not work with the different "Nano" dongle (U0010) as it does
10 not use the Unifying protocol.
11
12 Some bootloader protocol information was taken from the Mousejack[1] project,
13 specifically logitech-usb-restore.py and unifying.py. Other documentation was
14 supplied by Logitech.
15
16 Additional constants were taken from the Solaar[2] project.
17
18 Firmware Format
19 ---------------
20
21 The daemon will decompress the cabinet archive and extract a firmware blob in
22 a vendor-specific format that appears to be a subset of the Intel HEX format.
23
24 This plugin supports the following protocol IDs:
25
26 * com.logitech.unifying
27 * com.logitech.unifyingsigned
28
29 GUID Generation
30 ---------------
31
32 These devices use the standard USB DeviceInstanceId values when in DFU mode:
33
34 * `USB\VID_046D&PID_AAAA&REV_0001`
35 * `USB\VID_046D&PID_AAAA`
36 * `USB\VID_046D`
37
38 When in runtime mode, the HID raw DeviceInstanceId values are used:
39
40 * `HIDRAW\VEN_046D&DEV_C52B`
41 * `HIDRAW\VEN_046D`
42
43 Design Notes
44 ------------
45
46 When a dongle is detected in bootloader mode we detach the hidraw driver from
47 the kernel and use raw control transfers. This ensures that we don't accidentally
48 corrupt the uploading firmware. For application firmware we use hidraw which
49 means the hardware keeps working while probing, and also allows us to detect
50 paired devices.
51
52 [1] https://www.mousejack.com/
53 [2] https://pwr-Solaar.github.io/Solaar/
plugins/unifying/data/dump.csv.gz less more
Binary diff not shown
plugins/unifying/data/dump.tdc less more
Binary diff not shown
+0
-56
plugins/unifying/data/lsusb-U0007-bootloader.txt less more
0 Bus 001 Device 036: ID 046d:aaaa Logitech, Inc.
1 Device Descriptor:
2 bLength 18
3 bDescriptorType 1
4 bcdUSB 2.00
5 bDeviceClass 0
6 bDeviceSubClass 0
7 bDeviceProtocol 0
8 bMaxPacketSize0 32
9 idVendor 0x046d Logitech, Inc.
10 idProduct 0xaaaa
11 bcdDevice 1.02
12 iManufacturer 1
13 iProduct 2
14 iSerial 0
15 bNumConfigurations 1
16 Configuration Descriptor:
17 bLength 9
18 bDescriptorType 2
19 wTotalLength 34
20 bNumInterfaces 1
21 bConfigurationValue 1
22 iConfiguration 4
23 bmAttributes 0x80
24 (Bus Powered)
25 MaxPower 98mA
26 Interface Descriptor:
27 bLength 9
28 bDescriptorType 4
29 bInterfaceNumber 0
30 bAlternateSetting 0
31 bNumEndpoints 1
32 bInterfaceClass 3 Human Interface Device
33 bInterfaceSubClass 0
34 bInterfaceProtocol 0
35 iInterface 0
36 HID Device Descriptor:
37 bLength 9
38 bDescriptorType 33
39 bcdHID 1.11
40 bCountryCode 0 Not supported
41 bNumDescriptors 1
42 bDescriptorType 34 Report
43 wDescriptorLength 25
44 Report Descriptors:
45 ** UNAVAILABLE **
46 Endpoint Descriptor:
47 bLength 7
48 bDescriptorType 5
49 bEndpointAddress 0x81 EP 1 IN
50 bmAttributes 3
51 Transfer Type Interrupt
52 Synch Type None
53 Usage Type Data
54 wMaxPacketSize 0x0020 1x 32 bytes
55 bInterval 1
+0
-118
plugins/unifying/data/lsusb-U0007.txt less more
0 Bus 001 Device 049: ID 046d:c52b Logitech, Inc. Unifying Receiver
1 Device Descriptor:
2 bLength 18
3 bDescriptorType 1
4 bcdUSB 2.00
5 bDeviceClass 0
6 bDeviceSubClass 0
7 bDeviceProtocol 0
8 bMaxPacketSize0 8
9 idVendor 0x046d Logitech, Inc.
10 idProduct 0xc52b Unifying Receiver
11 bcdDevice 12.07
12 iManufacturer 1 Logitech
13 iProduct 2 USB Receiver
14 iSerial 0
15 bNumConfigurations 1
16 Configuration Descriptor:
17 bLength 9
18 bDescriptorType 2
19 wTotalLength 84
20 bNumInterfaces 3
21 bConfigurationValue 1
22 iConfiguration 4 RQR12.07_B0029
23 bmAttributes 0xa0
24 (Bus Powered)
25 Remote Wakeup
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 1 Boot Interface Subclass
35 bInterfaceProtocol 1 Keyboard
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 59
45 Report Descriptor: (length is 59)
46 Endpoint Descriptor:
47 bLength 7
48 bDescriptorType 5
49 bEndpointAddress 0x81 EP 1 IN
50 bmAttributes 3
51 Transfer Type Interrupt
52 Synch Type None
53 Usage Type Data
54 wMaxPacketSize 0x0008 1x 8 bytes
55 bInterval 8
56 Interface Descriptor:
57 bLength 9
58 bDescriptorType 4
59 bInterfaceNumber 1
60 bAlternateSetting 0
61 bNumEndpoints 1
62 bInterfaceClass 3 Human Interface Device
63 bInterfaceSubClass 1 Boot Interface Subclass
64 bInterfaceProtocol 2 Mouse
65 iInterface 0
66 HID Device Descriptor:
67 bLength 9
68 bDescriptorType 33
69 bcdHID 1.11
70 bCountryCode 0 Not supported
71 bNumDescriptors 1
72 bDescriptorType 34 Report
73 wDescriptorLength 148
74 Report Descriptors:
75 ** UNAVAILABLE **
76 Endpoint Descriptor:
77 bLength 7
78 bDescriptorType 5
79 bEndpointAddress 0x82 EP 2 IN
80 bmAttributes 3
81 Transfer Type Interrupt
82 Synch Type None
83 Usage Type Data
84 wMaxPacketSize 0x0008 1x 8 bytes
85 bInterval 2
86 Interface Descriptor:
87 bLength 9
88 bDescriptorType 4
89 bInterfaceNumber 2
90 bAlternateSetting 0
91 bNumEndpoints 1
92 bInterfaceClass 3 Human Interface Device
93 bInterfaceSubClass 0
94 bInterfaceProtocol 0
95 iInterface 0
96 HID Device Descriptor:
97 bLength 9
98 bDescriptorType 33
99 bcdHID 1.11
100 bCountryCode 0 Not supported
101 bNumDescriptors 1
102 bDescriptorType 34 Report
103 wDescriptorLength 93
104 Report Descriptors:
105 ** UNAVAILABLE **
106 Endpoint Descriptor:
107 bLength 7
108 bDescriptorType 5
109 bEndpointAddress 0x83 EP 3 IN
110 bmAttributes 3
111 Transfer Type Interrupt
112 Synch Type None
113 Usage Type Data
114 wMaxPacketSize 0x0020 1x 32 bytes
115 bInterval 2
116 Device Status: 0x0000
117 (Bus Powered)
+0
-79
plugins/unifying/data/lsusb-U0008-bootloader-old.txt less more
0
1 Bus 003 Device 036: ID 046d:aaac Logitech, Inc.
2 Device Descriptor:
3 bLength 18
4 bDescriptorType 1
5 bcdUSB 2.00
6 bDeviceClass 0
7 bDeviceSubClass 0
8 bDeviceProtocol 0
9 bMaxPacketSize0 32
10 idVendor 0x046d Logitech, Inc.
11 idProduct 0xaaac
12 bcdDevice 3.01
13 iManufacturer 1 Logitech
14 iProduct 2 USB BootLoader
15 iSerial 0
16 bNumConfigurations 1
17 Configuration Descriptor:
18 bLength 9
19 bDescriptorType 2
20 wTotalLength 34
21 bNumInterfaces 1
22 bConfigurationValue 1
23 iConfiguration 4 BOT03.01_B0008
24 bmAttributes 0x80
25 (Bus Powered)
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 0
35 bInterfaceProtocol 0
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 25
45 Report Descriptor: (length is 25)
46 Item(Global): Usage Page, data= [ 0xb0 0xff ] 65456
47 (null)
48 Item(Local ): Usage, data= [ 0x01 ] 1
49 (null)
50 Item(Main ): Collection, data= [ 0x01 ] 1
51 Application
52 Item(Global): Report Size, data= [ 0x08 ] 8
53 Item(Global): Report Count, data= [ 0x20 ] 32
54 Item(Global): Logical Minimum, data= [ 0x00 ] 0
55 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
56 Item(Local ): Usage, data= [ 0x01 ] 1
57 (null)
58 Item(Main ): Input, data= [ 0x00 ] 0
59 Data Array Absolute No_Wrap Linear
60 Preferred_State No_Null_Position Non_Volatile Bitfield
61 Item(Local ): Usage, data= [ 0x01 ] 1
62 (null)
63 Item(Main ): Output, data= [ 0x00 ] 0
64 Data Array Absolute No_Wrap Linear
65 Preferred_State No_Null_Position Non_Volatile Bitfield
66 Item(Main ): End Collection, data=none
67 Endpoint Descriptor:
68 bLength 7
69 bDescriptorType 5
70 bEndpointAddress 0x81 EP 1 IN
71 bmAttributes 3
72 Transfer Type Interrupt
73 Synch Type None
74 Usage Type Data
75 wMaxPacketSize 0x0020 1x 32 bytes
76 bInterval 1
77 Device Status: 0x0000
78 (Bus Powered)
+0
-79
plugins/unifying/data/lsusb-U0008-bootloader.txt less more
0
1 Bus 003 Device 039: ID 046d:aaac Logitech, Inc.
2 Device Descriptor:
3 bLength 18
4 bDescriptorType 1
5 bcdUSB 2.00
6 bDeviceClass 0
7 bDeviceSubClass 0
8 bDeviceProtocol 0
9 bMaxPacketSize0 32
10 idVendor 0x046d Logitech, Inc.
11 idProduct 0xaaac
12 bcdDevice 3.00
13 iManufacturer 1 Logitech
14 iProduct 2 USB BootLoader
15 iSerial 0
16 bNumConfigurations 1
17 Configuration Descriptor:
18 bLength 9
19 bDescriptorType 2
20 wTotalLength 34
21 bNumInterfaces 1
22 bConfigurationValue 1
23 iConfiguration 4 BOT03.00_B0006
24 bmAttributes 0x80
25 (Bus Powered)
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 0
35 bInterfaceProtocol 0
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 25
45 Report Descriptor: (length is 25)
46 Item(Global): Usage Page, data= [ 0xb0 0xff ] 65456
47 (null)
48 Item(Local ): Usage, data= [ 0x01 ] 1
49 (null)
50 Item(Main ): Collection, data= [ 0x01 ] 1
51 Application
52 Item(Global): Report Size, data= [ 0x08 ] 8
53 Item(Global): Report Count, data= [ 0x20 ] 32
54 Item(Global): Logical Minimum, data= [ 0x00 ] 0
55 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
56 Item(Local ): Usage, data= [ 0x01 ] 1
57 (null)
58 Item(Main ): Input, data= [ 0x00 ] 0
59 Data Array Absolute No_Wrap Linear
60 Preferred_State No_Null_Position Non_Volatile Bitfield
61 Item(Local ): Usage, data= [ 0x01 ] 1
62 (null)
63 Item(Main ): Output, data= [ 0x00 ] 0
64 Data Array Absolute No_Wrap Linear
65 Preferred_State No_Null_Position Non_Volatile Bitfield
66 Item(Main ): End Collection, data=none
67 Endpoint Descriptor:
68 bLength 7
69 bDescriptorType 5
70 bEndpointAddress 0x81 EP 1 IN
71 bmAttributes 3
72 Transfer Type Interrupt
73 Synch Type None
74 Usage Type Data
75 wMaxPacketSize 0x0020 1x 32 bytes
76 bInterval 1
77 Device Status: 0x0000
78 (Bus Powered)
+0
-367
plugins/unifying/data/lsusb-U0008-old.txt less more
0
1 Bus 003 Device 033: ID 046d:c52b Logitech, Inc. Unifying Receiver
2 Device Descriptor:
3 bLength 18
4 bDescriptorType 1
5 bcdUSB 2.00
6 bDeviceClass 0
7 bDeviceSubClass 0
8 bDeviceProtocol 0
9 bMaxPacketSize0 32
10 idVendor 0x046d Logitech, Inc.
11 idProduct 0xc52b Unifying Receiver
12 bcdDevice 24.01
13 iManufacturer 1 Logitech
14 iProduct 2 USB Receiver
15 iSerial 0
16 bNumConfigurations 1
17 Configuration Descriptor:
18 bLength 9
19 bDescriptorType 2
20 wTotalLength 84
21 bNumInterfaces 3
22 bConfigurationValue 1
23 iConfiguration 4 RQR24.01_B0023
24 bmAttributes 0xa0
25 (Bus Powered)
26 Remote Wakeup
27 MaxPower 98mA
28 Interface Descriptor:
29 bLength 9
30 bDescriptorType 4
31 bInterfaceNumber 0
32 bAlternateSetting 0
33 bNumEndpoints 1
34 bInterfaceClass 3 Human Interface Device
35 bInterfaceSubClass 1 Boot Interface Subclass
36 bInterfaceProtocol 1 Keyboard
37 iInterface 0
38 HID Device Descriptor:
39 bLength 9
40 bDescriptorType 33
41 bcdHID 1.11
42 bCountryCode 0 Not supported
43 bNumDescriptors 1
44 bDescriptorType 34 Report
45 wDescriptorLength 59
46 Report Descriptor: (length is 59)
47 Item(Global): Usage Page, data= [ 0x01 ] 1
48 Generic Desktop Controls
49 Item(Local ): Usage, data= [ 0x06 ] 6
50 Keyboard
51 Item(Main ): Collection, data= [ 0x01 ] 1
52 Application
53 Item(Global): Usage Page, data= [ 0x07 ] 7
54 Keyboard
55 Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
56 Control Left
57 Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
58 GUI Right
59 Item(Global): Logical Minimum, data= [ 0x00 ] 0
60 Item(Global): Logical Maximum, data= [ 0x01 ] 1
61 Item(Global): Report Size, data= [ 0x01 ] 1
62 Item(Global): Report Count, data= [ 0x08 ] 8
63 Item(Main ): Input, data= [ 0x02 ] 2
64 Data Variable Absolute No_Wrap Linear
65 Preferred_State No_Null_Position Non_Volatile Bitfield
66 Item(Main ): Input, data= [ 0x03 ] 3
67 Constant Variable Absolute No_Wrap Linear
68 Preferred_State No_Null_Position Non_Volatile Bitfield
69 Item(Global): Report Count, data= [ 0x05 ] 5
70 Item(Global): Usage Page, data= [ 0x08 ] 8
71 LEDs
72 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
73 NumLock
74 Item(Local ): Usage Maximum, data= [ 0x05 ] 5
75 Kana
76 Item(Main ): Output, data= [ 0x02 ] 2
77 Data Variable Absolute No_Wrap Linear
78 Preferred_State No_Null_Position Non_Volatile Bitfield
79 Item(Global): Report Count, data= [ 0x01 ] 1
80 Item(Global): Report Size, data= [ 0x03 ] 3
81 Item(Main ): Output, data= [ 0x01 ] 1
82 Constant Array Absolute No_Wrap Linear
83 Preferred_State No_Null_Position Non_Volatile Bitfield
84 Item(Global): Report Count, data= [ 0x06 ] 6
85 Item(Global): Report Size, data= [ 0x08 ] 8
86 Item(Global): Logical Minimum, data= [ 0x00 ] 0
87 Item(Global): Logical Maximum, data= [ 0xa4 0x00 ] 164
88 Item(Global): Usage Page, data= [ 0x07 ] 7
89 Keyboard
90 Item(Local ): Usage Minimum, data= [ 0x00 ] 0
91 No Event
92 Item(Local ): Usage Maximum, data= [ 0xa4 0x00 ] 164
93 ExSel
94 Item(Main ): Input, data= [ 0x00 ] 0
95 Data Array Absolute No_Wrap Linear
96 Preferred_State No_Null_Position Non_Volatile Bitfield
97 Item(Main ): End Collection, data=none
98 Endpoint Descriptor:
99 bLength 7
100 bDescriptorType 5
101 bEndpointAddress 0x81 EP 1 IN
102 bmAttributes 3
103 Transfer Type Interrupt
104 Synch Type None
105 Usage Type Data
106 wMaxPacketSize 0x0008 1x 8 bytes
107 bInterval 8
108 Interface Descriptor:
109 bLength 9
110 bDescriptorType 4
111 bInterfaceNumber 1
112 bAlternateSetting 0
113 bNumEndpoints 1
114 bInterfaceClass 3 Human Interface Device
115 bInterfaceSubClass 1 Boot Interface Subclass
116 bInterfaceProtocol 2 Mouse
117 iInterface 0
118 HID Device Descriptor:
119 bLength 9
120 bDescriptorType 33
121 bcdHID 1.11
122 bCountryCode 0 Not supported
123 bNumDescriptors 1
124 bDescriptorType 34 Report
125 wDescriptorLength 148
126 Report Descriptor: (length is 148)
127 Item(Global): Usage Page, data= [ 0x01 ] 1
128 Generic Desktop Controls
129 Item(Local ): Usage, data= [ 0x02 ] 2
130 Mouse
131 Item(Main ): Collection, data= [ 0x01 ] 1
132 Application
133 Item(Global): Report ID, data= [ 0x02 ] 2
134 Item(Local ): Usage, data= [ 0x01 ] 1
135 Pointer
136 Item(Main ): Collection, data= [ 0x00 ] 0
137 Physical
138 Item(Global): Usage Page, data= [ 0x09 ] 9
139 Buttons
140 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
141 Button 1 (Primary)
142 Item(Local ): Usage Maximum, data= [ 0x10 ] 16
143 (null)
144 Item(Global): Logical Minimum, data= [ 0x00 ] 0
145 Item(Global): Logical Maximum, data= [ 0x01 ] 1
146 Item(Global): Report Count, data= [ 0x10 ] 16
147 Item(Global): Report Size, data= [ 0x01 ] 1
148 Item(Main ): Input, data= [ 0x02 ] 2
149 Data Variable Absolute No_Wrap Linear
150 Preferred_State No_Null_Position Non_Volatile Bitfield
151 Item(Global): Usage Page, data= [ 0x01 ] 1
152 Generic Desktop Controls
153 Item(Global): Logical Minimum, data= [ 0x01 0xf8 ] 63489
154 Item(Global): Logical Maximum, data= [ 0xff 0x07 ] 2047
155 Item(Global): Report Size, data= [ 0x0c ] 12
156 Item(Global): Report Count, data= [ 0x02 ] 2
157 Item(Local ): Usage, data= [ 0x30 ] 48
158 Direction-X
159 Item(Local ): Usage, data= [ 0x31 ] 49
160 Direction-Y
161 Item(Main ): Input, data= [ 0x06 ] 6
162 Data Variable Relative No_Wrap Linear
163 Preferred_State No_Null_Position Non_Volatile Bitfield
164 Item(Global): Logical Minimum, data= [ 0x81 ] 129
165 Item(Global): Logical Maximum, data= [ 0x7f ] 127
166 Item(Global): Report Size, data= [ 0x08 ] 8
167 Item(Global): Report Count, data= [ 0x01 ] 1
168 Item(Local ): Usage, data= [ 0x38 ] 56
169 Wheel
170 Item(Main ): Input, data= [ 0x06 ] 6
171 Data Variable Relative No_Wrap Linear
172 Preferred_State No_Null_Position Non_Volatile Bitfield
173 Item(Global): Usage Page, data= [ 0x0c ] 12
174 Consumer
175 Item(Local ): Usage, data= [ 0x38 0x02 ] 568
176 AC Pan
177 Item(Global): Report Count, data= [ 0x01 ] 1
178 Item(Main ): Input, data= [ 0x06 ] 6
179 Data Variable Relative No_Wrap Linear
180 Preferred_State No_Null_Position Non_Volatile Bitfield
181 Item(Main ): End Collection, data=none
182 Item(Main ): End Collection, data=none
183 Item(Global): Usage Page, data= [ 0x0c ] 12
184 Consumer
185 Item(Local ): Usage, data= [ 0x01 ] 1
186 Consumer Control
187 Item(Main ): Collection, data= [ 0x01 ] 1
188 Application
189 Item(Global): Report ID, data= [ 0x03 ] 3
190 Item(Global): Report Size, data= [ 0x10 ] 16
191 Item(Global): Report Count, data= [ 0x02 ] 2
192 Item(Global): Logical Minimum, data= [ 0x01 ] 1
193 Item(Global): Logical Maximum, data= [ 0x8c 0x02 ] 652
194 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
195 Consumer Control
196 Item(Local ): Usage Maximum, data= [ 0x8c 0x02 ] 652
197 (null)
198 Item(Main ): Input, data= [ 0x00 ] 0
199 Data Array Absolute No_Wrap Linear
200 Preferred_State No_Null_Position Non_Volatile Bitfield
201 Item(Main ): End Collection, data=none
202 Item(Global): Usage Page, data= [ 0x01 ] 1
203 Generic Desktop Controls
204 Item(Local ): Usage, data= [ 0x80 ] 128
205 System Control
206 Item(Main ): Collection, data= [ 0x01 ] 1
207 Application
208 Item(Global): Report ID, data= [ 0x04 ] 4
209 Item(Global): Report Size, data= [ 0x02 ] 2
210 Item(Global): Report Count, data= [ 0x01 ] 1
211 Item(Global): Logical Minimum, data= [ 0x01 ] 1
212 Item(Global): Logical Maximum, data= [ 0x03 ] 3
213 Item(Local ): Usage, data= [ 0x82 ] 130
214 System Sleep
215 Item(Local ): Usage, data= [ 0x81 ] 129
216 System Power Down
217 Item(Local ): Usage, data= [ 0x83 ] 131
218 System Wake Up
219 Item(Main ): Input, data= [ 0x60 ] 96
220 Data Array Absolute No_Wrap Linear
221 No_Preferred_State Null_State Non_Volatile Bitfield
222 Item(Global): Report Size, data= [ 0x06 ] 6
223 Item(Main ): Input, data= [ 0x03 ] 3
224 Constant Variable Absolute No_Wrap Linear
225 Preferred_State No_Null_Position Non_Volatile Bitfield
226 Item(Main ): End Collection, data=none
227 Item(Global): Usage Page, data= [ 0xbc 0xff ] 65468
228 (null)
229 Item(Local ): Usage, data= [ 0x88 ] 136
230 (null)
231 Item(Main ): Collection, data= [ 0x01 ] 1
232 Application
233 Item(Global): Report ID, data= [ 0x08 ] 8
234 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
235 (null)
236 Item(Local ): Usage Maximum, data= [ 0xff ] 255
237 (null)
238 Item(Global): Logical Minimum, data= [ 0x01 ] 1
239 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
240 Item(Global): Report Size, data= [ 0x08 ] 8
241 Item(Global): Report Count, data= [ 0x01 ] 1
242 Item(Main ): Input, data= [ 0x00 ] 0
243 Data Array Absolute No_Wrap Linear
244 Preferred_State No_Null_Position Non_Volatile Bitfield
245 Item(Main ): End Collection, data=none
246 Endpoint Descriptor:
247 bLength 7
248 bDescriptorType 5
249 bEndpointAddress 0x82 EP 2 IN
250 bmAttributes 3
251 Transfer Type Interrupt
252 Synch Type None
253 Usage Type Data
254 wMaxPacketSize 0x0008 1x 8 bytes
255 bInterval 2
256 Interface Descriptor:
257 bLength 9
258 bDescriptorType 4
259 bInterfaceNumber 2
260 bAlternateSetting 0
261 bNumEndpoints 1
262 bInterfaceClass 3 Human Interface Device
263 bInterfaceSubClass 0
264 bInterfaceProtocol 0
265 iInterface 0
266 HID Device Descriptor:
267 bLength 9
268 bDescriptorType 33
269 bcdHID 1.11
270 bCountryCode 0 Not supported
271 bNumDescriptors 1
272 bDescriptorType 34 Report
273 wDescriptorLength 98
274 Report Descriptor: (length is 98)
275 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
276 (null)
277 Item(Local ): Usage, data= [ 0x01 ] 1
278 (null)
279 Item(Main ): Collection, data= [ 0x01 ] 1
280 Application
281 Item(Global): Report ID, data= [ 0x10 ] 16
282 Item(Global): Report Size, data= [ 0x08 ] 8
283 Item(Global): Report Count, data= [ 0x06 ] 6
284 Item(Global): Logical Minimum, data= [ 0x00 ] 0
285 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
286 Item(Local ): Usage, data= [ 0x01 ] 1
287 (null)
288 Item(Main ): Input, data= [ 0x00 ] 0
289 Data Array Absolute No_Wrap Linear
290 Preferred_State No_Null_Position Non_Volatile Bitfield
291 Item(Local ): Usage, data= [ 0x01 ] 1
292 (null)
293 Item(Main ): Output, data= [ 0x00 ] 0
294 Data Array Absolute No_Wrap Linear
295 Preferred_State No_Null_Position Non_Volatile Bitfield
296 Item(Main ): End Collection, data=none
297 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
298 (null)
299 Item(Local ): Usage, data= [ 0x02 ] 2
300 (null)
301 Item(Main ): Collection, data= [ 0x01 ] 1
302 Application
303 Item(Global): Report ID, data= [ 0x11 ] 17
304 Item(Global): Report Size, data= [ 0x08 ] 8
305 Item(Global): Report Count, data= [ 0x13 ] 19
306 Item(Global): Logical Minimum, data= [ 0x00 ] 0
307 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
308 Item(Local ): Usage, data= [ 0x02 ] 2
309 (null)
310 Item(Main ): Input, data= [ 0x00 ] 0
311 Data Array Absolute No_Wrap Linear
312 Preferred_State No_Null_Position Non_Volatile Bitfield
313 Item(Local ): Usage, data= [ 0x02 ] 2
314 (null)
315 Item(Main ): Output, data= [ 0x00 ] 0
316 Data Array Absolute No_Wrap Linear
317 Preferred_State No_Null_Position Non_Volatile Bitfield
318 Item(Main ): End Collection, data=none
319 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
320 (null)
321 Item(Local ): Usage, data= [ 0x04 ] 4
322 (null)
323 Item(Main ): Collection, data= [ 0x01 ] 1
324 Application
325 Item(Global): Report ID, data= [ 0x20 ] 32
326 Item(Global): Report Size, data= [ 0x08 ] 8
327 Item(Global): Report Count, data= [ 0x0e ] 14
328 Item(Global): Logical Minimum, data= [ 0x00 ] 0
329 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
330 Item(Local ): Usage, data= [ 0x41 ] 65
331 (null)
332 Item(Main ): Input, data= [ 0x00 ] 0
333 Data Array Absolute No_Wrap Linear
334 Preferred_State No_Null_Position Non_Volatile Bitfield
335 Item(Local ): Usage, data= [ 0x41 ] 65
336 (null)
337 Item(Main ): Output, data= [ 0x00 ] 0
338 Data Array Absolute No_Wrap Linear
339 Preferred_State No_Null_Position Non_Volatile Bitfield
340 Item(Global): Report ID, data= [ 0x21 ] 33
341 Item(Global): Report Count, data= [ 0x1f ] 31
342 Item(Global): Logical Minimum, data= [ 0x00 ] 0
343 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
344 Item(Local ): Usage, data= [ 0x42 ] 66
345 (null)
346 Item(Main ): Input, data= [ 0x00 ] 0
347 Data Array Absolute No_Wrap Linear
348 Preferred_State No_Null_Position Non_Volatile Bitfield
349 Item(Local ): Usage, data= [ 0x42 ] 66
350 (null)
351 Item(Main ): Output, data= [ 0x00 ] 0
352 Data Array Absolute No_Wrap Linear
353 Preferred_State No_Null_Position Non_Volatile Bitfield
354 Item(Main ): End Collection, data=none
355 Endpoint Descriptor:
356 bLength 7
357 bDescriptorType 5
358 bEndpointAddress 0x83 EP 3 IN
359 bmAttributes 3
360 Transfer Type Interrupt
361 Synch Type None
362 Usage Type Data
363 wMaxPacketSize 0x0020 1x 32 bytes
364 bInterval 2
365 Device Status: 0x0000
366 (Bus Powered)
+0
-366
plugins/unifying/data/lsusb-U0008.txt less more
0 Bus 003 Device 032: ID 046d:c52b Logitech, Inc. Unifying Receiver
1 Device Descriptor:
2 bLength 18
3 bDescriptorType 1
4 bcdUSB 2.00
5 bDeviceClass 0
6 bDeviceSubClass 0
7 bDeviceProtocol 0
8 bMaxPacketSize0 32
9 idVendor 0x046d Logitech, Inc.
10 idProduct 0xc52b Unifying Receiver
11 bcdDevice 24.05
12 iManufacturer 1 Logitech
13 iProduct 2 USB Receiver
14 iSerial 0
15 bNumConfigurations 1
16 Configuration Descriptor:
17 bLength 9
18 bDescriptorType 2
19 wTotalLength 84
20 bNumInterfaces 3
21 bConfigurationValue 1
22 iConfiguration 4 RQR24.05_B0029
23 bmAttributes 0xa0
24 (Bus Powered)
25 Remote Wakeup
26 MaxPower 98mA
27 Interface Descriptor:
28 bLength 9
29 bDescriptorType 4
30 bInterfaceNumber 0
31 bAlternateSetting 0
32 bNumEndpoints 1
33 bInterfaceClass 3 Human Interface Device
34 bInterfaceSubClass 1 Boot Interface Subclass
35 bInterfaceProtocol 1 Keyboard
36 iInterface 0
37 HID Device Descriptor:
38 bLength 9
39 bDescriptorType 33
40 bcdHID 1.11
41 bCountryCode 0 Not supported
42 bNumDescriptors 1
43 bDescriptorType 34 Report
44 wDescriptorLength 59
45 Report Descriptor: (length is 59)
46 Item(Global): Usage Page, data= [ 0x01 ] 1
47 Generic Desktop Controls
48 Item(Local ): Usage, data= [ 0x06 ] 6
49 Keyboard
50 Item(Main ): Collection, data= [ 0x01 ] 1
51 Application
52 Item(Global): Usage Page, data= [ 0x07 ] 7
53 Keyboard
54 Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
55 Control Left
56 Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
57 GUI Right
58 Item(Global): Logical Minimum, data= [ 0x00 ] 0
59 Item(Global): Logical Maximum, data= [ 0x01 ] 1
60 Item(Global): Report Size, data= [ 0x01 ] 1
61 Item(Global): Report Count, data= [ 0x08 ] 8
62 Item(Main ): Input, data= [ 0x02 ] 2
63 Data Variable Absolute No_Wrap Linear
64 Preferred_State No_Null_Position Non_Volatile Bitfield
65 Item(Main ): Input, data= [ 0x03 ] 3
66 Constant Variable Absolute No_Wrap Linear
67 Preferred_State No_Null_Position Non_Volatile Bitfield
68 Item(Global): Report Count, data= [ 0x05 ] 5
69 Item(Global): Usage Page, data= [ 0x08 ] 8
70 LEDs
71 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
72 NumLock
73 Item(Local ): Usage Maximum, data= [ 0x05 ] 5
74 Kana
75 Item(Main ): Output, data= [ 0x02 ] 2
76 Data Variable Absolute No_Wrap Linear
77 Preferred_State No_Null_Position Non_Volatile Bitfield
78 Item(Global): Report Count, data= [ 0x01 ] 1
79 Item(Global): Report Size, data= [ 0x03 ] 3
80 Item(Main ): Output, data= [ 0x01 ] 1
81 Constant Array Absolute No_Wrap Linear
82 Preferred_State No_Null_Position Non_Volatile Bitfield
83 Item(Global): Report Count, data= [ 0x06 ] 6
84 Item(Global): Report Size, data= [ 0x08 ] 8
85 Item(Global): Logical Minimum, data= [ 0x00 ] 0
86 Item(Global): Logical Maximum, data= [ 0xa4 0x00 ] 164
87 Item(Global): Usage Page, data= [ 0x07 ] 7
88 Keyboard
89 Item(Local ): Usage Minimum, data= [ 0x00 ] 0
90 No Event
91 Item(Local ): Usage Maximum, data= [ 0xa4 0x00 ] 164
92 ExSel
93 Item(Main ): Input, data= [ 0x00 ] 0
94 Data Array Absolute No_Wrap Linear
95 Preferred_State No_Null_Position Non_Volatile Bitfield
96 Item(Main ): End Collection, data=none
97 Endpoint Descriptor:
98 bLength 7
99 bDescriptorType 5
100 bEndpointAddress 0x81 EP 1 IN
101 bmAttributes 3
102 Transfer Type Interrupt
103 Synch Type None
104 Usage Type Data
105 wMaxPacketSize 0x0008 1x 8 bytes
106 bInterval 8
107 Interface Descriptor:
108 bLength 9
109 bDescriptorType 4
110 bInterfaceNumber 1
111 bAlternateSetting 0
112 bNumEndpoints 1
113 bInterfaceClass 3 Human Interface Device
114 bInterfaceSubClass 1 Boot Interface Subclass
115 bInterfaceProtocol 2 Mouse
116 iInterface 0
117 HID Device Descriptor:
118 bLength 9
119 bDescriptorType 33
120 bcdHID 1.11
121 bCountryCode 0 Not supported
122 bNumDescriptors 1
123 bDescriptorType 34 Report
124 wDescriptorLength 148
125 Report Descriptor: (length is 148)
126 Item(Global): Usage Page, data= [ 0x01 ] 1
127 Generic Desktop Controls
128 Item(Local ): Usage, data= [ 0x02 ] 2
129 Mouse
130 Item(Main ): Collection, data= [ 0x01 ] 1
131 Application
132 Item(Global): Report ID, data= [ 0x02 ] 2
133 Item(Local ): Usage, data= [ 0x01 ] 1
134 Pointer
135 Item(Main ): Collection, data= [ 0x00 ] 0
136 Physical
137 Item(Global): Usage Page, data= [ 0x09 ] 9
138 Buttons
139 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
140 Button 1 (Primary)
141 Item(Local ): Usage Maximum, data= [ 0x10 ] 16
142 (null)
143 Item(Global): Logical Minimum, data= [ 0x00 ] 0
144 Item(Global): Logical Maximum, data= [ 0x01 ] 1
145 Item(Global): Report Count, data= [ 0x10 ] 16
146 Item(Global): Report Size, data= [ 0x01 ] 1
147 Item(Main ): Input, data= [ 0x02 ] 2
148 Data Variable Absolute No_Wrap Linear
149 Preferred_State No_Null_Position Non_Volatile Bitfield
150 Item(Global): Usage Page, data= [ 0x01 ] 1
151 Generic Desktop Controls
152 Item(Global): Logical Minimum, data= [ 0x01 0xf8 ] 63489
153 Item(Global): Logical Maximum, data= [ 0xff 0x07 ] 2047
154 Item(Global): Report Size, data= [ 0x0c ] 12
155 Item(Global): Report Count, data= [ 0x02 ] 2
156 Item(Local ): Usage, data= [ 0x30 ] 48
157 Direction-X
158 Item(Local ): Usage, data= [ 0x31 ] 49
159 Direction-Y
160 Item(Main ): Input, data= [ 0x06 ] 6
161 Data Variable Relative No_Wrap Linear
162 Preferred_State No_Null_Position Non_Volatile Bitfield
163 Item(Global): Logical Minimum, data= [ 0x81 ] 129
164 Item(Global): Logical Maximum, data= [ 0x7f ] 127
165 Item(Global): Report Size, data= [ 0x08 ] 8
166 Item(Global): Report Count, data= [ 0x01 ] 1
167 Item(Local ): Usage, data= [ 0x38 ] 56
168 Wheel
169 Item(Main ): Input, data= [ 0x06 ] 6
170 Data Variable Relative No_Wrap Linear
171 Preferred_State No_Null_Position Non_Volatile Bitfield
172 Item(Global): Usage Page, data= [ 0x0c ] 12
173 Consumer
174 Item(Local ): Usage, data= [ 0x38 0x02 ] 568
175 AC Pan
176 Item(Global): Report Count, data= [ 0x01 ] 1
177 Item(Main ): Input, data= [ 0x06 ] 6
178 Data Variable Relative No_Wrap Linear
179 Preferred_State No_Null_Position Non_Volatile Bitfield
180 Item(Main ): End Collection, data=none
181 Item(Main ): End Collection, data=none
182 Item(Global): Usage Page, data= [ 0x0c ] 12
183 Consumer
184 Item(Local ): Usage, data= [ 0x01 ] 1
185 Consumer Control
186 Item(Main ): Collection, data= [ 0x01 ] 1
187 Application
188 Item(Global): Report ID, data= [ 0x03 ] 3
189 Item(Global): Report Size, data= [ 0x10 ] 16
190 Item(Global): Report Count, data= [ 0x02 ] 2
191 Item(Global): Logical Minimum, data= [ 0x01 ] 1
192 Item(Global): Logical Maximum, data= [ 0x8c 0x02 ] 652
193 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
194 Consumer Control
195 Item(Local ): Usage Maximum, data= [ 0x8c 0x02 ] 652
196 (null)
197 Item(Main ): Input, data= [ 0x00 ] 0
198 Data Array Absolute No_Wrap Linear
199 Preferred_State No_Null_Position Non_Volatile Bitfield
200 Item(Main ): End Collection, data=none
201 Item(Global): Usage Page, data= [ 0x01 ] 1
202 Generic Desktop Controls
203 Item(Local ): Usage, data= [ 0x80 ] 128
204 System Control
205 Item(Main ): Collection, data= [ 0x01 ] 1
206 Application
207 Item(Global): Report ID, data= [ 0x04 ] 4
208 Item(Global): Report Size, data= [ 0x02 ] 2
209 Item(Global): Report Count, data= [ 0x01 ] 1
210 Item(Global): Logical Minimum, data= [ 0x01 ] 1
211 Item(Global): Logical Maximum, data= [ 0x03 ] 3
212 Item(Local ): Usage, data= [ 0x82 ] 130
213 System Sleep
214 Item(Local ): Usage, data= [ 0x81 ] 129
215 System Power Down
216 Item(Local ): Usage, data= [ 0x83 ] 131
217 System Wake Up
218 Item(Main ): Input, data= [ 0x60 ] 96
219 Data Array Absolute No_Wrap Linear
220 No_Preferred_State Null_State Non_Volatile Bitfield
221 Item(Global): Report Size, data= [ 0x06 ] 6
222 Item(Main ): Input, data= [ 0x03 ] 3
223 Constant Variable Absolute No_Wrap Linear
224 Preferred_State No_Null_Position Non_Volatile Bitfield
225 Item(Main ): End Collection, data=none
226 Item(Global): Usage Page, data= [ 0xbc 0xff ] 65468
227 (null)
228 Item(Local ): Usage, data= [ 0x88 ] 136
229 (null)
230 Item(Main ): Collection, data= [ 0x01 ] 1
231 Application
232 Item(Global): Report ID, data= [ 0x08 ] 8
233 Item(Local ): Usage Minimum, data= [ 0x01 ] 1
234 (null)
235 Item(Local ): Usage Maximum, data= [ 0xff ] 255
236 (null)
237 Item(Global): Logical Minimum, data= [ 0x01 ] 1
238 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
239 Item(Global): Report Size, data= [ 0x08 ] 8
240 Item(Global): Report Count, data= [ 0x01 ] 1
241 Item(Main ): Input, data= [ 0x00 ] 0
242 Data Array Absolute No_Wrap Linear
243 Preferred_State No_Null_Position Non_Volatile Bitfield
244 Item(Main ): End Collection, data=none
245 Endpoint Descriptor:
246 bLength 7
247 bDescriptorType 5
248 bEndpointAddress 0x82 EP 2 IN
249 bmAttributes 3
250 Transfer Type Interrupt
251 Synch Type None
252 Usage Type Data
253 wMaxPacketSize 0x0008 1x 8 bytes
254 bInterval 2
255 Interface Descriptor:
256 bLength 9
257 bDescriptorType 4
258 bInterfaceNumber 2
259 bAlternateSetting 0
260 bNumEndpoints 1
261 bInterfaceClass 3 Human Interface Device
262 bInterfaceSubClass 0
263 bInterfaceProtocol 0
264 iInterface 0
265 HID Device Descriptor:
266 bLength 9
267 bDescriptorType 33
268 bcdHID 1.11
269 bCountryCode 0 Not supported
270 bNumDescriptors 1
271 bDescriptorType 34 Report
272 wDescriptorLength 98
273 Report Descriptor: (length is 98)
274 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
275 (null)
276 Item(Local ): Usage, data= [ 0x01 ] 1
277 (null)
278 Item(Main ): Collection, data= [ 0x01 ] 1
279 Application
280 Item(Global): Report ID, data= [ 0x10 ] 16
281 Item(Global): Report Size, data= [ 0x08 ] 8
282 Item(Global): Report Count, data= [ 0x06 ] 6
283 Item(Global): Logical Minimum, data= [ 0x00 ] 0
284 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
285 Item(Local ): Usage, data= [ 0x01 ] 1
286 (null)
287 Item(Main ): Input, data= [ 0x00 ] 0
288 Data Array Absolute No_Wrap Linear
289 Preferred_State No_Null_Position Non_Volatile Bitfield
290 Item(Local ): Usage, data= [ 0x01 ] 1
291 (null)
292 Item(Main ): Output, data= [ 0x00 ] 0
293 Data Array Absolute No_Wrap Linear
294 Preferred_State No_Null_Position Non_Volatile Bitfield
295 Item(Main ): End Collection, data=none
296 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
297 (null)
298 Item(Local ): Usage, data= [ 0x02 ] 2
299 (null)
300 Item(Main ): Collection, data= [ 0x01 ] 1
301 Application
302 Item(Global): Report ID, data= [ 0x11 ] 17
303 Item(Global): Report Size, data= [ 0x08 ] 8
304 Item(Global): Report Count, data= [ 0x13 ] 19
305 Item(Global): Logical Minimum, data= [ 0x00 ] 0
306 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
307 Item(Local ): Usage, data= [ 0x02 ] 2
308 (null)
309 Item(Main ): Input, data= [ 0x00 ] 0
310 Data Array Absolute No_Wrap Linear
311 Preferred_State No_Null_Position Non_Volatile Bitfield
312 Item(Local ): Usage, data= [ 0x02 ] 2
313 (null)
314 Item(Main ): Output, data= [ 0x00 ] 0
315 Data Array Absolute No_Wrap Linear
316 Preferred_State No_Null_Position Non_Volatile Bitfield
317 Item(Main ): End Collection, data=none
318 Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
319 (null)
320 Item(Local ): Usage, data= [ 0x04 ] 4
321 (null)
322 Item(Main ): Collection, data= [ 0x01 ] 1
323 Application
324 Item(Global): Report ID, data= [ 0x20 ] 32
325 Item(Global): Report Size, data= [ 0x08 ] 8
326 Item(Global): Report Count, data= [ 0x0e ] 14
327 Item(Global): Logical Minimum, data= [ 0x00 ] 0
328 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
329 Item(Local ): Usage, data= [ 0x41 ] 65
330 (null)
331 Item(Main ): Input, data= [ 0x00 ] 0
332 Data Array Absolute No_Wrap Linear
333 Preferred_State No_Null_Position Non_Volatile Bitfield
334 Item(Local ): Usage, data= [ 0x41 ] 65
335 (null)
336 Item(Main ): Output, data= [ 0x00 ] 0
337 Data Array Absolute No_Wrap Linear
338 Preferred_State No_Null_Position Non_Volatile Bitfield
339 Item(Global): Report ID, data= [ 0x21 ] 33
340 Item(Global): Report Count, data= [ 0x1f ] 31
341 Item(Global): Logical Minimum, data= [ 0x00 ] 0
342 Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
343 Item(Local ): Usage, data= [ 0x42 ] 66
344 (null)
345 Item(Main ): Input, data= [ 0x00 ] 0
346 Data Array Absolute No_Wrap Linear
347 Preferred_State No_Null_Position Non_Volatile Bitfield
348 Item(Local ): Usage, data= [ 0x42 ] 66
349 (null)
350 Item(Main ): Output, data= [ 0x00 ] 0
351 Data Array Absolute No_Wrap Linear
352 Preferred_State No_Null_Position Non_Volatile Bitfield
353 Item(Main ): End Collection, data=none
354 Endpoint Descriptor:
355 bLength 7
356 bDescriptorType 5
357 bEndpointAddress 0x83 EP 3 IN
358 bmAttributes 3
359 Transfer Type Interrupt
360 Synch Type None
361 Usage Type Data
362 wMaxPacketSize 0x0020 1x 32 bytes
363 bInterval 2
364 Device Status: 0x0000
365 (Bus Powered)
+0
-46
plugins/unifying/fu-plugin-unifying.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <fwupd.h>
9
10 #include "fu-plugin-vfuncs.h"
11
12 #include "fu-unifying-bootloader-nordic.h"
13 #include "fu-unifying-bootloader-texas.h"
14 #include "fu-unifying-common.h"
15 #include "fu-unifying-peripheral.h"
16 #include "fu-unifying-runtime.h"
17
18 gboolean
19 fu_plugin_startup (FuPlugin *plugin, GError **error)
20 {
21 /* check the kernel has CONFIG_HIDRAW */
22 if (!g_file_test ("/sys/class/hidraw", G_FILE_TEST_IS_DIR)) {
23 g_set_error_literal (error,
24 FWUPD_ERROR,
25 FWUPD_ERROR_NOT_SUPPORTED,
26 "no kernel support for CONFIG_HIDRAW");
27 return FALSE;
28 }
29 return TRUE;
30 }
31
32 void
33 fu_plugin_init (FuPlugin *plugin)
34 {
35 fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
36 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying");
37 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned");
38 fu_plugin_add_udev_subsystem (plugin, "hidraw");
39
40 /* register the custom types */
41 g_type_ensure (FU_TYPE_UNIFYING_BOOTLOADER_NORDIC);
42 g_type_ensure (FU_TYPE_UNIFYING_BOOTLOADER_TEXAS);
43 g_type_ensure (FU_TYPE_UNIFYING_PERIPHERAL);
44 g_type_ensure (FU_TYPE_UNIFYING_RUNTIME);
45 }
+0
-286
plugins/unifying/fu-unifying-bootloader-nordic.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-unifying-common.h"
11 #include "fu-unifying-bootloader-nordic.h"
12
13 struct _FuUnifyingBootloaderNordic
14 {
15 FuUnifyingBootloader parent_instance;
16 };
17
18 G_DEFINE_TYPE (FuUnifyingBootloaderNordic, fu_unifying_bootloader_nordic, FU_TYPE_UNIFYING_BOOTLOADER)
19
20 static gchar *
21 fu_unifying_bootloader_nordic_get_hw_platform_id (FuUnifyingBootloader *self, GError **error)
22 {
23 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
24 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_HW_PLATFORM_ID;
25 if (!fu_unifying_bootloader_request (self, req, error)) {
26 g_prefix_error (error, "failed to get HW ID: ");
27 return NULL;
28 }
29 return g_strndup ((const gchar *) req->data, req->len);
30 }
31
32 static gchar *
33 fu_unifying_bootloader_nordic_get_fw_version (FuUnifyingBootloader *self, GError **error)
34 {
35 guint16 micro;
36
37 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
38 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_FW_VERSION;
39 if (!fu_unifying_bootloader_request (self, req, error)) {
40 g_prefix_error (error, "failed to get firmware version: ");
41 return NULL;
42 }
43
44 /* RRRxx.yy_Bzzzz
45 * 012345678901234*/
46 micro = (guint16) fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 10) << 8;
47 micro += fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 12);
48 return fu_unifying_format_version ("RQR",
49 fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 3),
50 fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 6),
51 micro);
52 }
53
54 static gboolean
55 fu_unifying_bootloader_nordic_setup (FuUnifyingBootloader *self, GError **error)
56 {
57 g_autofree gchar *hw_platform_id = NULL;
58 g_autofree gchar *version_fw = NULL;
59 g_autoptr(GError) error_local = NULL;
60
61 /* get MCU */
62 hw_platform_id = fu_unifying_bootloader_nordic_get_hw_platform_id (self, error);
63 if (hw_platform_id == NULL)
64 return FALSE;
65 g_debug ("hw-platform-id=%s", hw_platform_id);
66
67 /* get firmware version, which is not fatal */
68 version_fw = fu_unifying_bootloader_nordic_get_fw_version (self, &error_local);
69 if (version_fw == NULL) {
70 g_warning ("failed to get firmware version: %s",
71 error_local->message);
72 fu_device_set_version (FU_DEVICE (self), "RQR12.00_B0000",
73 FWUPD_VERSION_FORMAT_PLAIN);
74 } else {
75 fu_device_set_version (FU_DEVICE (self), version_fw,
76 FWUPD_VERSION_FORMAT_PLAIN);
77 }
78
79 return TRUE;
80 }
81
82 static gboolean
83 fu_unifying_bootloader_nordic_write_signature (FuUnifyingBootloader *self,
84 guint16 addr, guint8 len, const guint8 *data,
85 GError **error)
86 {
87 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new();
88 req->cmd = 0xC0;
89 req->addr = addr;
90 req->len = len;
91 memcpy (req->data, data, req->len);
92 if (!fu_unifying_bootloader_request (self, req, error)) {
93 g_prefix_error (error, "failed to write sig @0x%02x: ", addr);
94 return FALSE;
95 }
96 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) {
97 g_set_error (error,
98 G_IO_ERROR,
99 G_IO_ERROR_FAILED,
100 "failed to write @%04x: signature is too big",
101 addr);
102 return FALSE;
103 }
104 return TRUE;
105 }
106
107 static gboolean
108 fu_unifying_bootloader_nordic_write (FuUnifyingBootloader *self,
109 guint16 addr, guint8 len, const guint8 *data,
110 GError **error)
111 {
112 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
113 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE;
114 req->addr = addr;
115 req->len = len;
116 if (req->len > 28) {
117 g_set_error (error,
118 G_IO_ERROR,
119 G_IO_ERROR_FAILED,
120 "failed to write @%04x: data length too large %02x",
121 addr, req->len);
122 return FALSE;
123 }
124 memcpy (req->data, data, req->len);
125 if (!fu_unifying_bootloader_request (self, req, error)) {
126 g_prefix_error (error, "failed to transfer fw @0x%02x: ", addr);
127 return FALSE;
128 }
129 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_ADDR) {
130 g_set_error (error,
131 G_IO_ERROR,
132 G_IO_ERROR_FAILED,
133 "failed to write @%04x: invalid address",
134 addr);
135 return FALSE;
136 }
137 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_VERIFY_FAIL) {
138 g_set_error (error,
139 G_IO_ERROR,
140 G_IO_ERROR_FAILED,
141 "failed to write @%04x: failed to verify flash content",
142 addr);
143 return FALSE;
144 }
145 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_NONZERO_START) {
146 g_debug ("wrote %d bytes at address %04x, value %02x", req->len,
147 req->addr, req->data[0]);
148 g_set_error (error,
149 G_IO_ERROR,
150 G_IO_ERROR_FAILED,
151 "failed to write @%04x: only 1 byte write of 0xff supported",
152 addr);
153 return FALSE;
154 }
155 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_CRC) {
156 g_set_error (error,
157 G_IO_ERROR,
158 G_IO_ERROR_FAILED,
159 "failed to write @%04x: invalid CRC",
160 addr);
161 return FALSE;
162 }
163 return TRUE;
164 }
165
166 static gboolean
167 fu_unifying_bootloader_nordic_erase (FuUnifyingBootloader *self, guint16 addr, GError **error)
168 {
169 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
170 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE;
171 req->addr = addr;
172 req->len = 0x01;
173 if (!fu_unifying_bootloader_request (self, req, error)) {
174 g_prefix_error (error, "failed to erase fw @0x%02x: ", addr);
175 return FALSE;
176 }
177 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR) {
178 g_set_error (error,
179 G_IO_ERROR,
180 G_IO_ERROR_FAILED,
181 "failed to erase @%04x: invalid page",
182 addr);
183 return FALSE;
184 }
185 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START) {
186 g_set_error (error,
187 G_IO_ERROR,
188 G_IO_ERROR_FAILED,
189 "failed to erase @%04x: byte 0x00 is not 0xff",
190 addr);
191 return FALSE;
192 }
193 return TRUE;
194 }
195
196 static gboolean
197 fu_unifying_bootloader_nordic_write_firmware (FuDevice *device,
198 FuFirmware *firmware,
199 FwupdInstallFlags flags,
200 GError **error)
201 {
202 FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
203 const FuUnifyingBootloaderRequest *payload;
204 guint16 addr;
205 g_autoptr(GBytes) fw = NULL;
206 g_autoptr(GPtrArray) reqs = NULL;
207
208 /* get default image */
209 fw = fu_firmware_get_image_default_bytes (firmware, error);
210 if (fw == NULL)
211 return FALSE;
212
213 /* erase firmware pages up to the bootloader */
214 fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
215 for (addr = fu_unifying_bootloader_get_addr_lo (self);
216 addr < fu_unifying_bootloader_get_addr_hi (self);
217 addr += fu_unifying_bootloader_get_blocksize (self)) {
218 if (!fu_unifying_bootloader_nordic_erase (self, addr, error))
219 return FALSE;
220 }
221
222 /* transfer payload */
223 reqs = fu_unifying_bootloader_parse_requests (self, fw, error);
224 if (reqs == NULL)
225 return FALSE;
226 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
227 for (guint i = 1; i < reqs->len; i++) {
228 gboolean res;
229 payload = g_ptr_array_index (reqs, i);
230
231 if (payload->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
232 res = fu_unifying_bootloader_nordic_write_signature (self,
233 payload->addr,
234 payload->len,
235 payload->data,
236 error);
237 } else {
238 res = fu_unifying_bootloader_nordic_write (self,
239 payload->addr,
240 payload->len,
241 payload->data,
242 error);
243 }
244
245 if (!res)
246 return FALSE;
247 fu_device_set_progress_full (device, i * 32, reqs->len * 32);
248 }
249
250 /* send the first managed packet last, excluding the reset vector */
251 payload = g_ptr_array_index (reqs, 0);
252 if (!fu_unifying_bootloader_nordic_write (self,
253 payload->addr + 1,
254 payload->len - 1,
255 payload->data + 1,
256 error))
257 return FALSE;
258
259 if (!fu_unifying_bootloader_nordic_write (self,
260 0x0000,
261 0x01,
262 payload->data,
263 error))
264 return FALSE;
265
266 /* mark as complete */
267 fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32);
268
269 /* success! */
270 return TRUE;
271 }
272
273 static void
274 fu_unifying_bootloader_nordic_class_init (FuUnifyingBootloaderNordicClass *klass)
275 {
276 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
277 FuUnifyingBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass);
278 klass_device->write_firmware = fu_unifying_bootloader_nordic_write_firmware;
279 klass_device_bootloader->setup = fu_unifying_bootloader_nordic_setup;
280 }
281
282 static void
283 fu_unifying_bootloader_nordic_init (FuUnifyingBootloaderNordic *self)
284 {
285 }
+0
-12
plugins/unifying/fu-unifying-bootloader-nordic.h less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-unifying-bootloader.h"
9
10 #define FU_TYPE_UNIFYING_BOOTLOADER_NORDIC (fu_unifying_bootloader_nordic_get_type ())
11 G_DECLARE_FINAL_TYPE (FuUnifyingBootloaderNordic, fu_unifying_bootloader_nordic, FU, UNIFYING_BOOTLOADER_NORDIC, FuUnifyingBootloader)
+0
-241
plugins/unifying/fu-unifying-bootloader-texas.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-unifying-common.h"
11 #include "fu-unifying-bootloader-texas.h"
12
13 struct _FuUnifyingBootloaderTexas
14 {
15 FuUnifyingBootloader parent_instance;
16 };
17
18 G_DEFINE_TYPE (FuUnifyingBootloaderTexas, fu_unifying_bootloader_texas, FU_TYPE_UNIFYING_BOOTLOADER)
19
20 static gboolean
21 fu_unifying_bootloader_texas_erase_all (FuUnifyingBootloader *self, GError **error)
22 {
23 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
24 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
25 req->len = 0x01; /* magic number */
26 req->data[0] = 0x00; /* magic number */
27 if (!fu_unifying_bootloader_request (self, req, error)) {
28 g_prefix_error (error, "failed to erase all pages: ");
29 return FALSE;
30 }
31 return TRUE;
32 }
33
34 static gboolean
35 fu_unifying_bootloader_texas_compute_and_test_crc (FuUnifyingBootloader *self, GError **error)
36 {
37 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
38 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
39 req->len = 0x01; /* magic number */
40 req->data[0] = 0x03; /* magic number */
41 if (!fu_unifying_bootloader_request (self, req, error)) {
42 g_prefix_error (error, "failed to compute and test CRC: ");
43 return FALSE;
44 }
45 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC) {
46 g_set_error_literal (error,
47 G_IO_ERROR,
48 G_IO_ERROR_FAILED,
49 "CRC is incorrect");
50 return FALSE;
51 }
52 return TRUE;
53 }
54
55 static gboolean
56 fu_unifying_bootloader_texas_flash_ram_buffer (FuUnifyingBootloader *self, guint16 addr, GError **error)
57 {
58 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
59 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
60 req->addr = addr;
61 req->len = 0x01; /* magic number */
62 req->data[0] = 0x01; /* magic number */
63 if (!fu_unifying_bootloader_request (self, req, error)) {
64 g_prefix_error (error, "failed to flash ram buffer @%04x: ", addr);
65 return FALSE;
66 }
67 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR) {
68 g_set_error (error,
69 G_IO_ERROR,
70 G_IO_ERROR_FAILED,
71 "failed to flash ram buffer @%04x: invalid flash page",
72 addr);
73 return FALSE;
74 }
75 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID) {
76 g_set_error (error,
77 G_IO_ERROR,
78 G_IO_ERROR_FAILED,
79 "failed to flash ram buffer @%04x: invalid App JMP vector",
80 addr);
81 return FALSE;
82 }
83 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER) {
84 g_set_error (error,
85 G_IO_ERROR,
86 G_IO_ERROR_FAILED,
87 "failed to flash ram buffer @%04x: page flashed before page 0",
88 addr);
89 return FALSE;
90 }
91 return TRUE;
92 }
93
94 static gboolean
95 fu_unifying_bootloader_texas_clear_ram_buffer (FuUnifyingBootloader *self, GError **error)
96 {
97 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
98 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM;
99 req->addr = 0x0000;
100 req->len = 0x01; /* magic number */
101 req->data[0] = 0x02; /* magic number */
102 if (!fu_unifying_bootloader_request (self, req, error)) {
103 g_prefix_error (error, "failed to clear ram buffer @%04x: ", req->addr);
104 return FALSE;
105 }
106 return TRUE;
107 }
108
109 static gboolean
110 fu_unifying_bootloader_texas_write_firmware (FuDevice *device,
111 FuFirmware *firmware,
112 FwupdInstallFlags flags,
113 GError **error)
114 {
115 FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
116 const FuUnifyingBootloaderRequest *payload;
117 g_autoptr(GBytes) fw = NULL;
118 g_autoptr(GPtrArray) reqs = NULL;
119 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
120
121 /* get default image */
122 fw = fu_firmware_get_image_default_bytes (firmware, error);
123 if (fw == NULL)
124 return FALSE;
125
126 /* transfer payload */
127 reqs = fu_unifying_bootloader_parse_requests (self, fw, error);
128 if (reqs == NULL)
129 return FALSE;
130
131 /* erase all flash pages */
132 fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
133 if (!fu_unifying_bootloader_texas_erase_all (self, error))
134 return FALSE;
135
136 /* set existing RAM buffer to 0xff's */
137 if (!fu_unifying_bootloader_texas_clear_ram_buffer (self, error))
138 return FALSE;
139
140 /* write to RAM buffer */
141 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
142 for (guint i = 0; i < reqs->len; i++) {
143 payload = g_ptr_array_index (reqs, i);
144
145 /* check size */
146 if (payload->len != 16) {
147 g_set_error (error,
148 G_IO_ERROR,
149 G_IO_ERROR_FAILED,
150 "payload size invalid @%04x: got 0x%02x",
151 payload->addr, payload->len);
152 return FALSE;
153 }
154
155 /* build packet */
156 req->cmd = payload->cmd;
157
158 /* signature addresses do not need to fit inside 128 bytes */
159 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE)
160 req->addr = payload->addr;
161 else
162 req->addr = payload->addr % 0x80;
163
164 req->len = payload->len;
165 memcpy (req->data, payload->data, payload->len);
166 if (!fu_unifying_bootloader_request (self, req, error)) {
167 g_prefix_error (error,
168 "failed to write ram buffer @0x%02x: ",
169 req->addr);
170 return FALSE;
171 }
172 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) {
173 g_set_error (error,
174 G_IO_ERROR,
175 G_IO_ERROR_FAILED,
176 "failed to write ram buffer @%04x: invalid location",
177 req->addr);
178 return FALSE;
179 }
180 if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW) {
181 g_set_error (error,
182 G_IO_ERROR,
183 G_IO_ERROR_FAILED,
184 "failed to write ram buffer @%04x: invalid size 0x%02x",
185 req->addr, req->len);
186 return FALSE;
187 }
188
189 /* flush RAM buffer to EEPROM */
190 if ((payload->addr + 0x10) % 0x80 == 0 &&
191 req->cmd != FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
192 guint16 addr_start = payload->addr - (7 * 0x10);
193 g_debug ("addr flush @ 0x%04x for 0x%04x",
194 payload->addr, addr_start);
195 if (!fu_unifying_bootloader_texas_flash_ram_buffer (self,
196 addr_start,
197 error)) {
198 g_prefix_error (error,
199 "failed to flash ram buffer @0x%04x: ",
200 addr_start);
201 return FALSE;
202 }
203 }
204
205 /* update progress */
206 fu_device_set_progress_full (device, i * 32, reqs->len * 32);
207 }
208
209 /* check CRC */
210 if (!fu_unifying_bootloader_texas_compute_and_test_crc (self, error))
211 return FALSE;
212
213 /* mark as complete */
214 fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32);
215
216 /* success! */
217 return TRUE;
218 }
219
220 static gboolean
221 fu_unifying_bootloader_texas_setup (FuUnifyingBootloader *self, GError **error)
222 {
223 fu_device_set_version (FU_DEVICE (self), "RQR24.00_B0000",
224 FWUPD_VERSION_FORMAT_PLAIN);
225 return TRUE;
226 }
227
228 static void
229 fu_unifying_bootloader_texas_class_init (FuUnifyingBootloaderTexasClass *klass)
230 {
231 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
232 FuUnifyingBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass);
233 klass_device->write_firmware = fu_unifying_bootloader_texas_write_firmware;
234 klass_device_bootloader->setup = fu_unifying_bootloader_texas_setup;
235 }
236
237 static void
238 fu_unifying_bootloader_texas_init (FuUnifyingBootloaderTexas *self)
239 {
240 }
+0
-12
plugins/unifying/fu-unifying-bootloader-texas.h less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-unifying-bootloader.h"
9
10 #define FU_TYPE_UNIFYING_BOOTLOADER_TEXAS (fu_unifying_bootloader_texas_get_type ())
11 G_DECLARE_FINAL_TYPE (FuUnifyingBootloaderTexas, fu_unifying_bootloader_texas, FU, UNIFYING_BOOTLOADER_TEXAS, FuUnifyingBootloader)
+0
-464
plugins/unifying/fu-unifying-bootloader.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-firmware-common.h"
11 #include "fu-unifying-common.h"
12 #include "fu-unifying-bootloader.h"
13 #include "fu-unifying-hidpp.h"
14
15 typedef struct
16 {
17 guint16 flash_addr_lo;
18 guint16 flash_addr_hi;
19 guint16 flash_blocksize;
20 } FuUnifyingBootloaderPrivate;
21
22 #define FU_UNIFYING_DEVICE_EP1 0x81
23 #define FU_UNIFYING_DEVICE_EP3 0x83
24
25 G_DEFINE_TYPE_WITH_PRIVATE (FuUnifyingBootloader, fu_unifying_bootloader, FU_TYPE_USB_DEVICE)
26
27 #define GET_PRIVATE(o) (fu_unifying_bootloader_get_instance_private (o))
28
29 static void
30 fu_unifying_bootloader_to_string (FuDevice *device, guint idt, GString *str)
31 {
32 FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
33 FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self);
34 fu_common_string_append_kx (str, idt, "FlashAddrHigh", priv->flash_addr_hi);
35 fu_common_string_append_kx (str, idt, "FlashAddrLow", priv->flash_addr_lo);
36 fu_common_string_append_kx (str, idt, "FlashBlockSize", priv->flash_blocksize);
37 }
38
39 FuUnifyingBootloaderRequest *
40 fu_unifying_bootloader_request_new (void)
41 {
42 FuUnifyingBootloaderRequest *req = g_new0 (FuUnifyingBootloaderRequest, 1);
43 return req;
44 }
45
46 GPtrArray *
47 fu_unifying_bootloader_parse_requests (FuUnifyingBootloader *self, GBytes *fw, GError **error)
48 {
49 const gchar *tmp;
50 g_auto(GStrv) lines = NULL;
51 g_autoptr(GPtrArray) reqs = NULL;
52 guint32 last_addr = 0;
53
54 reqs = g_ptr_array_new_with_free_func (g_free);
55 tmp = g_bytes_get_data (fw, NULL);
56 lines = g_strsplit_set (tmp, "\n\r", -1);
57 for (guint i = 0; lines[i] != NULL; i++) {
58 g_autoptr(FuUnifyingBootloaderRequest) payload = NULL;
59 guint8 rec_type = 0x00;
60 guint16 offset = 0x0000;
61 gboolean exit = FALSE;
62
63 /* skip empty lines */
64 tmp = lines[i];
65 if (strlen (tmp) < 5)
66 continue;
67
68 payload = fu_unifying_bootloader_request_new ();
69 payload->len = fu_unifying_buffer_read_uint8 (tmp + 0x01);
70 if (payload->len > 28) {
71 g_set_error (error,
72 G_IO_ERROR,
73 G_IO_ERROR_INVALID_DATA,
74 "firmware data invalid: too large %u bytes",
75 payload->len);
76 return NULL;
77 }
78 payload->addr = fu_firmware_strparse_uint16 (tmp + 0x03);
79 payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER;
80
81 rec_type = fu_unifying_buffer_read_uint8 (tmp + 0x07);
82
83 switch (rec_type) {
84 case 0x00: /* data */
85 break;
86 case 0x01: /* EOF */
87 exit = TRUE;
88 break;
89 case 0x03: /* start segment address */
90 /* this is used to specify the start address,
91 it is doesn't mater in this context so we can
92 safely ignore it */
93 continue;
94 case 0x04: /* extended linear address */
95 offset = fu_firmware_strparse_uint16 (tmp + 0x09);
96 if (offset != 0x0000) {
97 g_set_error (error,
98 G_IO_ERROR,
99 G_IO_ERROR_INVALID_DATA,
100 "extended linear addresses with offset different from 0 are not supported");
101 return NULL;
102 }
103 continue;
104 case 0x05: /* start linear address */
105 /* this is used to specify the start address,
106 it is doesn't mater in this context so we can
107 safely ignore it */
108 continue;
109 case 0xFD: /* custom - vendor */
110 /* record type of 0xFD indicates signature data */
111 payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE;
112 break;
113 default:
114 g_set_error (error,
115 G_IO_ERROR,
116 G_IO_ERROR_INVALID_DATA,
117 "intel hex file record type %02x not supported",
118 rec_type);
119 return NULL;
120 }
121
122 if (exit)
123 break;
124
125 /* read the data, but skip the checksum byte */
126 for (guint j = 0; j < payload->len; j++) {
127 const gchar *ptr = tmp + 0x09 + (j * 2);
128 if (ptr[0] == '\0') {
129 g_set_error (error,
130 G_IO_ERROR,
131 G_IO_ERROR_INVALID_DATA,
132 "firmware data invalid: expected %u bytes",
133 payload->len);
134 return NULL;
135 }
136 payload->data[j] = fu_unifying_buffer_read_uint8 (ptr);
137 }
138
139 /* no need to bound check signature addresses */
140 if (payload->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) {
141 g_ptr_array_add (reqs, g_steal_pointer (&payload));
142 continue;
143 }
144
145 /* skip the bootloader */
146 if (payload->addr > fu_unifying_bootloader_get_addr_hi (self)) {
147 g_debug ("skipping write @ %04x", payload->addr);
148 continue;
149 }
150
151 /* skip the header */
152 if (payload->addr < fu_unifying_bootloader_get_addr_lo (self)) {
153 g_debug ("skipping write @ %04x", payload->addr);
154 continue;
155 }
156
157 /* make sure firmware addresses only go up */
158 if (payload->addr < last_addr) {
159 g_debug ("skipping write @ %04x", payload->addr);
160 continue;
161 }
162 last_addr = payload->addr;
163
164 /* pending */
165 g_ptr_array_add (reqs, g_steal_pointer (&payload));
166 }
167 if (reqs->len == 0) {
168 g_set_error_literal (error,
169 G_IO_ERROR,
170 G_IO_ERROR_INVALID_DATA,
171 "firmware data invalid: no payloads found");
172 return NULL;
173 }
174 return g_steal_pointer (&reqs);
175 }
176
177 guint16
178 fu_unifying_bootloader_get_addr_lo (FuUnifyingBootloader *self)
179 {
180 FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self);
181 g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000);
182 return priv->flash_addr_lo;
183 }
184
185 guint16
186 fu_unifying_bootloader_get_addr_hi (FuUnifyingBootloader *self)
187 {
188 FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self);
189 g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000);
190 return priv->flash_addr_hi;
191 }
192
193 guint16
194 fu_unifying_bootloader_get_blocksize (FuUnifyingBootloader *self)
195 {
196 FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self);
197 g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000);
198 return priv->flash_blocksize;
199 }
200
201 static gboolean
202 fu_unifying_bootloader_attach (FuDevice *device, GError **error)
203 {
204 FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
205 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
206 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_REBOOT;
207 if (!fu_unifying_bootloader_request (self, req, error)) {
208 g_prefix_error (error, "failed to attach back to runtime: ");
209 return FALSE;
210 }
211 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
212 return TRUE;
213 }
214
215 static gboolean
216 fu_unifying_bootloader_set_bl_version (FuUnifyingBootloader *self, GError **error)
217 {
218 guint16 build;
219 g_autofree gchar *version = NULL;
220 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
221
222 /* call into hardware */
223 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_BL_VERSION;
224 if (!fu_unifying_bootloader_request (self, req, error)) {
225 g_prefix_error (error, "failed to get firmware version: ");
226 return FALSE;
227 }
228
229 /* BOTxx.yy_Bzzzz
230 * 012345678901234 */
231 build = (guint16) fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 10) << 8;
232 build += fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 12);
233 version = fu_unifying_format_version ("BOT",
234 fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 3),
235 fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 6),
236 build);
237 if (version == NULL) {
238 g_prefix_error (error, "failed to format firmware version: ");
239 return FALSE;
240 }
241 fu_device_set_version_bootloader (FU_DEVICE (self), version);
242 return TRUE;
243 }
244
245 static gboolean
246 fu_unifying_bootloader_open (FuUsbDevice *device, GError **error)
247 {
248 GUsbDevice *usb_device = fu_usb_device_get_dev (device);
249 const guint idx = 0x00;
250
251 /* claim the only interface */
252 if (!g_usb_device_claim_interface (usb_device, idx,
253 G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
254 error)) {
255 g_prefix_error (error, "Failed to claim 0x%02x: ", idx);
256 return FALSE;
257 }
258
259 /* success */
260 return TRUE;
261 }
262
263 static gboolean
264 fu_unifying_bootloader_setup (FuDevice *device, GError **error)
265 {
266 FuUnifyingBootloaderClass *klass = FU_UNIFYING_BOOTLOADER_GET_CLASS (device);
267 FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device);
268 FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self);
269 g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new ();
270
271 /* get memory map */
272 req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO;
273 if (!fu_unifying_bootloader_request (self, req, error)) {
274 g_prefix_error (error, "failed to get meminfo: ");
275 return FALSE;
276 }
277 if (req->len != 0x06) {
278 g_set_error (error,
279 G_IO_ERROR,
280 G_IO_ERROR_FAILED,
281 "failed to get meminfo: invalid size %02x",
282 req->len);
283 return FALSE;
284 }
285
286 /* parse values */
287 priv->flash_addr_lo = fu_common_read_uint16 (req->data + 0, G_BIG_ENDIAN);
288 priv->flash_addr_hi = fu_common_read_uint16 (req->data + 2, G_BIG_ENDIAN);
289 priv->flash_blocksize = fu_common_read_uint16 (req->data + 4, G_BIG_ENDIAN);
290
291 /* get bootloader version */
292 if (!fu_unifying_bootloader_set_bl_version (self, error))
293 return FALSE;
294
295 /* subclassed further */
296 if (klass->setup != NULL)
297 return klass->setup (self, error);
298
299 /* success */
300 return TRUE;
301 }
302
303 static gboolean
304 fu_unifying_bootloader_close (FuUsbDevice *device, GError **error)
305 {
306 GUsbDevice *usb_device = fu_usb_device_get_dev (device);
307 if (usb_device != NULL) {
308 if (!g_usb_device_release_interface (usb_device, 0x00,
309 G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER,
310 error)) {
311 return FALSE;
312 }
313 }
314 return TRUE;
315 }
316
317 gboolean
318 fu_unifying_bootloader_request (FuUnifyingBootloader *self,
319 FuUnifyingBootloaderRequest *req,
320 GError **error)
321 {
322 GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
323 gsize actual_length = 0;
324 guint8 buf_request[32];
325 guint8 buf_response[32];
326
327 /* build packet */
328 memset (buf_request, 0x00, sizeof (buf_request));
329 buf_request[0x00] = req->cmd;
330 buf_request[0x01] = req->addr >> 8;
331 buf_request[0x02] = req->addr & 0xff;
332 buf_request[0x03] = req->len;
333 if (!fu_memcpy_safe (buf_request, sizeof(buf_request), 0x04, /* dst */
334 req->data, sizeof(req->data), 0x0, /* src */
335 sizeof(req->data), error))
336 return FALSE;
337
338 /* send request */
339 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
340 fu_common_dump_raw (G_LOG_DOMAIN, "host->device",
341 buf_request, sizeof (buf_request));
342 }
343 if (usb_device != NULL) {
344 if (!g_usb_device_control_transfer (usb_device,
345 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
346 G_USB_DEVICE_REQUEST_TYPE_CLASS,
347 G_USB_DEVICE_RECIPIENT_INTERFACE,
348 HID_REPORT_SET,
349 0x0200, 0x0000,
350 buf_request,
351 sizeof (buf_request),
352 &actual_length,
353 FU_UNIFYING_DEVICE_TIMEOUT_MS,
354 NULL,
355 error)) {
356 g_prefix_error (error, "failed to send data: ");
357 return FALSE;
358 }
359 }
360
361 /* no response required when rebooting */
362 if (usb_device != NULL &&
363 req->cmd == FU_UNIFYING_BOOTLOADER_CMD_REBOOT) {
364 g_autoptr(GError) error_ignore = NULL;
365 if (!g_usb_device_interrupt_transfer (usb_device,
366 FU_UNIFYING_DEVICE_EP1,
367 buf_response,
368 sizeof (buf_response),
369 &actual_length,
370 FU_UNIFYING_DEVICE_TIMEOUT_MS,
371 NULL,
372 &error_ignore)) {
373 g_debug ("ignoring: %s", error_ignore->message);
374 } else {
375 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
376 fu_common_dump_raw (G_LOG_DOMAIN, "device->host",
377 buf_response, actual_length);
378 }
379 }
380 return TRUE;
381 }
382
383 /* get response */
384 memset (buf_response, 0x00, sizeof (buf_response));
385 if (usb_device != NULL) {
386 if (!g_usb_device_interrupt_transfer (usb_device,
387 FU_UNIFYING_DEVICE_EP1,
388 buf_response,
389 sizeof (buf_response),
390 &actual_length,
391 FU_UNIFYING_DEVICE_TIMEOUT_MS,
392 NULL,
393 error)) {
394 g_prefix_error (error, "failed to get data: ");
395 return FALSE;
396 }
397 } else {
398 /* emulated */
399 buf_response[0] = buf_request[0];
400 if (buf_response[0] == FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO) {
401 buf_response[3] = 0x06; /* len */
402 buf_response[4] = 0x40; /* lo MSB */
403 buf_response[5] = 0x00; /* lo LSB */
404 buf_response[6] = 0x6b; /* hi MSB */
405 buf_response[7] = 0xff; /* hi LSB */
406 buf_response[8] = 0x00; /* bs MSB */
407 buf_response[9] = 0x80; /* bs LSB */
408 }
409 actual_length = sizeof (buf_response);
410 }
411 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
412 fu_common_dump_raw (G_LOG_DOMAIN, "device->host",
413 buf_response, actual_length);
414 }
415
416 /* parse response */
417 if ((buf_response[0x00] & 0xf0) != req->cmd) {
418 g_set_error (error,
419 G_IO_ERROR,
420 G_IO_ERROR_FAILED,
421 "invalid command response of %02x, expected %02x",
422 buf_response[0x00], req->cmd);
423 return FALSE;
424 }
425 req->cmd = buf_response[0x00];
426 req->addr = ((guint16) buf_response[0x01] << 8) + buf_response[0x02];
427 req->len = buf_response[0x03];
428 if (req->len > 28) {
429 g_set_error (error,
430 G_IO_ERROR,
431 G_IO_ERROR_FAILED,
432 "invalid data size of %02x", req->len);
433 return FALSE;
434 }
435 memset (req->data, 0x00, 28);
436 if (req->len > 0)
437 memcpy (req->data, buf_response + 0x04, req->len);
438 return TRUE;
439 }
440
441 static void
442 fu_unifying_bootloader_init (FuUnifyingBootloader *self)
443 {
444 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
445 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
446 fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard");
447 fu_device_set_name (FU_DEVICE (self), "Unifying Receiver");
448 fu_device_set_summary (FU_DEVICE (self), "A miniaturised USB wireless receiver (bootloader)");
449 fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN);
450 fu_device_set_remove_delay (FU_DEVICE (self), FU_UNIFYING_DEVICE_TIMEOUT_MS);
451 }
452
453 static void
454 fu_unifying_bootloader_class_init (FuUnifyingBootloaderClass *klass)
455 {
456 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
457 FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass);
458 klass_device->to_string = fu_unifying_bootloader_to_string;
459 klass_device->attach = fu_unifying_bootloader_attach;
460 klass_device->setup = fu_unifying_bootloader_setup;
461 klass_usb_device->open = fu_unifying_bootloader_open;
462 klass_usb_device->close = fu_unifying_bootloader_close;
463 }
+0
-76
plugins/unifying/fu-unifying-bootloader.h less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-usb-device.h"
9
10 #define FU_TYPE_UNIFYING_BOOTLOADER (fu_unifying_bootloader_get_type ())
11 G_DECLARE_DERIVABLE_TYPE (FuUnifyingBootloader, fu_unifying_bootloader, FU, UNIFYING_BOOTLOADER, FuUsbDevice)
12
13 struct _FuUnifyingBootloaderClass
14 {
15 FuUsbDeviceClass parent_class;
16 gboolean (*setup) (FuUnifyingBootloader *self,
17 GError **error);
18 };
19
20 typedef enum {
21 FU_UNIFYING_BOOTLOADER_CMD_GENERAL_ERROR = 0x01,
22 FU_UNIFYING_BOOTLOADER_CMD_READ = 0x10,
23 FU_UNIFYING_BOOTLOADER_CMD_WRITE = 0x20,
24 FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_ADDR = 0x21,
25 FU_UNIFYING_BOOTLOADER_CMD_WRITE_VERIFY_FAIL = 0x22,
26 FU_UNIFYING_BOOTLOADER_CMD_WRITE_NONZERO_START = 0x23,
27 FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_CRC = 0x24,
28 FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE = 0x30,
29 FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR = 0x31,
30 FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START = 0x33,
31 FU_UNIFYING_BOOTLOADER_CMD_GET_HW_PLATFORM_ID = 0x40,
32 FU_UNIFYING_BOOTLOADER_CMD_GET_FW_VERSION = 0x50,
33 FU_UNIFYING_BOOTLOADER_CMD_GET_CHECKSUM = 0x60,
34 FU_UNIFYING_BOOTLOADER_CMD_REBOOT = 0x70,
35 FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO = 0x80,
36 FU_UNIFYING_BOOTLOADER_CMD_GET_BL_VERSION = 0x90,
37 FU_UNIFYING_BOOTLOADER_CMD_GET_INIT_FW_VERSION = 0xa0,
38 FU_UNIFYING_BOOTLOADER_CMD_READ_SIGNATURE = 0xb0,
39 FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER = 0xc0,
40 FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR= 0xc1,
41 FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW = 0xc2,
42 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM = 0xd0,
43 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR = 0xd1,
44 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC = 0xd2,
45 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID = 0xd3,
46 FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER = 0xd4,
47 FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE = 0xe0,
48 FU_UNIFYING_BOOTLOADER_CMD_LAST
49 } FuUnifyingBootloaderCmd;
50
51 /* packet to and from device */
52 typedef struct __attribute__((packed)) {
53 guint8 cmd;
54 guint16 addr;
55 guint8 len;
56 guint8 data[28];
57 } FuUnifyingBootloaderRequest;
58
59 FuUnifyingBootloaderRequest *fu_unifying_bootloader_request_new (void);
60
61 #pragma clang diagnostic push
62 #pragma clang diagnostic ignored "-Wunused-function"
63 G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUnifyingBootloaderRequest, g_free);
64 #pragma clang diagnostic pop
65
66 GPtrArray *fu_unifying_bootloader_parse_requests (FuUnifyingBootloader *self,
67 GBytes *fw,
68 GError **error);
69 gboolean fu_unifying_bootloader_request (FuUnifyingBootloader *self,
70 FuUnifyingBootloaderRequest *req,
71 GError **error);
72
73 guint16 fu_unifying_bootloader_get_addr_lo (FuUnifyingBootloader *self);
74 guint16 fu_unifying_bootloader_get_addr_hi (FuUnifyingBootloader *self);
75 guint16 fu_unifying_bootloader_get_blocksize (FuUnifyingBootloader *self);
+0
-47
plugins/unifying/fu-unifying-common.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <gio/gio.h>
12
13 #include "fu-unifying-common.h"
14
15 guint8
16 fu_unifying_buffer_read_uint8 (const gchar *str)
17 {
18 guint64 tmp;
19 gchar buf[3] = { 0x0, 0x0, 0x0 };
20 memcpy (buf, str, 2);
21 tmp = g_ascii_strtoull (buf, NULL, 16);
22 return tmp;
23 }
24
25 guint16
26 fu_unifying_buffer_read_uint16 (const gchar *str)
27 {
28 guint64 tmp;
29 gchar buf[5] = { 0x0, 0x0, 0x0, 0x0, 0x0 };
30 memcpy (buf, str, 4);
31 tmp = g_ascii_strtoull (buf, NULL, 16);
32 return tmp;
33 }
34
35 gchar *
36 fu_unifying_format_version (const gchar *name, guint8 major, guint8 minor, guint16 build)
37 {
38 GString *str = g_string_new (NULL);
39 for (guint i = 0; i < 3; i++) {
40 if (g_ascii_isspace (name[i]))
41 continue;
42 g_string_append_c (str, name[i]);
43 }
44 g_string_append_printf (str, "%02x.%02x_B%04x", major, minor, build);
45 return g_string_free (str, FALSE);
46 }
+0
-28
plugins/unifying/fu-unifying-common.h less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include <glib.h>
9
10 #define FU_UNIFYING_DEVICE_VID 0x046d
11
12 #define FU_UNIFYING_DEVICE_PID_RUNTIME 0xc52b
13 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC 0xaaaa
14 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC_PICO 0xaaae
15 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS 0xaaac
16 #define FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS_PICO 0xaaad
17
18 /* Signed firmware are very long to verify on the device */
19 #define FU_UNIFYING_DEVICE_TIMEOUT_MS 30000
20
21 guint8 fu_unifying_buffer_read_uint8 (const gchar *str);
22 guint16 fu_unifying_buffer_read_uint16 (const gchar *str);
23
24 gchar *fu_unifying_format_version (const gchar *name,
25 guint8 major,
26 guint8 minor,
27 guint16 build);
+0
-398
plugins/unifying/fu-unifying-hidpp-msg.c less more
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-unifying-hidpp.h"
11 #include "fu-unifying-hidpp-msg.h"
12
13 FuUnifyingHidppMsg *
14 fu_unifying_hidpp_msg_new (void)
15 {
16 return g_new0 (FuUnifyingHidppMsg, 1);
17 }
18
19 const gchar *
20 fu_unifying_hidpp_msg_dev_id_to_string (FuUnifyingHidppMsg *msg)
21 {
22 g_return_val_if_fail (msg != NULL, NULL);
23 if (msg->device_id == HIDPP_DEVICE_ID_WIRED)
24 return "wired";
25 if (msg->device_id == HIDPP_DEVICE_ID_RECEIVER)
26 return "receiver";
27 if (msg->device_id == HIDPP_DEVICE_ID_UNSET)
28 return "unset";
29 return NULL;
30 }
31
32 const gchar *
33 fu_unifying_hidpp_msg_rpt_id_to_string (FuUnifyingHidppMsg *msg)
34 {
35 g_return_val_if_fail (msg != NULL, NULL);
36 if (msg->report_id == HIDPP_REPORT_ID_SHORT)
37 return "short";
38 if (msg->report_id == HIDPP_REPORT_ID_LONG)
39 return "long";
40 if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG)
41 return "very-long";
42 return NULL;
43 }
44
45 gsize
46 fu_unifying_hidpp_msg_get_payload_length (FuUnifyingHidppMsg *msg)
47 {
48 if (msg->report_id == HIDPP_REPORT_ID_SHORT)
49 return 0x07;
50 if (msg->report_id == HIDPP_REPORT_ID_LONG)
51 return 0x14;
52 if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG)
53 return 0x2f;
54 if (msg->report_id == HIDPP_REPORT_NOTIFICATION)
55 return 0x08;
56 return 0x0;
57 }
58
59 const gchar *
60 fu_unifying_hidpp_msg_fcn_id_to_string (FuUnifyingHidppMsg *msg)
61 {
62 g_return_val_if_fail (msg != NULL, NULL);
63 switch (msg->sub_id) {
64 case HIDPP_SUBID_SET_REGISTER:
65 case HIDPP_SUBID_GET_REGISTER:
66 case HIDPP_SUBID_SET_LONG_REGISTER:
67 case HIDPP_SUBID_GET_LONG_REGISTER:
68 case HIDPP_SUBID_SET_VERY_LONG_REGISTER:
69 case HIDPP_SUBID_GET_VERY_LONG_REGISTER:
70 if (msg->function_id == HIDPP_REGISTER_HIDPP_NOTIFICATIONS)
71 return "hidpp-notifications";
72 if (msg->function_id == HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES)
73 return "individual-features";
74 if (msg->function_id == HIDPP_REGISTER_BATTERY_STATUS)
75 return "battery-status";
76 if (msg->function_id == HIDPP_REGISTER_BATTERY_MILEAGE)
77 return "battery-mileage";
78 if (msg->function_id == HIDPP_REGISTER_PROFILE)
79 return "profile";
80 if (msg->function_id == HIDPP_REGISTER_LED_STATUS)
81 return "led-status";
82 if (msg->function_id == HIDPP_REGISTER_LED_INTENSITY)
83 return "led-intensity";
84 if (msg->function_id == HIDPP_REGISTER_LED_COLOR)
85 return "led-color";
86 if (msg->function_id == HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS)
87 return "optical-sensor-settings";
88 if (msg->function_id == HIDPP_REGISTER_CURRENT_RESOLUTION)
89 return "current-resolution";
90 if (msg->function_id == HIDPP_REGISTER_USB_REFRESH_RATE)
91 return "usb-refresh-rate";
92 if (msg->function_id == HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT)
93 return "generic-memory-management";
94 if (msg->function_id == HIDPP_REGISTER_HOT_CONTROL)
95 return "hot-control";
96 if (msg->function_id == HIDPP_REGISTER_READ_MEMORY)
97 return "read-memory";
98 if (msg->function_id == HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION)
99 return "device-connection-disconnection";
100 if (msg->function_id == HIDPP_REGISTER_PAIRING_INFORMATION)
101 return "pairing-information";
102 if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE)
103 return "device-firmware-update-mode";
104 if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION)
105 return "device-firmware-information";
106 break;
107 default:
108 break;
109 }
110 return NULL;
111
112 }
113
114 const gchar *
115 fu_unifying_hidpp_msg_sub_id_to_string (FuUnifyingHidppMsg *msg)
116 {
117 g_return_val_if_fail (msg != NULL, NULL);
118 if (msg->sub_id == HIDPP_SUBID_VENDOR_SPECIFIC_KEYS)
119 return "vendor-specific-keys";
120 if (msg->sub_id == HIDPP_SUBID_POWER_KEYS)
121 return "power-keys";
122 if (msg->sub_id == HIDPP_SUBID_ROLLER)
123 return "roller";
124 if (msg->sub_id == HIDPP_SUBID_MOUSE_EXTRA_BUTTONS)
125 return "mouse-extra-buttons";
126 if (msg->sub_id == HIDPP_SUBID_BATTERY_CHARGING_LEVEL)
127 return "battery-charging-level";
128 if (msg->sub_id == HIDPP_SUBID_USER_INTERFACE_EVENT)
129 return "user-interface-event";
130 if (msg->sub_id == HIDPP_SUBID_F_LOCK_STATUS)
131 return "f-lock-status";
132 if (msg->sub_id == HIDPP_SUBID_CALCULATOR_RESULT)
133 return "calculator-result";
134 if (msg->sub_id == HIDPP_SUBID_MENU_NAVIGATE)
135 return "menu-navigate";
136 if (msg->sub_id == HIDPP_SUBID_FN_KEY)
137 return "fn-key";
138 if (msg->sub_id == HIDPP_SUBID_BATTERY_MILEAGE)
139 return "battery-mileage";
140 if (msg->sub_id == HIDPP_SUBID_UART_RX)
141 return "uart-rx";
142 if (msg->sub_id == HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE)
143 return "backlight-duration-update";
144 if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCONNECTION)
145 return "device-disconnection";
146 if (msg->sub_id == HIDPP_SUBID_DEVICE_CONNECTION)
147 return "device-connection";
148 if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCOVERY)
149 return "device-discovery";
150 if (msg->sub_id == HIDPP_SUBID_PIN_CODE_REQUEST)
151 return "pin-code-request";
152 if (msg->sub_id == HIDPP_SUBID_RECEIVER_WORKING_MODE)
153 return "receiver-working-mode";
154 if (msg->sub_id == HIDPP_SUBID_ERROR_MESSAGE)
155 return "error-message";
156 if (msg->sub_id == HIDPP_SUBID_RF_LINK_CHANGE)
157 return "rf-link-change";
158 if (msg->sub_id == HIDPP_SUBID_HCI)
159 return "hci";
160 if (msg->sub_id == HIDPP_SUBID_LINK_QUALITY)
161 return "link-quality";
162 if (msg->sub_id == HIDPP_SUBID_DEVICE_LOCKING_CHANGED)
163 return "device-locking-changed";
164 if (msg->sub_id == HIDPP_SUBID_WIRELESS_DEVICE_CHANGE)
165 return "wireless-device-change";
166 if (msg->sub_id == HIDPP_SUBID_ACL)
167 return "acl";
168 if (msg->sub_id == HIDPP_SUBID_VOIP_TELEPHONY_EVENT)
169 return "voip-telephony-event";
170 if (msg->sub_id == HIDPP_SUBID_LED)
171 return "led";
172 if (msg->sub_id == HIDPP_SUBID_GESTURE_AND_AIR)
173 return "gesture-and-air";
174 if (msg->sub_id == HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH)
175 return "touchpad-multi-touch";
176 if (msg->sub_id == HIDPP_SUBID_TRACEABILITY)
177 return "traceability";
178 if (msg->sub_id == HIDPP_SUBID_SET_REGISTER)
179 return "set-register";
180 if (msg->sub_id == HIDPP_SUBID_GET_REGISTER)
181 return "get-register";
182 if (msg->sub_id == HIDPP_SUBID_SET_LONG_REGISTER)
183 return "set-long-register";
184 if (msg->sub_id == HIDPP_SUBID_GET_LONG_REGISTER)
185 return "get-long-register";
186 if (msg->sub_id == HIDPP_SUBID_SET_VERY_LONG_REGISTER)
187 return "set-very-long-register";
188 if (msg->sub_id == HIDPP_SUBID_GET_VERY_LONG_REGISTER)
189 return "get-very-long-register";
190 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG)
191 return "error-msg";
192 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20)
193 return "error-msg-v2";
194 return NULL;
195 }
196
197 gboolean
198 fu_unifying_hidpp_msg_is_reply (FuUnifyingHidppMsg *msg1, FuUnifyingHidppMsg *msg2)
199 {
200 g_return_val_if_fail (msg1 != NULL, FALSE);
201 g_return_val_if_fail (msg2 != NULL, FALSE);
202 if (msg1->device_id != msg2->device_id &&
203 msg1->device_id != HIDPP_DEVICE_ID_UNSET &&
204 msg2->device_id != HIDPP_DEVICE_ID_UNSET)
205 return FALSE;
206 if (msg1->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID ||
207 msg2->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID)
208 return TRUE;
209 if (msg1->sub_id != msg2->sub_id)
210 return FALSE;
211 if (msg1->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID ||
212 msg2->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID)
213 return TRUE;
214 if (msg1->function_id != msg2->function_id)
215 return FALSE;
216 return TRUE;
217 }
218
219 /* HID++ error */
220 gboolean
221 fu_unifying_hidpp_msg_is_error (FuUnifyingHidppMsg *msg, GError **error)
222 {
223 g_return_val_if_fail (msg != NULL, FALSE);
224 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG) {
225 switch (msg->data[1]) {
226 case HIDPP_ERR_INVALID_SUBID:
227 g_set_error_literal (error,
228 G_IO_ERROR,
229 G_IO_ERROR_NOT_SUPPORTED,
230 "invalid SubID");
231 break;
232 case HIDPP_ERR_INVALID_ADDRESS:
233 g_set_error_literal (error,
234 G_IO_ERROR,
235 G_IO_ERROR_INVALID_DATA,
236 "invalid address");
237 break;
238 case HIDPP_ERR_INVALID_VALUE:
239 g_set_error_literal (error,
240 G_IO_ERROR,
241 G_IO_ERROR_INVALID_DATA,
242 "invalid value");
243 break;
244 case HIDPP_ERR_CONNECT_FAIL:
245 g_set_error_literal (error,
246 G_IO_ERROR,
247 G_IO_ERROR_FAILED,
248 "connection request failed");
249 break;
250 case HIDPP_ERR_TOO_MANY_DEVICES:
251 g_set_error_literal (error,
252 G_IO_ERROR,
253 G_IO_ERROR_NO_SPACE,
254 "too many devices connected");
255 break;
256 case HIDPP_ERR_ALREADY_EXISTS:
257 g_set_error_literal (error,
258 G_IO_ERROR,
259 G_IO_ERROR_EXISTS,
260 "already exists");
261 break;
262 case HIDPP_ERR_BUSY:
263 g_set_error_literal (error,
264 G_IO_ERROR,
265 G_IO_ERROR_BUSY,
266 "busy");
267 break;
268 case HIDPP_ERR_UNKNOWN_DEVICE:
269 g_set_error_literal (error,
270 G_IO_ERROR,
271 G_IO_ERROR_NOT_FOUND,
272 "unknown device");
273 break;
274 case HIDPP_ERR_RESOURCE_ERROR:
275 g_set_error_literal (error,
276 G_IO_ERROR,
277 G_IO_ERROR_HOST_UNREACHABLE,
278 "resource error");
279 break;
280 case HIDPP_ERR_REQUEST_UNAVAILABLE:
281 g_set_error_literal (error,
282 G_IO_ERROR,
283 G_IO_ERROR_EXISTS,
284 "request not valid in current context");
285 break;
286 case HIDPP_ERR_INVALID_PARAM_VALUE:
287 g_set_error_literal (error,
288 G_IO_ERROR,
289 G_IO_ERROR_INVALID_DATA,
290 "request parameter has unsupported value");
291 break;
292 case HIDPP_ERR_WRONG_PIN_CODE:
293 g_set_error_literal (error,
294 G_IO_ERROR,
295 G_IO_ERROR_CONNECTION_REFUSED,
296 "the pin code was wrong");
297 break;
298 default:
299 g_set_error_literal (error,
300 G_IO_ERROR,
301 G_IO_ERROR_FAILED,
302 "generic failure");
303 }
304 return FALSE;
305 }
306 if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20) {
307 switch (msg->data[1]) {
308 case HIDPP_ERROR_CODE_INVALID_ARGUMENT:
309 g_set_error (error,
310 G_IO_ERROR,
311 G_IO_ERROR_INVALID_ARGUMENT,
312 "Invalid argument 0x%02x",
313 msg->data[2]);
314 break;
315 case HIDPP_ERROR_CODE_OUT_OF_RANGE:
316 g_set_error_literal (error,
317 G_IO_ERROR,
318 G_IO_ERROR_INVALID_DATA,
319 "out of range");
320 break;
321 case HIDPP_ERROR_CODE_HW_ERROR:
322 g_set_error_literal (error,
323 G_IO_ERROR,
324 G_IO_ERROR_BROKEN_PIPE,
325 "hardware error");
326 break;
327 case HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX:
328 g_set_error_literal (error,
329 G_IO_ERROR,
330 G_IO_ERROR_INVALID_ARGUMENT,
331 "invalid feature index");
332 break;
333 case HIDPP_ERROR_CODE_INVALID_FUNCTION_ID:
334 g_set_error_literal (error,
335 G_IO_ERROR,
336 G_IO_ERROR_INVALID_ARGUMENT,
337 "invalid function ID");
338 break;
339 case HIDPP_ERROR_CODE_BUSY:
340 g_set_error_literal (error,
341 G_IO_ERROR,
342 G_IO_ERROR_BUSY,
343 "busy");
344 break;
345 case HIDPP_ERROR_CODE_UNSUPPORTED:
346 g_set_error_literal (error,
347 G_IO_ERROR,
348 G_IO_ERROR_NOT_SUPPORTED,
349 "unsupported");
350 break;
351 default:
352 g_set_error_literal (error,
353 G_IO_ERROR,
354 G_IO_ERROR_FAILED,
355 "generic failure");
356 break;
357 }
358 return FALSE;
359 }
360 return TRUE;
361 }
362
363 void
364 fu_unifying_hidpp_msg_copy (FuUnifyingHidppMsg *msg_dst, const FuUnifyingHidppMsg *msg_src)
365 {
366 g_return_if_fail (msg_dst != NULL);
367 g_return_if_fail (msg_src != NULL);
368 memset (msg_dst->data, 0x00, sizeof(msg_dst->data));
369 msg_dst->device_id = msg_src->device_id;
370 msg_dst->sub_id = msg_src->sub_id;
371 msg_dst->function_id = msg_src->function_id;
372 memcpy (msg_dst->data, msg_src->data, sizeof(msg_dst->data));
373 }
374
375 /* filter HID++1.0 messages */
376 gboolean
377 fu_unifying_hidpp_msg_is_hidpp10_compat (FuUnifyingHidppMsg *msg)
378 {
379 g_return_val_if_fail (msg != NULL, FALSE);
380 if (msg->sub_id == 0x40 ||
381 msg->sub_id == 0x41 ||
382 msg->sub_id == 0x49 ||
383 msg->sub_id == 0x4b ||
384 msg->sub_id == 0x8f) {
385 return TRUE;
386 }
387 return FALSE;
388 }
389
390 gboolean
391 fu_unifying_hidpp_msg_verify_swid (FuUnifyingHidppMsg *msg)
392 {
393 g_return_val_if_fail (msg != NULL, FALSE);
394 if ((msg->function_id & 0x0f) != FU_UNIFYING_HIDPP_MSG_SW_ID)
395 return FALSE;
396 return TRUE;
397 }
+0
-54
plugins/unifying/fu-unifying-hidpp-msg.h less more
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include <glib.h>
9
10 typedef enum {
11 FU_UNIFYING_HIDPP_MSG_FLAG_NONE,
12 FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT = 1 << 0,
13 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID = 1 << 1,
14 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID = 1 << 2,
15 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID = 1 << 3,
16 /*< private >*/
17 FU_UNIFYING_HIDPP_MSG_FLAG_LAST
18 } FuUnifyingHidppMsgFlags;
19
20 typedef struct __attribute__((packed)) {
21 guint8 report_id;
22 guint8 device_id;
23 guint8 sub_id;
24 guint8 function_id; /* funcId:software_id */
25 guint8 data[47]; /* maximum supported by Windows XP SP2 */
26 /* not included in the packet sent to the hardware */
27 guint32 flags;
28 guint8 hidpp_version;
29 } FuUnifyingHidppMsg;
30
31 /* this is specific to fwupd */
32 #define FU_UNIFYING_HIDPP_MSG_SW_ID 0x07
33
34 #pragma clang diagnostic push
35 #pragma clang diagnostic ignored "-Wunused-function"
36 G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUnifyingHidppMsg, g_free);
37 #pragma clang diagnostic pop
38
39 FuUnifyingHidppMsg *fu_unifying_hidpp_msg_new (void);
40 void fu_unifying_hidpp_msg_copy (FuUnifyingHidppMsg *msg_dst,
41 const FuUnifyingHidppMsg *msg_src);
42 gsize fu_unifying_hidpp_msg_get_payload_length (FuUnifyingHidppMsg *msg);
43 gboolean fu_unifying_hidpp_msg_is_reply (FuUnifyingHidppMsg *msg1,
44 FuUnifyingHidppMsg *msg2);
45 gboolean fu_unifying_hidpp_msg_is_hidpp10_compat (FuUnifyingHidppMsg *msg);
46 gboolean fu_unifying_hidpp_msg_is_error (FuUnifyingHidppMsg *msg,
47 GError **error);
48 gboolean fu_unifying_hidpp_msg_verify_swid (FuUnifyingHidppMsg *msg);
49
50 const gchar *fu_unifying_hidpp_msg_dev_id_to_string (FuUnifyingHidppMsg *msg);
51 const gchar *fu_unifying_hidpp_msg_rpt_id_to_string (FuUnifyingHidppMsg *msg);
52 const gchar *fu_unifying_hidpp_msg_sub_id_to_string (FuUnifyingHidppMsg *msg);
53 const gchar *fu_unifying_hidpp_msg_fcn_id_to_string (FuUnifyingHidppMsg *msg);
+0
-207
plugins/unifying/fu-unifying-hidpp.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include "fu-common.h"
9 #include "fu-unifying-common.h"
10 #include "fu-unifying-hidpp.h"
11
12 static gchar *
13 fu_unifying_hidpp_msg_to_string (FuUnifyingHidppMsg *msg)
14 {
15 GString *str = g_string_new (NULL);
16 const gchar *tmp;
17 g_autoptr(GError) error = NULL;
18 g_autoptr(GString) flags_str = g_string_new (NULL);
19
20 g_return_val_if_fail (msg != NULL, NULL);
21
22 if (msg->flags == FU_UNIFYING_HIDPP_MSG_FLAG_NONE) {
23 g_string_append (flags_str, "none");
24 } else {
25 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT)
26 g_string_append (flags_str, "longer-timeout,");
27 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID)
28 g_string_append (flags_str, "ignore-sub-id,");
29 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID)
30 g_string_append (flags_str, "ignore-fnct-id,");
31 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID)
32 g_string_append (flags_str, "ignore-swid,");
33 if (str->len > 0)
34 g_string_truncate (str, str->len - 1);
35 }
36 g_string_append_printf (str, "flags: %02x [%s]\n",
37 msg->flags,
38 flags_str->str);
39 g_string_append_printf (str, "report-id: %02x [%s]\n",
40 msg->report_id,
41 fu_unifying_hidpp_msg_rpt_id_to_string (msg));
42 tmp = fu_unifying_hidpp_msg_dev_id_to_string (msg);
43 g_string_append_printf (str, "device-id: %02x [%s]\n",
44 msg->device_id, tmp );
45 g_string_append_printf (str, "sub-id: %02x [%s]\n",
46 msg->sub_id,
47 fu_unifying_hidpp_msg_sub_id_to_string (msg));
48 g_string_append_printf (str, "function-id: %02x [%s]\n",
49 msg->function_id,
50 fu_unifying_hidpp_msg_fcn_id_to_string (msg));
51 if (!fu_unifying_hidpp_msg_is_error (msg, &error)) {
52 g_string_append_printf (str, "error: %s\n",
53 error->message);
54 }
55 return g_string_free (str, FALSE);
56 }
57
58 gboolean
59 fu_unifying_hidpp_send (FuIOChannel *io_channel,
60 FuUnifyingHidppMsg *msg,
61 guint timeout,
62 GError **error)
63 {
64 gsize len = fu_unifying_hidpp_msg_get_payload_length (msg);
65
66 /* only for HID++2.0 */
67 if (msg->hidpp_version >= 2.f)
68 msg->function_id |= FU_UNIFYING_HIDPP_MSG_SW_ID;
69
70 /* detailed debugging */
71 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
72 g_autofree gchar *str = fu_unifying_hidpp_msg_to_string (msg);
73 fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len);
74 g_print ("%s", str);
75 }
76
77 /* HID */
78 if (!fu_io_channel_write_raw (io_channel, (guint8 *) msg, len, 1500,
79 FU_IO_CHANNEL_FLAG_FLUSH_INPUT |
80 FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) {
81 g_prefix_error (error, "failed to send: ");
82 return FALSE;
83 }
84
85 /* success */
86 return TRUE;
87 }
88
89 gboolean
90 fu_unifying_hidpp_receive (FuIOChannel *io_channel,
91 FuUnifyingHidppMsg *msg,
92 guint timeout,
93 GError **error)
94 {
95 gsize read_size = 0;
96
97 if (!fu_io_channel_read_raw (io_channel,
98 (guint8 *) msg,
99 sizeof(FuUnifyingHidppMsg),
100 &read_size,
101 timeout,
102 FU_IO_CHANNEL_FLAG_SINGLE_SHOT,
103 error)) {
104 g_prefix_error (error, "failed to receive: ");
105 return FALSE;
106 }
107
108 /* check long enough, but allow returning oversize packets */
109 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL)
110 fu_common_dump_raw (G_LOG_DOMAIN, "device->host", (guint8 *) msg, read_size);
111 if (read_size < fu_unifying_hidpp_msg_get_payload_length (msg)) {
112 g_set_error (error,
113 G_IO_ERROR,
114 G_IO_ERROR_FAILED,
115 "message length too small, "
116 "got %" G_GSIZE_FORMAT " expected %" G_GSIZE_FORMAT,
117 read_size, fu_unifying_hidpp_msg_get_payload_length (msg));
118 return FALSE;
119 }
120
121 /* detailed debugging */
122 if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) {
123 g_autofree gchar *str = fu_unifying_hidpp_msg_to_string (msg);
124 g_print ("%s", str);
125 }
126
127 /* success */
128 return TRUE;
129 }
130
131 gboolean
132 fu_unifying_hidpp_transfer (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, GError **error)
133 {
134 guint timeout = FU_UNIFYING_DEVICE_TIMEOUT_MS;
135 guint ignore_cnt = 0;
136 g_autoptr(FuUnifyingHidppMsg) msg_tmp = fu_unifying_hidpp_msg_new ();
137
138 /* increase timeout for some operations */
139 if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT)
140 timeout *= 10;
141
142 /* send request */
143 if (!fu_unifying_hidpp_send (io_channel, msg, timeout, error))
144 return FALSE;
145
146 /* keep trying to receive until we get a valid reply */
147 while (1) {
148 msg_tmp->hidpp_version = msg->hidpp_version;
149 if (!fu_unifying_hidpp_receive (io_channel, msg_tmp, timeout, error)) {
150 g_prefix_error (error, "failed to receive: ");
151 return FALSE;
152 }
153
154 /* we don't know how to handle this report packet */
155 if (fu_unifying_hidpp_msg_get_payload_length (msg_tmp) == 0x0) {
156 g_debug ("HID++1.0 report 0x%02x has unknown length, ignoring",
157 msg_tmp->report_id);
158 continue;
159 }
160
161 /* maybe something is also writing to the device? --
162 * we can't use the SwID as this is a HID++2.0 feature */
163 if (!fu_unifying_hidpp_msg_is_error (msg_tmp, error))
164 return FALSE;
165
166 /* is valid reply */
167 if (fu_unifying_hidpp_msg_is_reply (msg, msg_tmp))
168 break;
169
170 /* to ensure compatibility when an HID++ 2.0 device is
171 * connected to an HID++ 1.0 receiver, any feature index
172 * corresponding to an HID++ 1.0 sub-identifier which could be
173 * sent by the receiver, must be assigned to a dummy feature */
174 if (msg->hidpp_version >= 2.f) {
175 if (fu_unifying_hidpp_msg_is_hidpp10_compat (msg_tmp)) {
176 g_debug ("ignoring HID++1.0 reply");
177 continue;
178 }
179
180 /* not us */
181 if ((msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID) == 0) {
182 if (!fu_unifying_hidpp_msg_verify_swid (msg_tmp)) {
183 g_debug ("ignoring reply with SwId 0x%02i, expected 0x%02i",
184 msg_tmp->function_id & 0x0f,
185 FU_UNIFYING_HIDPP_MSG_SW_ID);
186 continue;
187 }
188 }
189 }
190
191 /* hardware not responding */
192 if (ignore_cnt++ > 10) {
193 g_set_error (error,
194 G_IO_ERROR,
195 G_IO_ERROR_FAILED,
196 "too many messages to ignore");
197 return FALSE;
198 }
199
200 g_debug ("ignoring message %u", ignore_cnt);
201 };
202
203 /* copy over data */
204 fu_unifying_hidpp_msg_copy (msg, msg_tmp);
205 return TRUE;
206 }
+0
-148
plugins/unifying/fu-unifying-hidpp.h less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include <gio/gio.h>
9
10 #include "fu-io-channel.h"
11
12 /*
13 * Based on the HID++ documentation provided by Nestor Lopez Casado at:
14 * https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
15 */
16 #define HIDPP_DEVICE_ID_WIRED 0x00
17 #define HIDPP_DEVICE_ID_RECEIVER 0xFF
18 #define HIDPP_DEVICE_ID_UNSET 0xFE
19
20 #define HIDPP_REPORT_NOTIFICATION 0x01
21 #define HIDPP_REPORT_ID_SHORT 0x10
22 #define HIDPP_REPORT_ID_LONG 0x11
23 #define HIDPP_REPORT_ID_VERY_LONG 0x12
24
25 #define HIDPP_SUBID_VENDOR_SPECIFIC_KEYS 0x03
26 #define HIDPP_SUBID_POWER_KEYS 0x04
27 #define HIDPP_SUBID_ROLLER 0x05
28 #define HIDPP_SUBID_MOUSE_EXTRA_BUTTONS 0x06
29 #define HIDPP_SUBID_BATTERY_CHARGING_LEVEL 0x07
30 #define HIDPP_SUBID_USER_INTERFACE_EVENT 0x08
31 #define HIDPP_SUBID_F_LOCK_STATUS 0x09
32 #define HIDPP_SUBID_CALCULATOR_RESULT 0x0A
33 #define HIDPP_SUBID_MENU_NAVIGATE 0x0B
34 #define HIDPP_SUBID_FN_KEY 0x0C
35 #define HIDPP_SUBID_BATTERY_MILEAGE 0x0D
36 #define HIDPP_SUBID_UART_RX 0x0E
37 #define HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE 0x17
38 #define HIDPP_SUBID_DEVICE_DISCONNECTION 0x40
39 #define HIDPP_SUBID_DEVICE_CONNECTION 0x41
40 #define HIDPP_SUBID_DEVICE_DISCOVERY 0x42
41 #define HIDPP_SUBID_PIN_CODE_REQUEST 0x43
42 #define HIDPP_SUBID_RECEIVER_WORKING_MODE 0x44
43 #define HIDPP_SUBID_ERROR_MESSAGE 0x45
44 #define HIDPP_SUBID_RF_LINK_CHANGE 0x46
45 #define HIDPP_SUBID_HCI 0x48
46 #define HIDPP_SUBID_LINK_QUALITY 0x49
47 #define HIDPP_SUBID_DEVICE_LOCKING_CHANGED 0x4a
48 #define HIDPP_SUBID_WIRELESS_DEVICE_CHANGE 0x4B
49 #define HIDPP_SUBID_ACL 0x51
50 #define HIDPP_SUBID_VOIP_TELEPHONY_EVENT 0x5B
51 #define HIDPP_SUBID_LED 0x60
52 #define HIDPP_SUBID_GESTURE_AND_AIR 0x65
53 #define HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH 0x66
54 #define HIDPP_SUBID_TRACEABILITY 0x78
55 #define HIDPP_SUBID_SET_REGISTER 0x80
56 #define HIDPP_SUBID_GET_REGISTER 0x81
57 #define HIDPP_SUBID_SET_LONG_REGISTER 0x82
58 #define HIDPP_SUBID_GET_LONG_REGISTER 0x83
59 #define HIDPP_SUBID_SET_VERY_LONG_REGISTER 0x84
60 #define HIDPP_SUBID_GET_VERY_LONG_REGISTER 0x85
61 #define HIDPP_SUBID_ERROR_MSG 0x8F
62 #define HIDPP_SUBID_ERROR_MSG_20 0xFF
63
64 #define HIDPP_ERR_SUCCESS 0x00
65 #define HIDPP_ERR_INVALID_SUBID 0x01
66 #define HIDPP_ERR_INVALID_ADDRESS 0x02
67 #define HIDPP_ERR_INVALID_VALUE 0x03
68 #define HIDPP_ERR_CONNECT_FAIL 0x04
69 #define HIDPP_ERR_TOO_MANY_DEVICES 0x05
70 #define HIDPP_ERR_ALREADY_EXISTS 0x06
71 #define HIDPP_ERR_BUSY 0x07
72 #define HIDPP_ERR_UNKNOWN_DEVICE 0x08
73 #define HIDPP_ERR_RESOURCE_ERROR 0x09
74 #define HIDPP_ERR_REQUEST_UNAVAILABLE 0x0A
75 #define HIDPP_ERR_INVALID_PARAM_VALUE 0x0B
76 #define HIDPP_ERR_WRONG_PIN_CODE 0x0C
77
78 /*
79 * HID++1.0 registers
80 */
81
82 #define HIDPP_REGISTER_HIDPP_NOTIFICATIONS 0x00
83 #define HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES 0x01
84 #define HIDPP_REGISTER_BATTERY_STATUS 0x07
85 #define HIDPP_REGISTER_BATTERY_MILEAGE 0x0D
86 #define HIDPP_REGISTER_PROFILE 0x0F
87 #define HIDPP_REGISTER_LED_STATUS 0x51
88 #define HIDPP_REGISTER_LED_INTENSITY 0x54
89 #define HIDPP_REGISTER_LED_COLOR 0x57
90 #define HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS 0x61
91 #define HIDPP_REGISTER_CURRENT_RESOLUTION 0x63
92 #define HIDPP_REGISTER_USB_REFRESH_RATE 0x64
93 #define HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT 0xA0
94 #define HIDPP_REGISTER_HOT_CONTROL 0xA1
95 #define HIDPP_REGISTER_READ_MEMORY 0xA2
96 #define HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION 0xB2
97 #define HIDPP_REGISTER_PAIRING_INFORMATION 0xB5
98 #define HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE 0xF0
99 #define HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION 0xF1
100
101 /*
102 * HID++2.0 error codes
103 */
104 #define HIDPP_ERROR_CODE_NO_ERROR 0x00
105 #define HIDPP_ERROR_CODE_UNKNOWN 0x01
106 #define HIDPP_ERROR_CODE_INVALID_ARGUMENT 0x02
107 #define HIDPP_ERROR_CODE_OUT_OF_RANGE 0x03
108 #define HIDPP_ERROR_CODE_HW_ERROR 0x04
109 #define HIDPP_ERROR_CODE_LOGITECH_INTERNAL 0x05
110 #define HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX 0x06
111 #define HIDPP_ERROR_CODE_INVALID_FUNCTION_ID 0x07
112 #define HIDPP_ERROR_CODE_BUSY 0x08
113 #define HIDPP_ERROR_CODE_UNSUPPORTED 0x09
114
115 /*
116 * HID++2.0 features
117 */
118 #define HIDPP_FEATURE_ROOT 0x0000
119 #define HIDPP_FEATURE_I_FEATURE_SET 0x0001
120 #define HIDPP_FEATURE_I_FIRMWARE_INFO 0x0003
121 #define HIDPP_FEATURE_GET_DEVICE_NAME_TYPE 0x0005
122 #define HIDPP_FEATURE_DFU_CONTROL 0x00c1
123 #define HIDPP_FEATURE_DFU_CONTROL_SIGNED 0x00c2
124 #define HIDPP_FEATURE_DFU 0x00d0
125 #define HIDPP_FEATURE_BATTERY_LEVEL_STATUS 0x1000
126 #define HIDPP_FEATURE_KBD_REPROGRAMMABLE_KEYS 0x1b00
127 #define HIDPP_FEATURE_SPECIAL_KEYS_BUTTONS 0x1b04
128 #define HIDPP_FEATURE_MOUSE_POINTER_BASIC 0x2200
129 #define HIDPP_FEATURE_ADJUSTABLE_DPI 0x2201
130 #define HIDPP_FEATURE_ADJUSTABLE_REPORT_RATE 0x8060
131 #define HIDPP_FEATURE_COLOR_LED_EFFECTS 0x8070
132 #define HIDPP_FEATURE_ONBOARD_PROFILES 0x8100
133 #define HIDPP_FEATURE_MOUSE_BUTTON_SPY 0x8110
134
135 #include "fu-unifying-hidpp-msg.h"
136
137 gboolean fu_unifying_hidpp_send (FuIOChannel *self,
138 FuUnifyingHidppMsg *msg,
139 guint timeout,
140 GError **error);
141 gboolean fu_unifying_hidpp_receive (FuIOChannel *self,
142 FuUnifyingHidppMsg *msg,
143 guint timeout,
144 GError **error);
145 gboolean fu_unifying_hidpp_transfer (FuIOChannel *self,
146 FuUnifyingHidppMsg *msg,
147 GError **error);
+0
-1027
plugins/unifying/fu-unifying-peripheral.c less more
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-unifying-common.h"
11 #include "fu-unifying-peripheral.h"
12 #include "fu-unifying-hidpp.h"
13
14 struct _FuUnifyingPeripheral
15 {
16 FuUdevDevice parent_instance;
17 guint8 battery_level;
18 guint8 cached_fw_entity;
19 guint8 hidpp_id;
20 guint8 hidpp_version;
21 gboolean is_updatable;
22 gboolean is_active;
23 FuIOChannel *io_channel;
24 GPtrArray *feature_index; /* of FuUnifyingHidppMap */
25 };
26
27 typedef struct {
28 guint8 idx;
29 guint16 feature;
30 } FuUnifyingHidppMap;
31
32 G_DEFINE_TYPE (FuUnifyingPeripheral, fu_unifying_peripheral, FU_TYPE_UDEV_DEVICE)
33
34 typedef enum {
35 FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD,
36 FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL,
37 FU_UNIFYING_PERIPHERAL_KIND_NUMPAD,
38 FU_UNIFYING_PERIPHERAL_KIND_MOUSE,
39 FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD,
40 FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL,
41 FU_UNIFYING_PERIPHERAL_KIND_PRESENTER,
42 FU_UNIFYING_PERIPHERAL_KIND_RECEIVER,
43 FU_UNIFYING_PERIPHERAL_KIND_LAST
44 } FuUnifyingPeripheralKind;
45
46 static const gchar *
47 fu_unifying_peripheral_get_icon (FuUnifyingPeripheralKind kind)
48 {
49 if (kind == FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD)
50 return "input-keyboard";
51 if (kind == FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL)
52 return "pda"; // ish
53 if (kind == FU_UNIFYING_PERIPHERAL_KIND_NUMPAD)
54 return "input-dialpad";
55 if (kind == FU_UNIFYING_PERIPHERAL_KIND_MOUSE)
56 return "input-mouse";
57 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD)
58 return "input-touchpad";
59 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL)
60 return "input-mouse"; // ish
61 if (kind == FU_UNIFYING_PERIPHERAL_KIND_PRESENTER)
62 return "pda"; // ish
63 if (kind == FU_UNIFYING_PERIPHERAL_KIND_RECEIVER)
64 return "preferences-desktop-keyboard";
65 return NULL;
66 }
67
68 static const gchar *
69 fu_unifying_peripheral_get_summary (FuUnifyingPeripheralKind kind)
70 {
71 if (kind == FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD)
72 return "Unifying Keyboard";
73 if (kind == FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL)
74 return "Unifying Remote Control";
75 if (kind == FU_UNIFYING_PERIPHERAL_KIND_NUMPAD)
76 return "Unifying Number Pad";
77 if (kind == FU_UNIFYING_PERIPHERAL_KIND_MOUSE)
78 return "Unifying Mouse";
79 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD)
80 return "Unifying Touchpad";
81 if (kind == FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL)
82 return "Unifying Trackball";
83 if (kind == FU_UNIFYING_PERIPHERAL_KIND_PRESENTER)
84 return "Unifying Presenter";
85 if (kind == FU_UNIFYING_PERIPHERAL_KIND_RECEIVER)
86 return "Unifying Receiver";
87 return NULL;
88 }
89
90 static const gchar *
91 fu_unifying_hidpp_feature_to_string (guint16 feature)
92 {
93 if (feature == HIDPP_FEATURE_ROOT)
94 return "Root";
95 if (feature == HIDPP_FEATURE_I_FIRMWARE_INFO)
96 return "IFirmwareInfo";
97 if (feature == HIDPP_FEATURE_GET_DEVICE_NAME_TYPE)
98 return "GetDevicenameType";
99 if (feature == HIDPP_FEATURE_BATTERY_LEVEL_STATUS)
100 return "BatteryLevelStatus";
101 if (feature == HIDPP_FEATURE_DFU_CONTROL)
102 return "DfuControl";
103 if (feature == HIDPP_FEATURE_DFU_CONTROL_SIGNED)
104 return "DfuControlSigned";
105 if (feature == HIDPP_FEATURE_DFU)
106 return "Dfu";
107 return NULL;
108 }
109
110 static void
111 fu_unifying_peripheral_refresh_updatable (FuUnifyingPeripheral *self)
112 {
113 /* device can only be upgraded if it is capable, and active */
114 if (self->is_updatable && self->is_active) {
115 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
116 return;
117 }
118 fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
119 }
120
121 static gboolean
122 fu_unifying_peripheral_ping (FuUnifyingPeripheral *self, GError **error)
123 {
124 gdouble version;
125 g_autoptr(GError) error_local = NULL;
126 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
127
128 /* handle failure */
129 msg->report_id = HIDPP_REPORT_ID_SHORT;
130 msg->device_id = self->hidpp_id;
131 msg->sub_id = 0x00; /* rootIndex */
132 msg->function_id = 0x01 << 4; /* ping */
133 msg->data[0] = 0x00;
134 msg->data[1] = 0x00;
135 msg->data[2] = 0xaa; /* user-selected value */
136 msg->hidpp_version = self->hidpp_version;
137 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) {
138 if (g_error_matches (error_local,
139 G_IO_ERROR,
140 G_IO_ERROR_NOT_SUPPORTED)) {
141 self->hidpp_version = 1;
142 return TRUE;
143 }
144 if (g_error_matches (error_local,
145 G_IO_ERROR,
146 G_IO_ERROR_HOST_UNREACHABLE)) {
147 self->is_active = FALSE;
148 fu_unifying_peripheral_refresh_updatable (self);
149 return TRUE;
150 }
151 g_set_error (error,
152 G_IO_ERROR,
153 G_IO_ERROR_FAILED,
154 "failed to ping %s: %s",
155 fu_device_get_name (FU_DEVICE (self)),
156 error_local->message);
157 return FALSE;
158 }
159
160 /* device no longer asleep */
161 self->is_active = TRUE;
162 fu_unifying_peripheral_refresh_updatable (self);
163
164 /* if the HID++ ID is unset, grab it from the reply */
165 if (self->hidpp_id == HIDPP_DEVICE_ID_UNSET) {
166 self->hidpp_id = msg->device_id;
167 g_debug ("HID++ ID is %02x", self->hidpp_id);
168 }
169
170 /* format version in BCD format */
171 version = (gdouble) msg->data[0] + ((gdouble) msg->data[1]) / 100.f;
172 self->hidpp_version = (guint) version;
173
174 /* success */
175 return TRUE;
176 }
177
178 static gboolean
179 fu_unifying_peripheral_close (FuDevice *device, GError **error)
180 {
181 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
182 if (!fu_io_channel_shutdown (self->io_channel, error))
183 return FALSE;
184 g_clear_object (&self->io_channel);
185 return TRUE;
186 }
187
188 static gboolean
189 fu_unifying_peripheral_poll (FuDevice *device, GError **error)
190 {
191 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
192 const guint timeout = 1; /* ms */
193 g_autoptr(GError) error_local = NULL;
194 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
195 g_autoptr(FuDeviceLocker) locker = NULL;
196
197 /* open */
198 locker = fu_device_locker_new (self, error);
199 if (locker == NULL)
200 return FALSE;
201
202 /* flush pending data */
203 msg->device_id = self->hidpp_id;
204 msg->hidpp_version = self->hidpp_version;
205 if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) {
206 if (!g_error_matches (error_local,
207 G_IO_ERROR,
208 G_IO_ERROR_TIMED_OUT)) {
209 g_warning ("failed to get pending read: %s", error_local->message);
210 return TRUE;
211 }
212 /* no data to receive */
213 g_clear_error (&error_local);
214 }
215
216 /* just ping */
217 if (!fu_unifying_peripheral_ping (self, &error_local)) {
218 g_warning ("failed to ping device: %s", error_local->message);
219 return TRUE;
220 }
221
222 /* this is the first time the device has been active */
223 if (self->feature_index->len == 0) {
224 fu_device_probe_invalidate (FU_DEVICE (self));
225 if (!fu_device_setup (FU_DEVICE (self), error))
226 return FALSE;
227 }
228
229 /* success */
230 return TRUE;
231 }
232
233 static gboolean
234 fu_unifying_peripheral_open (FuDevice *device, GError **error)
235 {
236 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
237 GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
238 const gchar *devpath = g_udev_device_get_device_file (udev_device);
239
240 /* open */
241 self->io_channel = fu_io_channel_new_file (devpath, error);
242 if (self->io_channel == NULL)
243 return FALSE;
244
245 return TRUE;
246 }
247
248 static void
249 fu_unifying_hidpp_map_to_string (FuUnifyingHidppMap *map, guint idt, GString *str)
250 {
251 g_autofree gchar *title = g_strdup_printf ("Feature%02x", map->idx);
252 g_autofree gchar *tmp = g_strdup_printf ("%s [0x%04x]",
253 fu_unifying_hidpp_feature_to_string (map->feature),
254 map->feature);
255 fu_common_string_append_kv (str, idt, title, tmp);
256 }
257
258 static void
259 fu_unifying_peripheral_to_string (FuDevice *device, guint idt, GString *str)
260 {
261 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
262 fu_common_string_append_ku (str, idt, "HidppVersion", self->hidpp_version);
263 fu_common_string_append_kx (str, idt, "HidppId", self->hidpp_id);
264 fu_common_string_append_ku (str, idt, "BatteryLevel", self->battery_level);
265 fu_common_string_append_kb (str, idt, "IsUpdatable", self->is_updatable);
266 fu_common_string_append_kb (str, idt, "IsActive", self->is_active);
267 for (guint i = 0; i < self->feature_index->len; i++) {
268 FuUnifyingHidppMap *map = g_ptr_array_index (self->feature_index, i);
269 fu_unifying_hidpp_map_to_string (map, idt, str);
270 }
271 }
272
273 static guint8
274 fu_unifying_peripheral_feature_get_idx (FuUnifyingPeripheral *self, guint16 feature)
275 {
276 for (guint i = 0; i < self->feature_index->len; i++) {
277 FuUnifyingHidppMap *map = g_ptr_array_index (self->feature_index, i);
278 if (map->feature == feature)
279 return map->idx;
280 }
281 return 0x00;
282 }
283
284 static gboolean
285 fu_unifying_peripheral_fetch_firmware_info (FuUnifyingPeripheral *self, GError **error)
286 {
287 guint8 idx;
288 guint8 entity_count;
289 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
290
291 /* get the feature index */
292 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_I_FIRMWARE_INFO);
293 if (idx == 0x00)
294 return TRUE;
295
296 /* get the entity count */
297 msg->report_id = HIDPP_REPORT_ID_SHORT;
298 msg->device_id = self->hidpp_id;
299 msg->sub_id = idx;
300 msg->function_id = 0x00 << 4; /* getCount */
301 msg->hidpp_version = self->hidpp_version;
302 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
303 g_prefix_error (error, "failed to get firmware count: ");
304 return FALSE;
305 }
306 entity_count = msg->data[0];
307 g_debug ("firmware entity count is %u", entity_count);
308
309 /* get firmware, bootloader, hardware versions */
310 for (guint8 i = 0; i < entity_count; i++) {
311 guint16 build;
312 g_autofree gchar *version = NULL;
313 g_autofree gchar *name = NULL;
314
315 msg->report_id = HIDPP_REPORT_ID_SHORT;
316 msg->device_id = self->hidpp_id;
317 msg->sub_id = idx;
318 msg->function_id = 0x01 << 4; /* getInfo */
319 msg->data[0] = i;
320 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
321 g_prefix_error (error, "failed to get firmware info: ");
322 return FALSE;
323 }
324 if (msg->data[1] == 0x00 &&
325 msg->data[2] == 0x00 &&
326 msg->data[3] == 0x00 &&
327 msg->data[4] == 0x00 &&
328 msg->data[5] == 0x00 &&
329 msg->data[6] == 0x00 &&
330 msg->data[7] == 0x00) {
331 g_debug ("no version set for entity %u", i);
332 continue;
333 }
334 name = g_strdup_printf ("%c%c%c",
335 msg->data[1],
336 msg->data[2],
337 msg->data[3]);
338 build = ((guint16) msg->data[6]) << 8 | msg->data[7];
339 version = fu_unifying_format_version (name,
340 msg->data[4],
341 msg->data[5],
342 build);
343 g_debug ("firmware entity 0x%02x version is %s", i, version);
344 if (msg->data[0] == 0) {
345 fu_device_set_version (FU_DEVICE (self), version,
346 FWUPD_VERSION_FORMAT_PLAIN);
347 self->cached_fw_entity = i;
348 } else if (msg->data[0] == 1) {
349 fu_device_set_version_bootloader (FU_DEVICE (self), version);
350 } else if (msg->data[0] == 2) {
351 fu_device_set_metadata (FU_DEVICE (self), "version-hw", version);
352 }
353 }
354
355 /* not an error, the device just doesn't support this */
356 return TRUE;
357 }
358
359 static gboolean
360 fu_unifying_peripheral_fetch_battery_level (FuUnifyingPeripheral *self, GError **error)
361 {
362 /* try using HID++2.0 */
363 if (self->hidpp_version >= 2.f) {
364 guint8 idx;
365 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_BATTERY_LEVEL_STATUS);
366 if (idx != 0x00) {
367 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
368 msg->report_id = HIDPP_REPORT_ID_SHORT;
369 msg->device_id = self->hidpp_id;
370 msg->sub_id = idx;
371 msg->function_id = 0x00; /* GetBatteryLevelStatus */
372 msg->hidpp_version = self->hidpp_version;
373 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
374 g_prefix_error (error, "failed to get battery info: ");
375 return FALSE;
376 }
377 if (msg->data[0] != 0x00)
378 self->battery_level = msg->data[0];
379 return TRUE;
380 }
381 }
382
383 /* try HID++1.0 battery mileage */
384 if (self->hidpp_version == 1.f) {
385 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
386 msg->report_id = HIDPP_REPORT_ID_SHORT;
387 msg->device_id = self->hidpp_id;
388 msg->sub_id = HIDPP_SUBID_GET_REGISTER;
389 msg->function_id = HIDPP_REGISTER_BATTERY_MILEAGE;
390 msg->hidpp_version = self->hidpp_version;
391 if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) {
392 if (msg->data[0] != 0x00)
393 self->battery_level = msg->data[0];
394 return TRUE;
395 }
396
397 /* try HID++1.0 battery status instead */
398 msg->function_id = HIDPP_REGISTER_BATTERY_STATUS;
399 if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) {
400 switch (msg->data[0]) {
401 case 1: /* 0 - 10 */
402 self->battery_level = 5;
403 break;
404 case 3: /* 11 - 30 */
405 self->battery_level = 20;
406 break;
407 case 5: /* 31 - 80 */
408 self->battery_level = 55;
409 break;
410 case 7: /* 81 - 100 */
411 self->battery_level = 90;
412 break;
413 default:
414 g_warning ("unknown battery percentage: 0x%02x",
415 msg->data[0]);
416 break;
417 }
418 return TRUE;
419 }
420 }
421
422 /* not an error, the device just doesn't support any of the methods */
423 return TRUE;
424 }
425
426 static gboolean
427 fu_unifying_hidpp_feature_search (FuDevice *device, guint16 feature, GError **error)
428 {
429 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
430 FuUnifyingHidppMap *map;
431 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
432
433 /* find the idx for the feature */
434 msg->report_id = HIDPP_REPORT_ID_SHORT;
435 msg->device_id = self->hidpp_id;
436 msg->sub_id = 0x00; /* rootIndex */
437 msg->function_id = 0x00 << 4; /* getFeature */
438 msg->data[0] = feature >> 8;
439 msg->data[1] = feature;
440 msg->data[2] = 0x00;
441 msg->hidpp_version = self->hidpp_version;
442 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
443 g_prefix_error (error,
444 "failed to get idx for feature %s [0x%04x]: ",
445 fu_unifying_hidpp_feature_to_string (feature), feature);
446 return FALSE;
447 }
448
449 /* zero index */
450 if (msg->data[0] == 0x00) {
451 g_set_error (error,
452 G_IO_ERROR,
453 G_IO_ERROR_NOT_SUPPORTED,
454 "feature %s [0x%04x] not found",
455 fu_unifying_hidpp_feature_to_string (feature), feature);
456 return FALSE;
457 }
458
459 /* add to map */
460 map = g_new0 (FuUnifyingHidppMap, 1);
461 map->idx = msg->data[0];
462 map->feature = feature;
463 g_ptr_array_add (self->feature_index, map);
464 g_debug ("added feature %s [0x%04x] as idx %02x",
465 fu_unifying_hidpp_feature_to_string (feature), feature, map->idx);
466 return TRUE;
467 }
468
469 static gboolean
470 fu_unifying_peripheral_probe (FuUdevDevice *device, GError **error)
471 {
472 g_autofree gchar *devid = NULL;
473
474 /* set the physical ID */
475 if (!fu_udev_device_set_physical_id (device, "hid", error))
476 return FALSE;
477
478 /* nearly... */
479 fu_device_set_vendor_id (FU_DEVICE (device), "USB:0x046D");
480
481 /* this is a non-standard extension */
482 devid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X",
483 fu_udev_device_get_vendor (device),
484 fu_udev_device_get_model (device));
485 fu_device_add_instance_id (FU_DEVICE (device), devid);
486 return TRUE;
487 }
488
489 static gboolean
490 fu_unifying_peripheral_setup (FuDevice *device, GError **error)
491 {
492 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
493 guint8 idx;
494 const guint16 map_features[] = {
495 HIDPP_FEATURE_GET_DEVICE_NAME_TYPE,
496 HIDPP_FEATURE_I_FIRMWARE_INFO,
497 HIDPP_FEATURE_BATTERY_LEVEL_STATUS,
498 HIDPP_FEATURE_DFU_CONTROL,
499 HIDPP_FEATURE_DFU_CONTROL_SIGNED,
500 HIDPP_FEATURE_DFU,
501 HIDPP_FEATURE_ROOT };
502
503 /* ping device to get HID++ version */
504 if (!fu_unifying_peripheral_ping (self, error))
505 return FALSE;
506
507 /* add known root for HID++2.0 */
508 g_ptr_array_set_size (self->feature_index, 0);
509 if (self->hidpp_version >= 2.f) {
510 FuUnifyingHidppMap *map = g_new0 (FuUnifyingHidppMap, 1);
511 map->idx = 0x00;
512 map->feature = HIDPP_FEATURE_ROOT;
513 g_ptr_array_add (self->feature_index, map);
514 }
515
516 /* map some *optional* HID++2.0 features we might use */
517 for (guint i = 0; map_features[i] != HIDPP_FEATURE_ROOT; i++) {
518 g_autoptr(GError) error_local = NULL;
519 if (!fu_unifying_hidpp_feature_search (device,
520 map_features[i],
521 &error_local)) {
522 g_debug ("%s", error_local->message);
523 if (g_error_matches (error_local,
524 G_IO_ERROR,
525 G_IO_ERROR_TIMED_OUT) ||
526 g_error_matches (error_local,
527 G_IO_ERROR,
528 G_IO_ERROR_HOST_UNREACHABLE)) {
529 /* timed out, so not trying any more */
530 break;
531 }
532 }
533 }
534
535 /* get the firmware information */
536 if (!fu_unifying_peripheral_fetch_firmware_info (self, error))
537 return FALSE;
538
539 /* get the battery level */
540 if (!fu_unifying_peripheral_fetch_battery_level (self, error))
541 return FALSE;
542
543 /* try using HID++2.0 */
544 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_GET_DEVICE_NAME_TYPE);
545 if (idx != 0x00) {
546 const gchar *tmp;
547 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
548 msg->report_id = HIDPP_REPORT_ID_SHORT;
549 msg->device_id = self->hidpp_id;
550 msg->sub_id = idx;
551 msg->function_id = 0x02 << 4; /* getDeviceType */
552 msg->hidpp_version = self->hidpp_version;
553 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
554 g_prefix_error (error, "failed to get device type: ");
555 return FALSE;
556 }
557
558 /* add nice-to-have data */
559 tmp = fu_unifying_peripheral_get_summary (msg->data[0]);
560 if (tmp != NULL)
561 fu_device_set_summary (FU_DEVICE (device), tmp);
562 tmp = fu_unifying_peripheral_get_icon (msg->data[0]);
563 if (tmp != NULL)
564 fu_device_add_icon (FU_DEVICE (device), tmp);
565 }
566 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL);
567 if (idx != 0x00) {
568 self->is_updatable = TRUE;
569 fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
570 }
571 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED);
572 if (idx != 0x00) {
573 /* check the feature is available */
574 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
575 msg->report_id = HIDPP_REPORT_ID_SHORT;
576 msg->device_id = self->hidpp_id;
577 msg->sub_id = idx;
578 msg->function_id = 0x00 << 4; /* getDfuStatus */
579 msg->hidpp_version = self->hidpp_version;
580 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
581 g_prefix_error (error, "failed to get DFU status: ");
582 return FALSE;
583 }
584 if ((msg->data[2] & 0x01) > 0) {
585 g_warning ("DFU mode not available");
586 } else {
587 self->is_updatable = TRUE;
588 fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
589 }
590 }
591 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
592 if (idx != 0x00) {
593 self->is_updatable = TRUE;
594 fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
595 if (fu_device_get_version (device) == NULL) {
596 g_debug ("repairing device in bootloader mode");
597 fu_device_set_version (FU_DEVICE (device),
598 "MPK00.00_B0000",
599 FWUPD_VERSION_FORMAT_PLAIN);
600 }
601 }
602
603 /* this device may have changed state */
604 fu_unifying_peripheral_refresh_updatable (self);
605
606 /* poll for pings to track active state */
607 fu_device_set_poll_interval (device, 30000);
608 return TRUE;
609 }
610
611 static gboolean
612 fu_unifying_peripheral_detach (FuDevice *device, GError **error)
613 {
614 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
615 guint8 idx;
616 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
617
618 /* this requires user action */
619 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL);
620 if (idx != 0x00) {
621 msg->report_id = HIDPP_REPORT_ID_LONG;
622 msg->device_id = self->hidpp_id;
623 msg->sub_id = idx;
624 msg->function_id = 0x01 << 4; /* setDfuControl */
625 msg->data[0] = 0x01; /* enterDfu */
626 msg->data[1] = 0x00; /* dfuControlParam */
627 msg->data[2] = 0x00; /* unused */
628 msg->data[3] = 0x00; /* unused */
629 msg->data[4] = 'D';
630 msg->data[5] = 'F';
631 msg->data[6] = 'U';
632 msg->hidpp_version = self->hidpp_version;
633 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID |
634 FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
635 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
636 g_prefix_error (error, "failed to put device into DFU mode: ");
637 return FALSE;
638 }
639 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
640 g_set_error (error,
641 FWUPD_ERROR,
642 FWUPD_ERROR_NEEDS_USER_ACTION,
643 "%s needs to be manually restarted to complete the update."
644 "Please unplug and reconnect the device and re-run the update",
645 fu_device_get_name (device));
646 return FALSE;
647 }
648
649 /* this can reboot all by itself */
650 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED);
651 if (idx != 0x00) {
652 msg->report_id = HIDPP_REPORT_ID_LONG;
653 msg->device_id = self->hidpp_id;
654 msg->sub_id = idx;
655 msg->function_id = 0x01 << 4; /* setDfuControl */
656 msg->data[0] = 0x01; /* startDfu */
657 msg->data[1] = 0x00; /* dfuControlParam */
658 msg->data[2] = 0x00; /* unused */
659 msg->data[3] = 0x00; /* unused */
660 msg->data[4] = 'D';
661 msg->data[5] = 'F';
662 msg->data[6] = 'U';
663 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID;
664 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
665 g_prefix_error (error, "failed to put device into DFU mode: ");
666 return FALSE;
667 }
668 return fu_unifying_peripheral_setup (FU_DEVICE (self), error);
669 }
670
671 /* we don't know how */
672 g_set_error (error,
673 G_IO_ERROR,
674 G_IO_ERROR_FAILED,
675 "no method to detach");
676 return FALSE;
677 }
678
679 static gboolean
680 fu_unifying_peripheral_check_status (guint8 status, GError **error)
681 {
682 switch (status & 0x7f) {
683 case 0x00:
684 g_set_error (error,
685 G_IO_ERROR,
686 G_IO_ERROR_FAILED,
687 "invalid status value 0x%02x",
688 status);
689 break;
690 case 0x01: /* packet success */
691 case 0x02: /* DFU success */
692 case 0x05: /* DFU success: entity restart required */
693 case 0x06: /* DFU success: system restart required */
694 /* success */
695 return TRUE;
696 break;
697 case 0x03:
698 g_set_error_literal (error,
699 G_IO_ERROR,
700 G_IO_ERROR_PENDING,
701 "wait for event (command in progress)");
702 break;
703 case 0x04:
704 case 0x10: /* unknown */
705 g_set_error_literal (error,
706 G_IO_ERROR,
707 G_IO_ERROR_FAILED,
708 "generic error");
709 break;
710 case 0x11:
711 g_set_error_literal (error,
712 G_IO_ERROR,
713 G_IO_ERROR_FAILED,
714 "bad voltage (power too low?)");
715 break;
716 case 0x12:
717 case 0x14: /* bad magic string */
718 case 0x21: /* bad firmware */
719 g_set_error_literal (error,
720 G_IO_ERROR,
721 G_IO_ERROR_FAILED,
722 "unsupported firmware");
723 break;
724 case 0x13:
725 g_set_error_literal (error,
726 G_IO_ERROR,
727 G_IO_ERROR_FAILED,
728 "unsupported encryption mode");
729 break;
730 case 0x15:
731 g_set_error_literal (error,
732 G_IO_ERROR,
733 G_IO_ERROR_FAILED,
734 "erase failure");
735 break;
736 case 0x16:
737 g_set_error_literal (error,
738 G_IO_ERROR,
739 G_IO_ERROR_FAILED,
740 "DFU not started");
741 break;
742 case 0x17:
743 g_set_error_literal (error,
744 G_IO_ERROR,
745 G_IO_ERROR_FAILED,
746 "bad sequence number");
747 break;
748 case 0x18:
749 g_set_error_literal (error,
750 G_IO_ERROR,
751 G_IO_ERROR_FAILED,
752 "unsupported command");
753 break;
754 case 0x19:
755 g_set_error_literal (error,
756 G_IO_ERROR,
757 G_IO_ERROR_FAILED,
758 "command in progress");
759 break;
760 case 0x1a:
761 g_set_error_literal (error,
762 G_IO_ERROR,
763 G_IO_ERROR_FAILED,
764 "address out of range");
765 break;
766 case 0x1b:
767 g_set_error_literal (error,
768 G_IO_ERROR,
769 G_IO_ERROR_FAILED,
770 "unaligned address");
771 break;
772 case 0x1c:
773 g_set_error_literal (error,
774 G_IO_ERROR,
775 G_IO_ERROR_FAILED,
776 "bad size");
777 break;
778 case 0x1d:
779 g_set_error_literal (error,
780 G_IO_ERROR,
781 G_IO_ERROR_FAILED,
782 "missing program data");
783 break;
784 case 0x1e:
785 g_set_error_literal (error,
786 G_IO_ERROR,
787 G_IO_ERROR_FAILED,
788 "missing check data");
789 break;
790 case 0x1f:
791 g_set_error_literal (error,
792 G_IO_ERROR,
793 G_IO_ERROR_FAILED,
794 "program failed to write");
795 break;
796 case 0x20:
797 g_set_error_literal (error,
798 G_IO_ERROR,
799 G_IO_ERROR_FAILED,
800 "program failed to verify");
801 break;
802 case 0x22:
803 g_set_error_literal (error,
804 G_IO_ERROR,
805 G_IO_ERROR_FAILED,
806 "firmware check failure");
807 break;
808 case 0x23:
809 g_set_error_literal (error,
810 G_IO_ERROR,
811 G_IO_ERROR_FAILED,
812 "blocked command (restart required)");
813 break;
814 default:
815 g_set_error (error,
816 G_IO_ERROR,
817 G_IO_ERROR_FAILED,
818 "unhandled status value 0x%02x",
819 status);
820 break;
821 }
822 return FALSE;
823 }
824
825 static gboolean
826 fu_unifying_peripheral_write_firmware_pkt (FuUnifyingPeripheral *self,
827 guint8 idx,
828 guint8 cmd,
829 const guint8 *data,
830 GError **error)
831 {
832 guint32 packet_cnt;
833 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
834 g_autoptr(GError) error_local = NULL;
835
836 /* send firmware data */
837 msg->report_id = HIDPP_REPORT_ID_LONG;
838 msg->device_id = self->hidpp_id;
839 msg->sub_id = idx;
840 msg->function_id = cmd << 4; /* dfuStart or dfuCmdDataX */
841 msg->hidpp_version = self->hidpp_version;
842 memcpy (msg->data, data, 16);
843 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) {
844 g_prefix_error (error, "failed to supply program data: ");
845 return FALSE;
846 }
847
848 /* check error */
849 packet_cnt = fu_common_read_uint32 (msg->data, G_BIG_ENDIAN);
850 g_debug ("packet_cnt=0x%04x", packet_cnt);
851 if (fu_unifying_peripheral_check_status (msg->data[4], &error_local))
852 return TRUE;
853
854 /* fatal error */
855 if (!g_error_matches (error_local,
856 G_IO_ERROR,
857 G_IO_ERROR_PENDING)) {
858 g_set_error_literal (error,
859 G_IO_ERROR,
860 G_IO_ERROR_FAILED,
861 error_local->message);
862 return FALSE;
863 }
864
865 /* wait for the HID++ notification */
866 g_debug ("ignoring: %s", error_local->message);
867 for (guint retry = 0; retry < 10; retry++) {
868 g_autoptr(FuUnifyingHidppMsg) msg2 = fu_unifying_hidpp_msg_new ();
869 msg2->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID;
870 if (!fu_unifying_hidpp_receive (self->io_channel, msg2, 15000, error))
871 return FALSE;
872 if (fu_unifying_hidpp_msg_is_reply (msg, msg2)) {
873 g_autoptr(GError) error2 = NULL;
874 if (!fu_unifying_peripheral_check_status (msg2->data[4], &error2)) {
875 g_debug ("got %s, waiting a bit longer", error2->message);
876 continue;
877 }
878 return TRUE;
879 } else {
880 g_debug ("got wrong packet, continue to wait...");
881 }
882 }
883
884 /* nothing in the queue */
885 g_set_error_literal (error,
886 G_IO_ERROR,
887 G_IO_ERROR_FAILED,
888 "failed to get event after timeout");
889 return FALSE;
890 }
891
892 static gboolean
893 fu_unifying_peripheral_write_firmware (FuDevice *device,
894 FuFirmware *firmware,
895 FwupdInstallFlags flags,
896 GError **error)
897 {
898 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
899 gsize sz = 0;
900 const guint8 *data;
901 guint8 cmd = 0x04;
902 guint8 idx;
903 g_autoptr(GBytes) fw = NULL;
904
905 /* if we're in bootloader mode, we should be able to get this feature */
906 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
907 if (idx == 0x00) {
908 g_set_error (error,
909 G_IO_ERROR,
910 G_IO_ERROR_FAILED,
911 "no DFU feature available");
912 return FALSE;
913 }
914
915 /* get default image */
916 fw = fu_firmware_get_image_default_bytes (firmware, error);
917 if (fw == NULL)
918 return FALSE;
919
920 /* flash hardware */
921 data = g_bytes_get_data (fw, &sz);
922 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
923 for (gsize i = 0; i < sz / 16; i++) {
924
925 /* send packet and wait for reply */
926 g_debug ("send data at addr=0x%04x", (guint) i * 16);
927 if (!fu_unifying_peripheral_write_firmware_pkt (self,
928 idx,
929 cmd,
930 data + (i * 16),
931 error)) {
932 g_prefix_error (error,
933 "failed to write @0x%04x: ",
934 (guint) i * 16);
935 return FALSE;
936 }
937
938 /* use sliding window */
939 cmd = (cmd + 1) % 4;
940
941 /* update progress-bar */
942 fu_device_set_progress_full (device, i * 16, sz);
943 }
944
945 return TRUE;
946 }
947
948 static gboolean
949 fu_unifying_peripheral_attach (FuDevice *device, GError **error)
950 {
951 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device);
952 guint8 idx;
953 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
954
955 /* if we're in bootloader mode, we should be able to get this feature */
956 idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU);
957 if (idx == 0x00) {
958 g_set_error (error,
959 G_IO_ERROR,
960 G_IO_ERROR_FAILED,
961 "no DFU feature available");
962 return FALSE;
963 }
964
965 /* reboot back into firmware mode */
966 msg->report_id = HIDPP_REPORT_ID_SHORT;
967 msg->device_id = self->hidpp_id;
968 msg->sub_id = idx;
969 msg->function_id = 0x05 << 4; /* restart */
970 msg->data[0] = self->cached_fw_entity; /* fwEntity */
971 msg->hidpp_version = self->hidpp_version;
972 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID |
973 FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred?
974 FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
975 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
976 g_prefix_error (error, "failed to restart device: ");
977 return FALSE;
978 }
979
980 /* reprobe */
981 if (!fu_unifying_peripheral_setup (device, error))
982 return FALSE;
983
984 /* success */
985 return TRUE;
986 }
987
988 static void
989 fu_unifying_peripheral_finalize (GObject *object)
990 {
991 FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (object);
992 g_ptr_array_unref (self->feature_index);
993 G_OBJECT_CLASS (fu_unifying_peripheral_parent_class)->finalize (object);
994 }
995
996 static void
997 fu_unifying_peripheral_class_init (FuUnifyingPeripheralClass *klass)
998 {
999 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
1000 FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass);
1001 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1002
1003 object_class->finalize = fu_unifying_peripheral_finalize;
1004 klass_device->setup = fu_unifying_peripheral_setup;
1005 klass_device->open = fu_unifying_peripheral_open;
1006 klass_device->close = fu_unifying_peripheral_close;
1007 klass_device->write_firmware = fu_unifying_peripheral_write_firmware;
1008 klass_device->attach = fu_unifying_peripheral_attach;
1009 klass_device->detach = fu_unifying_peripheral_detach;
1010 klass_device->poll = fu_unifying_peripheral_poll;
1011 klass_device->to_string = fu_unifying_peripheral_to_string;
1012 klass_device_udev->probe = fu_unifying_peripheral_probe;
1013 }
1014
1015 static void
1016 fu_unifying_peripheral_init (FuUnifyingPeripheral *self)
1017 {
1018 self->hidpp_id = HIDPP_DEVICE_ID_UNSET;
1019 self->feature_index = g_ptr_array_new_with_free_func (g_free);
1020 fu_device_add_parent_guid (FU_DEVICE (self), "HIDRAW\\VEN_046D&DEV_C52B");
1021 fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
1022
1023 /* there are a lot of unifying peripherals, but not all respond
1024 * well to opening -- so limit to ones with issued updates */
1025 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ONLY_SUPPORTED);
1026 }
+0
-12
plugins/unifying/fu-unifying-peripheral.h less more
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-udev-device.h"
9
10 #define FU_TYPE_UNIFYING_PERIPHERAL (fu_unifying_peripheral_get_type ())
11 G_DECLARE_FINAL_TYPE (FuUnifyingPeripheral, fu_unifying_peripheral, FU, UNIFYING_PERIPHERAL, FuUdevDevice)
+0
-325
plugins/unifying/fu-unifying-runtime.c less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <string.h>
9
10 #include "fu-unifying-common.h"
11 #include "fu-unifying-runtime.h"
12 #include "fu-unifying-hidpp.h"
13
14 struct _FuUnifyingRuntime
15 {
16 FuUdevDevice parent_instance;
17 guint8 version_bl_major;
18 gboolean signed_firmware;
19 FuIOChannel *io_channel;
20 };
21
22 G_DEFINE_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU_TYPE_UDEV_DEVICE)
23
24 #ifndef HAVE_GUDEV_232
25 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
26 #endif
27
28 static void
29 fu_unifying_runtime_to_string (FuDevice *device, guint idt, GString *str)
30 {
31 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
32 fu_common_string_append_kb (str, idt, "SignedFirmware", self->signed_firmware);
33 }
34
35 static gboolean
36 fu_unifying_runtime_enable_notifications (FuUnifyingRuntime *self, GError **error)
37 {
38 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
39 msg->report_id = HIDPP_REPORT_ID_SHORT;
40 msg->device_id = HIDPP_DEVICE_ID_RECEIVER;
41 msg->sub_id = HIDPP_SUBID_SET_REGISTER;
42 msg->function_id = HIDPP_REGISTER_HIDPP_NOTIFICATIONS;
43 msg->data[0] = 0x00;
44 msg->data[1] = 0x05; /* Wireless + SoftwarePresent */
45 msg->data[2] = 0x00;
46 msg->hidpp_version = 1;
47 return fu_unifying_hidpp_transfer (self->io_channel, msg, error);
48 }
49
50 static gboolean
51 fu_unifying_runtime_close (FuDevice *device, GError **error)
52 {
53 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
54 if (!fu_io_channel_shutdown (self->io_channel, error))
55 return FALSE;
56 g_clear_object (&self->io_channel);
57 return TRUE;
58 }
59
60 static gboolean
61 fu_unifying_runtime_poll (FuDevice *device, GError **error)
62 {
63 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
64 const guint timeout = 1; /* ms */
65 g_autoptr(GError) error_local = NULL;
66 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
67 g_autoptr(FuDeviceLocker) locker = NULL;
68
69 /* open */
70 locker = fu_device_locker_new (self, error);
71 if (locker == NULL)
72 return FALSE;
73
74 /* is there any pending data to read */
75 msg->hidpp_version = 1;
76 if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) {
77 if (g_error_matches (error_local,
78 G_IO_ERROR,
79 G_IO_ERROR_TIMED_OUT)) {
80 return TRUE;
81 }
82 g_warning ("failed to get pending read: %s", error_local->message);
83 return TRUE;
84 }
85
86 /* HID++1.0 error */
87 if (!fu_unifying_hidpp_msg_is_error (msg, &error_local)) {
88 g_warning ("failed to get pending read: %s", error_local->message);
89 return TRUE;
90 }
91
92 /* unifying receiver notification */
93 if (msg->report_id == HIDPP_REPORT_ID_SHORT) {
94 switch (msg->sub_id) {
95 case HIDPP_SUBID_DEVICE_CONNECTION:
96 case HIDPP_SUBID_DEVICE_DISCONNECTION:
97 case HIDPP_SUBID_DEVICE_LOCKING_CHANGED:
98 g_debug ("device connection event, do something");
99 break;
100 case HIDPP_SUBID_LINK_QUALITY:
101 g_debug ("ignoring link quality message");
102 break;
103 case HIDPP_SUBID_ERROR_MSG:
104 g_debug ("ignoring link quality message");
105 break;
106 default:
107 g_debug ("unknown SubID %02x", msg->sub_id);
108 break;
109 }
110 }
111 return TRUE;
112 }
113
114 static gboolean
115 fu_unifying_runtime_open (FuDevice *device, GError **error)
116 {
117 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
118 GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
119 const gchar *devpath = g_udev_device_get_device_file (udev_device);
120
121 /* open, but don't block */
122 self->io_channel = fu_io_channel_new_file (devpath, error);
123 if (self->io_channel == NULL)
124 return FALSE;
125
126 /* poll for notifications */
127 fu_device_set_poll_interval (device, 5000);
128
129 /* success */
130 return TRUE;
131 }
132
133 static gboolean
134 fu_unifying_runtime_probe (FuUdevDevice *device, GError **error)
135 {
136 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
137 GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device));
138 guint16 release = 0xffff;
139 g_autoptr(GUdevDevice) udev_parent = NULL;
140
141 /* set the physical ID */
142 if (!fu_udev_device_set_physical_id (device, "usb", error))
143 return FALSE;
144
145 /* generate bootloader-specific GUID */
146 udev_parent = g_udev_device_get_parent_with_subsystem (udev_device,
147 "usb", "usb_device");
148 if (udev_parent != NULL) {
149 const gchar *release_str;
150 release_str = g_udev_device_get_property (udev_parent, "ID_REVISION");
151 if (release_str != NULL)
152 release = g_ascii_strtoull (release_str, NULL, 16);
153 }
154 if (release != 0xffff) {
155 g_autofree gchar *devid2 = NULL;
156 switch (release &= 0xff00) {
157 case 0x1200:
158 /* Nordic */
159 devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
160 (guint) FU_UNIFYING_DEVICE_VID,
161 (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC);
162 fu_device_add_counterpart_guid (FU_DEVICE (device), devid2);
163 self->version_bl_major = 0x01;
164 break;
165 case 0x2400:
166 /* Texas */
167 devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X",
168 (guint) FU_UNIFYING_DEVICE_VID,
169 (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS);
170 fu_device_add_counterpart_guid (FU_DEVICE (device), devid2);
171 self->version_bl_major = 0x03;
172 break;
173 default:
174 g_warning ("bootloader release %04x invalid", release);
175 break;
176 }
177 }
178 return TRUE;
179 }
180
181 static gboolean
182 fu_unifying_runtime_setup_internal (FuDevice *device, GError **error)
183 {
184 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
185 guint8 config[10];
186 g_autofree gchar *version_fw = NULL;
187
188 /* read all 10 bytes of the version register */
189 memset (config, 0x00, sizeof (config));
190 for (guint i = 0x01; i < 0x05; i++) {
191 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
192
193 /* workaround a bug in the 12.01 firmware, which fails with
194 * INVALID_VALUE when reading MCU1_HW_VERSION */
195 if (i == 0x03)
196 continue;
197
198 msg->report_id = HIDPP_REPORT_ID_SHORT;
199 msg->device_id = HIDPP_DEVICE_ID_RECEIVER;
200 msg->sub_id = HIDPP_SUBID_GET_REGISTER;
201 msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION;
202 msg->data[0] = i;
203 msg->hidpp_version = 1;
204 if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) {
205 g_prefix_error (error, "failed to read device config: ");
206 return FALSE;
207 }
208 if (!fu_memcpy_safe (config, sizeof(config), i * 2, /* dst */
209 msg->data, sizeof(msg->data), 0x1, /* src */
210 2, error))
211 return FALSE;
212 }
213
214 /* get firmware version */
215 version_fw = fu_unifying_format_version ("RQR",
216 config[2],
217 config[3],
218 (guint16) config[4] << 8 |
219 config[5]);
220 fu_device_set_version (device, version_fw, FWUPD_VERSION_FORMAT_PLAIN);
221
222 /* get bootloader version */
223 if (self->version_bl_major > 0) {
224 g_autofree gchar *version_bl = NULL;
225 version_bl = fu_unifying_format_version ("BOT",
226 self->version_bl_major,
227 config[8],
228 config[9]);
229 fu_device_set_version_bootloader (FU_DEVICE (device), version_bl);
230
231 /* is the dongle expecting signed firmware */
232 if ((self->version_bl_major == 0x01 && config[8] >= 0x04) ||
233 (self->version_bl_major == 0x03 && config[8] >= 0x02)) {
234 self->signed_firmware = TRUE;
235 }
236 }
237
238 /* enable HID++ notifications */
239 if (!fu_unifying_runtime_enable_notifications (self, error)) {
240 g_prefix_error (error, "failed to enable notifications: ");
241 return FALSE;
242 }
243
244 /* success */
245 return TRUE;
246 }
247
248 static gboolean
249 fu_unifying_runtime_setup (FuDevice *device, GError **error)
250 {
251 g_autoptr(GError) error_local = NULL;
252 for (guint i = 0; i < 5; i++) {
253 /* HID++1.0 devices have to sleep to allow Solaar to talk to
254 * the device first -- we can't use the SwID as this is a
255 * HID++2.0 feature */
256 g_usleep (200*1000);
257 if (fu_unifying_runtime_setup_internal (device, &error_local))
258 return TRUE;
259 if (!g_error_matches (error_local,
260 G_IO_ERROR,
261 G_IO_ERROR_INVALID_DATA)) {
262 g_propagate_error (error, g_steal_pointer (&error_local));
263 return FALSE;
264 }
265 g_clear_error (&error_local);
266 }
267 g_propagate_error (error, g_steal_pointer (&error_local));
268 return FALSE;
269 }
270
271 static gboolean
272 fu_unifying_runtime_detach (FuDevice *device, GError **error)
273 {
274 FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device);
275 g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new ();
276 msg->report_id = HIDPP_REPORT_ID_SHORT;
277 msg->device_id = HIDPP_DEVICE_ID_RECEIVER;
278 msg->sub_id = HIDPP_SUBID_SET_REGISTER;
279 msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE;
280 msg->data[0] = 'I';
281 msg->data[1] = 'C';
282 msg->data[2] = 'P';
283 msg->hidpp_version = 1;
284 msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT;
285 if (!fu_unifying_hidpp_send (self->io_channel, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) {
286 g_prefix_error (error, "failed to detach to bootloader: ");
287 return FALSE;
288 }
289 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
290 return TRUE;
291 }
292
293 static void
294 fu_unifying_runtime_finalize (GObject *object)
295 {
296 G_OBJECT_CLASS (fu_unifying_runtime_parent_class)->finalize (object);
297 }
298
299 static void
300 fu_unifying_runtime_class_init (FuUnifyingRuntimeClass *klass)
301 {
302 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
303 FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass);
304 GObjectClass *object_class = G_OBJECT_CLASS (klass);
305
306 object_class->finalize = fu_unifying_runtime_finalize;
307 klass_device->open = fu_unifying_runtime_open;
308 klass_device_udev->probe = fu_unifying_runtime_probe;
309 klass_device->setup = fu_unifying_runtime_setup;
310 klass_device->close = fu_unifying_runtime_close;
311 klass_device->detach = fu_unifying_runtime_detach;
312 klass_device->poll = fu_unifying_runtime_poll;
313 klass_device->to_string = fu_unifying_runtime_to_string;
314 }
315
316 static void
317 fu_unifying_runtime_init (FuUnifyingRuntime *self)
318 {
319 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
320 fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard");
321 fu_device_set_name (FU_DEVICE (self), "Unifying Receiver");
322 fu_device_set_summary (FU_DEVICE (self), "A miniaturised USB wireless receiver");
323 fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
324 }
+0
-12
plugins/unifying/fu-unifying-runtime.h less more
0 /*
1 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-udev-device.h"
9
10 #define FU_TYPE_UNIFYING_RUNTIME (fu_unifying_runtime_get_type ())
11 G_DECLARE_FINAL_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU, UNIFYING_RUNTIME, FuUdevDevice)
+0
-41
plugins/unifying/fu-unifying-self-test.c less more
0 /*
1 * Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #include "config.h"
7
8 #include <fwupd.h>
9 #include <glib-object.h>
10
11 #include "fu-unifying-common.h"
12
13 static void
14 fu_unifying_common (void)
15 {
16 guint8 u8;
17 guint16 u16;
18 g_autofree gchar *ver1 = NULL;
19
20 u8 = fu_unifying_buffer_read_uint8 ("12");
21 g_assert_cmpint (u8, ==, 0x12);
22 u16 = fu_unifying_buffer_read_uint16 ("1234");
23 g_assert_cmpint (u16, ==, 0x1234);
24
25 ver1 = fu_unifying_format_version (" A ", 0x87, 0x65, 0x4321);
26 g_assert_cmpstr (ver1, ==, "A87.65_B4321");
27 }
28
29 int
30 main (int argc, char **argv)
31 {
32 g_test_init (&argc, &argv, NULL);
33
34 /* only critical and error are fatal */
35 g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
36
37 /* tests go here */
38 g_test_add_func ("/unifying/common", fu_unifying_common);
39 return g_test_run ();
40 }
+0
-60
plugins/unifying/meson.build less more
0 cargs = ['-DG_LOG_DOMAIN="FuPluginUnifying"']
1
2 install_data([
3 'unifying.quirk',
4 ],
5 install_dir: join_paths(datadir, 'fwupd', 'quirks.d')
6 )
7
8
9 shared_module('fu_plugin_unifying',
10 fu_hash,
11 sources : [
12 'fu-plugin-unifying.c',
13 'fu-unifying-bootloader.c',
14 'fu-unifying-bootloader-nordic.c',
15 'fu-unifying-bootloader-texas.c',
16 'fu-unifying-common.c',
17 'fu-unifying-hidpp.c',
18 'fu-unifying-hidpp-msg.c',
19 'fu-unifying-peripheral.c',
20 'fu-unifying-runtime.c',
21 ],
22 include_directories : [
23 include_directories('../..'),
24 include_directories('../../src'),
25 include_directories('../../libfwupd'),
26 ],
27 install : true,
28 install_dir: plugin_dir,
29 link_with : [
30 libfwupdprivate,
31 ],
32 c_args : cargs,
33 dependencies : [
34 plugin_deps,
35 ],
36 )
37
38 if get_option('tests')
39 e = executable(
40 'unifying-self-test',
41 fu_hash,
42 sources : [
43 'fu-unifying-self-test.c',
44 'fu-unifying-common.c',
45 ],
46 include_directories : [
47 include_directories('../..'),
48 include_directories('../../libfwupd'),
49 ],
50 dependencies : [
51 plugin_deps,
52 ],
53 link_with : [
54 libfwupdprivate,
55 ],
56 c_args : cargs,
57 )
58 test('unifying-self-test', e)
59 endif
+0
-43
plugins/unifying/unifying.quirk less more
0 # Unifying Receiver
1 [DeviceInstanceId=HIDRAW\VEN_046D&DEV_C52B]
2 Plugin = unifying
3 GType = FuUnifyingRuntime
4 VendorId=USB:0x046D
5 InstallDuration = 30
6
7 # Nordic
8 [DeviceInstanceId=USB\VID_046D&PID_AAAA]
9 Plugin = unifying
10 GType = FuUnifyingBootloaderNordic
11 FirmwareSizeMin = 0x4000
12 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
13 InstallDuration = 30
14
15 # Nordic Pico
16 [DeviceInstanceId=USB\VID_046D&PID_AAAE]
17 Plugin = unifying
18 GType = FuUnifyingBootloaderNordic
19 FirmwareSizeMin = 0x4000
20 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
21 InstallDuration = 30
22
23 # Texas
24 [DeviceInstanceId=USB\VID_046D&PID_AAAC]
25 Plugin = unifying
26 GType = FuUnifyingBootloaderTexas
27 FirmwareSizeMin = 0x4000
28 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
29 InstallDuration = 18
30
31 # Texas Pico
32 [DeviceInstanceId=USB\VID_046D&PID_AAAD]
33 Plugin = unifying
34 GType = FuUnifyingBootloaderTexas
35 FirmwareSizeMin = 0x4000
36 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B
37 InstallDuration = 18
38
39 # Possible HID++ v2.0 peripheral device
40 [DeviceInstanceId=HIDRAW\VEN_046D]
41 Plugin = unifying
42 GType = FuUnifyingPeripheral
1313
1414 This plugin supports the following protocol ID:
1515
16 * com.via.vli-usbhub
16 * com.vli.usbhub
1717
1818 GUID Generation
1919 ---------------
2929 * `VLI_USBHUB\SPI_37303840`
3030 * `VLI_USBHUB\SPI_3730`
3131 * `VLI_USBHUB\SPI_37`
32
33 Optional PD child devices use just one extra GUID, e.g.
34
35 * `VLI_USBHUB_PD\VID_17EF&PID_3083`
36
37 Optional I²C child devices use just one extra GUID, e.g.
38
39 * `VLI_USBHUB_I2C\MSP430`
3240
3341 Quirk Use
3442 ---------
99
1010 #include "fu-vli-usbhub-device.h"
1111 #include "fu-vli-usbhub-firmware.h"
12 #include "fu-vli-usbhub-pd-firmware.h"
1213
1314 void
1415 fu_plugin_init (FuPlugin *plugin)
1516 {
1617 fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
17 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.via.vli-usbhub");
18 fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.vli.usbhub");
1819 fu_plugin_set_device_gtype (plugin, FU_TYPE_VLI_USBHUB_DEVICE);
1920 fu_plugin_add_firmware_gtype (plugin, "vli-usbhub", FU_TYPE_VLI_USBHUB_FIRMWARE);
21 fu_plugin_add_firmware_gtype (plugin, "vli-usbhub-pd", FU_TYPE_VLI_USBHUB_PD_FIRMWARE);
2022 }
23
24 /* reboot the FuVliUsbhubDevice if we update the FuVliUsbhubPdDevice */
25 static FuDevice *
26 fu_plugin_vli_usbhub_get_parent (GPtrArray *devices)
27 {
28 for (guint i = 0; i < devices->len; i++) {
29 FuDevice *dev = g_ptr_array_index (devices, i);
30 FuDevice *parent = fu_device_get_parent (dev);
31 if (FU_IS_VLI_USBHUB_DEVICE (dev))
32 return g_object_ref (dev);
33 if (parent != NULL && FU_IS_VLI_USBHUB_DEVICE (parent))
34 return g_object_ref (parent);
35 }
36 return NULL;
37 }
38
39 gboolean
40 fu_plugin_composite_cleanup (FuPlugin *plugin,
41 GPtrArray *devices,
42 GError **error)
43 {
44 g_autoptr(FuDeviceLocker) locker = NULL;
45 g_autoptr(FuDevice) parent = fu_plugin_vli_usbhub_get_parent (devices);
46 if (parent == NULL)
47 return TRUE;
48 locker = fu_device_locker_new (parent, error);
49 if (locker == NULL)
50 return FALSE;
51 return fu_device_attach (parent, error);
52 }
7676 GUINT16_FROM_BE(hdr->usb2_fw_sz));
7777 }
7878 fu_common_string_append_kx (str, idt, "Usb3FwAddr",
79 ((guint32) hdr->usb3_fw_addr_high) << 16 |
7980 GUINT16_FROM_BE(hdr->usb3_fw_addr));
8081 fu_common_string_append_kx (str, idt, "Usb3FwSz",
8182 GUINT16_FROM_BE(hdr->usb3_fw_sz));
7272 #define VLI_USBHUB_FLASHMAP_ADDR_HD1_BACKUP 0x1800
7373 #define VLI_USBHUB_FLASHMAP_ADDR_HD2 0x1000
7474 #define VLI_USBHUB_FLASHMAP_ADDR_FW 0x2000
75 #define VLI_USBHUB_FLASHMAP_ADDR_PD_LEGACY 0x10000
76 #define VLI_USBHUB_FLASHMAP_ADDR_PD 0x20000
77 #define VLI_USBHUB_FLASHMAP_ADDR_PD_BACKUP 0x30000
7578
7679 guint8 fu_vli_usbhub_header_crc8 (FuVliUsbhubHeader *hdr);
7780 void fu_vli_usbhub_header_to_string (FuVliUsbhubHeader *hdr,
1414 #include "fu-vli-usbhub-common.h"
1515 #include "fu-vli-usbhub-device.h"
1616 #include "fu-vli-usbhub-firmware.h"
17 #include "fu-vli-usbhub-i2c-device.h"
18 #include "fu-vli-usbhub-pd-common.h"
19 #include "fu-vli-usbhub-pd-device.h"
1720
1821 #define FU_VLI_USBHUB_DEVICE_TIMEOUT 3000 /* ms */
1922 #define FU_VLI_USBHUB_TXSIZE 0x20 /* bytes */
8083 }
8184 }
8285
86 gboolean
87 fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self,
88 guint8 cmd, guint8 *buf, gsize bufsz,
89 GError **error)
90 {
91 GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
92 guint16 value = ((guint16) FU_VLI_USBHUB_I2C_ADDR_WRITE << 8) | cmd;
93 guint16 index = (guint16) FU_VLI_USBHUB_I2C_ADDR_READ << 8;
94 if (!g_usb_device_control_transfer (usb_device,
95 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
96 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
97 G_USB_DEVICE_RECIPIENT_DEVICE,
98 FU_VLI_USBHUB_I2C_R_VDR, value, index,
99 buf, bufsz, NULL,
100 FU_VLI_USBHUB_DEVICE_TIMEOUT,
101 NULL, error)) {
102 g_prefix_error (error, "failed to read I2C: ");
103 return FALSE;
104 }
105 if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL)
106 fu_common_dump_raw (G_LOG_DOMAIN, "I2cReadData", buf, 0x1);
107 return TRUE;
108 }
109
110 gboolean
111 fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self,
112 FuVliUsbhubI2cStatus *status,
113 GError **error)
114 {
115 guint8 buf[1] = { 0xff };
116 if (!fu_vli_usbhub_device_i2c_read (self,
117 FU_VLI_USBHUB_I2C_CMD_READ_STATUS,
118 buf, sizeof(buf),
119 error))
120 return FALSE;
121 if (status != NULL)
122 *status = buf[0];
123 return TRUE;
124 }
125
126 gboolean
127 fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self,
128 guint8 skip_s,
129 guint8 skip_p,
130 const guint8 *buf,
131 gsize bufsz,
132 GError **error)
133 {
134 GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self));
135 guint16 value = (((guint16) skip_s) << 8) | skip_p;
136 if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL)
137 fu_common_dump_raw (G_LOG_DOMAIN, "I2cWriteData", buf, bufsz);
138 if (!g_usb_device_control_transfer (usb_device,
139 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
140 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
141 G_USB_DEVICE_RECIPIENT_DEVICE,
142 FU_VLI_USBHUB_I2C_W_VDR, value, 0x0,
143 (guint8 *) buf, bufsz, NULL,
144 FU_VLI_USBHUB_DEVICE_TIMEOUT,
145 NULL, error)) {
146 g_prefix_error (error, "failed to write I2C @0x%x: ", value);
147 return FALSE;
148 }
149 return TRUE;
150 }
151
152 gboolean
153 fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, guint8 cmd,
154 const guint8 *buf, gsize bufsz, GError **error)
155 {
156 guint8 buf2[10] = { FU_VLI_USBHUB_I2C_ADDR_WRITE, cmd, 0x0 };
157 if (!fu_memcpy_safe (buf2, sizeof(buf2), 0x2,
158 buf, bufsz, 0x0, bufsz, error))
159 return FALSE;
160 return fu_vli_usbhub_device_i2c_write_data (self, 0x0, 0x0, buf2, bufsz + 2, error);
161 }
162
83163 static gboolean
84164 fu_vli_usbhub_device_vdr_unlock_813 (FuVliUsbhubDevice *self, GError **error)
85165 {
468548 return TRUE;
469549 }
470550
471 static gboolean
472 fu_vli_usbhub_device_erase_sectors (FuVliUsbhubDevice *self,
473 guint32 addr,
474 gsize sz,
475 GError **error)
551 gboolean
552 fu_vli_usbhub_device_spi_erase (FuVliUsbhubDevice *self,
553 guint32 addr,
554 gsize sz,
555 GError **error)
476556 {
477557 g_autoptr(GPtrArray) chunks = fu_chunk_array_new (NULL, sz, addr, 0x0, 0x1000);
558 g_debug ("erasing 0x%x bytes @0x%x", (guint) sz, addr);
478559 for (guint i = 0; i < chunks->len; i++) {
479560 FuChunk *chunk = g_ptr_array_index (chunks, i);
480 g_debug ("erasing @0x%x", chunk->address);
561 if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL)
562 g_debug ("erasing @0x%x", chunk->address);
481563 if (!fu_vli_usbhub_device_erase_sector (self, chunk->address, error)) {
482564 g_prefix_error (error,
483 "failed to erase FW sector @0x%x",
565 "failed to erase FW sector @0x%x: ",
484566 chunk->address);
485567 return FALSE;
486568 }
652734 return TRUE;
653735 }
654736
655 static GBytes *
656 fu_vli_usbhub_device_dump_firmware (FuVliUsbhubDevice *self, gsize bufsz, GError **error)
737 GBytes *
738 fu_vli_usbhub_device_spi_read (FuVliUsbhubDevice *self,
739 guint32 address,
740 gsize bufsz,
741 GError **error)
657742 {
658743 g_autofree guint8 *buf = g_malloc0 (bufsz);
659744 g_autoptr(GPtrArray) chunks = NULL;
660745
661746 /* get data from hardware */
662 chunks = fu_chunk_array_new (buf, bufsz, 0x0, 0x0, FU_VLI_USBHUB_TXSIZE);
747 chunks = fu_chunk_array_new (buf, bufsz, address, 0x0, FU_VLI_USBHUB_TXSIZE);
663748 for (guint i = 0; i < chunks->len; i++) {
664749 FuChunk *chk = g_ptr_array_index (chunks, i);
665750 if (!fu_vli_usbhub_device_spi_read_data (self,
679764 static gboolean
680765 fu_vli_usbhub_device_probe (FuDevice *device, GError **error)
681766 {
767 guint16 usbver = fu_usb_device_get_spec (FU_USB_DEVICE (device));
768
682769 /* quirks now applied... */
683 if (fu_device_has_custom_flag (device, "usb3")) {
770 if (usbver > 0x0300 || fu_device_has_custom_flag (device, "usb3")) {
684771 fu_device_set_summary (device, "USB 3.x Hub");
685 } else if (fu_device_has_custom_flag (device, "usb2")) {
772 } else if (usbver > 0x0200 || fu_device_has_custom_flag (device, "usb2")) {
686773 fu_device_set_summary (device, "USB 2.x Hub");
687774 } else {
688775 fu_device_set_summary (device, "USB Hub");
689776 }
777 return TRUE;
778 }
779
780 static gboolean
781 fu_vli_usbhub_device_pd_setup (FuVliUsbhubDevice *self, GError **error)
782 {
783 FuVliUsbhubPdHdr hdr = { 0x0 };
784 g_autoptr(FuDevice) dev = NULL;
785 g_autoptr(GError) error_local = NULL;
786
787 /* legacy location */
788 if (!fu_vli_usbhub_device_spi_read_data (self,
789 VLI_USBHUB_FLASHMAP_ADDR_PD_LEGACY +
790 VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY,
791 (guint8 *) &hdr, sizeof(hdr), error)) {
792 g_prefix_error (error, "failed to read legacy PD header");
793 return FALSE;
794 }
795
796 /* new location */
797 if (GUINT16_FROM_LE (hdr.vid) != 0x2109) {
798 g_debug ("PD VID was 0x%04x trying new location",
799 GUINT16_FROM_LE (hdr.vid));
800 if (!fu_vli_usbhub_device_spi_read_data (self,
801 VLI_USBHUB_FLASHMAP_ADDR_PD +
802 VLI_USBHUB_PD_FLASHMAP_ADDR,
803 (guint8 *) &hdr, sizeof(hdr), error)) {
804 g_prefix_error (error, "failed to read PD header");
805 return FALSE;
806 }
807 }
808
809 /* emulate until we get actual hardware */
810 if (g_getenv ("VLI_USBHUB_EMULATE_PD") != NULL) {
811 gsize bufsz = 0;
812 g_autofree gchar *buf = NULL;
813 if (!g_file_get_contents (g_getenv ("VLI_USBHUB_EMULATE_PD"),
814 &buf, &bufsz, error))
815 return FALSE;
816 if (!fu_memcpy_safe ((guint8 *) &hdr, sizeof(hdr), 0x0,
817 (const guint8 *) buf, bufsz, 0x0, sizeof(hdr), error)) {
818 g_prefix_error (error, "failed to map emulated header: ");
819 return FALSE;
820 }
821 }
822
823 /* just empty space */
824 if (hdr.fwver == G_MAXUINT32) {
825 g_debug ("no PD device header found");
826 return TRUE;
827 }
828
829 /* add child */
830 dev = fu_vli_usbhub_pd_device_new (&hdr);
831 if (!fu_device_probe (dev, &error_local)) {
832 g_warning ("cannot create PD device: %s", error_local->message);
833 return TRUE;
834 }
835 fu_device_add_child (FU_DEVICE (self), dev);
836 return TRUE;
837 }
838
839 static gboolean
840 fu_vli_usbhub_device_i2c_setup (FuVliUsbhubDevice *self, GError **error)
841 {
842 g_autoptr(FuDevice) dev = NULL;
843 g_autoptr(GError) error_local = NULL;
844
845 /* add child */
846 dev = fu_vli_usbhub_i2c_device_new (self);
847 if (!fu_device_probe (dev, error))
848 return FALSE;
849 if (!fu_device_setup (dev, &error_local)) {
850 if (g_error_matches (error_local,
851 FWUPD_ERROR,
852 FWUPD_ERROR_NOT_FOUND)) {
853 g_debug ("%s", error_local->message);
854 } else {
855 g_warning ("cannot create I²C device: %s",
856 error_local->message);
857 }
858 return TRUE;
859 }
860 fu_device_add_child (FU_DEVICE (self), dev);
690861 return TRUE;
691862 }
692863
791962 }
792963 }
793964
965 /* detect the PD child */
966 if (!fu_vli_usbhub_device_pd_setup (self, error))
967 return FALSE;
968
969 /* detect the PD child */
970 if (!fu_vli_usbhub_device_i2c_setup (self, error))
971 return FALSE;
972
794973 /* success */
795974 return TRUE;
796975 }
9081087 }
9091088
9101089 /* write */
1090 if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL)
1091 g_debug ("writing 0x%x block @0x%x", (guint) bufsz, address);
9111092 if (!fu_vli_usbhub_device_spi_write_enable (self, error)) {
9121093 g_prefix_error (error, "enabling SPI write failed: ");
9131094 return FALSE;
9261107 return fu_common_bytes_compare_raw (buf, bufsz, buf_tmp, bufsz, error);
9271108 }
9281109
929 static gboolean
930 fu_vli_usbhub_device_write_blocks (FuVliUsbhubDevice *self,
931 guint32 address,
932 const guint8 *buf,
933 gsize bufsz,
934 GError **error)
1110 gboolean
1111 fu_vli_usbhub_device_spi_write (FuVliUsbhubDevice *self,
1112 guint32 address,
1113 const guint8 *buf,
1114 gsize bufsz,
1115 GError **error)
9351116 {
9361117 FuChunk *chk;
9371118 g_autoptr(GPtrArray) chunks = NULL;
9381119
9391120 /* write SPI data, then CRC bytes last */
1121 g_debug ("writing 0x%x bytes @0x%x", (guint) bufsz, address);
9401122 chunks = fu_chunk_array_new (buf, bufsz, 0x0, 0x0, FU_VLI_USBHUB_TXSIZE);
9411123 if (chunks->len > 1) {
9421124 for (guint i = 1; i < chunks->len; i++) {
9911173 /* write in chunks */
9921174 fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE);
9931175 buf = g_bytes_get_data (fw, &bufsz);
994 if (!fu_vli_usbhub_device_write_blocks (self, 0x0, buf, bufsz, error))
1176 if (!fu_vli_usbhub_device_spi_write (self, 0x0, buf, bufsz, error))
9951177 return FALSE;
9961178
9971179 /* success */
10161198
10171199 /* write in chunks */
10181200 fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE);
1019 if (!fu_vli_usbhub_device_write_blocks (self, VLI_USBHUB_FLASHMAP_ADDR_HD1,
1020 buf, bufsz, error))
1201 if (!fu_vli_usbhub_device_spi_write (self, VLI_USBHUB_FLASHMAP_ADDR_HD1,
1202 buf, bufsz, error))
10211203 return FALSE;
10221204
10231205 /* success */
11491331
11501332 /* make space */
11511333 fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE);
1152 if (!fu_vli_usbhub_device_erase_sectors (self, hd2_fw_addr, hd2_fw_sz, error))
1334 if (!fu_vli_usbhub_device_spi_erase (self, hd2_fw_addr, hd2_fw_sz, error))
11531335 return FALSE;
11541336
11551337 /* perform the actual write */
11561338 fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE);
1157 if (!fu_vli_usbhub_device_write_blocks (self,
1158 hd2_fw_addr,
1159 buf_fw + hd2_fw_offset,
1160 hd2_fw_sz,
1161 error)) {
1339 if (!fu_vli_usbhub_device_spi_write (self,
1340 hd2_fw_addr,
1341 buf_fw + hd2_fw_offset,
1342 hd2_fw_sz,
1343 error)) {
11621344 g_prefix_error (error, "failed to write payload: ");
11631345 return FALSE;
11641346 }
11901372 }
11911373
11921374 /* success */
1193 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
11941375 return TRUE;
11951376 }
11961377
12001381 FuVliUsbhubDevice *self = FU_VLI_USBHUB_DEVICE (device);
12011382 g_autoptr(GBytes) fw = NULL;
12021383 fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY);
1203 fw = fu_vli_usbhub_device_dump_firmware (self, fu_device_get_firmware_size_max (device), error);
1384 fw = fu_vli_usbhub_device_spi_read (self, 0x0,
1385 fu_device_get_firmware_size_max (device),
1386 error);
12041387 if (fw == NULL)
12051388 return NULL;
12061389 return fu_firmware_new_from_bytes (fw);
77
88 #include "fu-plugin.h"
99
10 #include "fu-vli-usbhub-i2c-common.h"
11
1012 #define FU_TYPE_VLI_USBHUB_DEVICE (fu_vli_usbhub_device_get_type ())
1113 G_DECLARE_FINAL_TYPE (FuVliUsbhubDevice, fu_vli_usbhub_device, FU, VLI_USBHUB_DEVICE, FuUsbDevice)
1214
1416 {
1517 FuUsbDeviceClass parent_class;
1618 };
19
20 gboolean fu_vli_usbhub_device_spi_erase (FuVliUsbhubDevice *self,
21 guint32 addr,
22 gsize sz,
23 GError **error);
24 gboolean fu_vli_usbhub_device_spi_write (FuVliUsbhubDevice *self,
25 guint32 address,
26 const guint8 *buf,
27 gsize bufsz,
28 GError **error);
29 GBytes *fu_vli_usbhub_device_spi_read (FuVliUsbhubDevice *self,
30 guint32 address,
31 gsize bufsz,
32 GError **error);
33 gboolean fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self,
34 guint8 cmd,
35 guint8 *buf,
36 gsize bufsz,
37 GError **error);
38 gboolean fu_vli_usbhub_device_i2c_read_status (FuVliUsbhubDevice *self,
39 FuVliUsbhubI2cStatus *status,
40 GError **error);
41 gboolean fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self,
42 guint8 cmd,
43 const guint8 *buf,
44 gsize bufsz,
45 GError **error);
46 gboolean fu_vli_usbhub_device_i2c_write_data (FuVliUsbhubDevice *self,
47 guint8 skip_s,
48 guint8 skip_p,
49 const guint8 *buf,
50 gsize bufsz,
51 GError **error);
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #include "config.h"
8
9 #include "fu-vli-usbhub-i2c-common.h"
10
11 const gchar *
12 fu_vli_usbhub_i2c_chip_to_string (FuVliUsbhubI2cChip chip)
13 {
14 if (chip == FU_VLI_USBHUB_I2C_CHIP_MSP430)
15 return "MSP430";
16 return NULL;
17 }
18
19 gboolean
20 fu_vli_usbhub_i2c_check_status (FuVliUsbhubI2cStatus status, GError **error)
21 {
22 if (status == FU_VLI_USBHUB_I2C_STATUS_OK)
23 return TRUE;
24 if (status == FU_VLI_USBHUB_I2C_STATUS_HEADER) {
25 g_set_error_literal (error,
26 FWUPD_ERROR,
27 FWUPD_ERROR_INTERNAL,
28 "Incorrect header value of data frame");
29 return FALSE;
30 }
31 if (status == FU_VLI_USBHUB_I2C_STATUS_COMMAND) {
32 g_set_error_literal (error,
33 FWUPD_ERROR,
34 FWUPD_ERROR_INTERNAL,
35 "Invalid command data");
36 return FALSE;
37 }
38 if (status == FU_VLI_USBHUB_I2C_STATUS_ADDRESS) {
39 g_set_error_literal (error,
40 FWUPD_ERROR,
41 FWUPD_ERROR_INTERNAL,
42 "Invalid address range");
43 return FALSE;
44 }
45 if (status == FU_VLI_USBHUB_I2C_STATUS_PACKETSIZE) {
46 g_set_error_literal (error,
47 FWUPD_ERROR,
48 FWUPD_ERROR_INTERNAL,
49 "Incorrect payload data length");
50 return FALSE;
51 }
52 if (status == FU_VLI_USBHUB_I2C_STATUS_CHECKSUM) {
53 g_set_error_literal (error,
54 FWUPD_ERROR,
55 FWUPD_ERROR_INTERNAL,
56 "Incorrect frame data checksum");
57 return FALSE;
58 }
59 g_set_error (error,
60 FWUPD_ERROR,
61 FWUPD_ERROR_INTERNAL,
62 "Unknown error [0x%02x]", status);
63 return FALSE;
64 }
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #pragma once
8
9 #include "fu-plugin.h"
10
11 typedef enum {
12 FU_VLI_USBHUB_I2C_CHIP_UNKNOWN,
13 FU_VLI_USBHUB_I2C_CHIP_MSP430,
14 } FuVliUsbhubI2cChip;
15
16 typedef enum {
17 FU_VLI_USBHUB_I2C_STATUS_OK,
18 FU_VLI_USBHUB_I2C_STATUS_HEADER,
19 FU_VLI_USBHUB_I2C_STATUS_COMMAND,
20 FU_VLI_USBHUB_I2C_STATUS_ADDRESS,
21 FU_VLI_USBHUB_I2C_STATUS_PACKETSIZE,
22 FU_VLI_USBHUB_I2C_STATUS_CHECKSUM,
23 } FuVliUsbhubI2cStatus;
24
25 /* Texas Instruments BSL */
26 #define FU_VLI_USBHUB_I2C_ADDR_WRITE 0x18
27 #define FU_VLI_USBHUB_I2C_ADDR_READ 0x19
28
29 #define FU_VLI_USBHUB_I2C_CMD_WRITE 0x32
30 #define FU_VLI_USBHUB_I2C_CMD_READ_STATUS 0x33
31 #define FU_VLI_USBHUB_I2C_CMD_UPGRADE 0x34
32 #define FU_VLI_USBHUB_I2C_CMD_READ_VERSIONS 0x40
33
34 #define FU_VLI_USBHUB_I2C_R_VDR 0xa0 /* read vendor comand */
35 #define FU_VLI_USBHUB_I2C_W_VDR 0xb0 /* write vendor comand */
36
37 const gchar *fu_vli_usbhub_i2c_chip_to_string (FuVliUsbhubI2cChip chip);
38 gboolean fu_vli_usbhub_i2c_check_status (FuVliUsbhubI2cStatus status,
39 GError **error);
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #include "config.h"
8
9 #include "fu-firmware-common.h"
10 #include "fu-ihex-firmware.h"
11
12 #include "fu-vli-usbhub-common.h"
13 #include "fu-vli-usbhub-device.h"
14 #include "fu-vli-usbhub-i2c-common.h"
15 #include "fu-vli-usbhub-i2c-device.h"
16
17 struct _FuVliUsbhubI2cDevice
18 {
19 FuDevice parent_instance;
20 FuVliUsbhubDevice *parent;
21 FuVliUsbhubI2cChip chip;
22 };
23
24 G_DEFINE_TYPE (FuVliUsbhubI2cDevice, fu_vli_usbhub_i2c_device, FU_TYPE_DEVICE)
25
26 static void
27 fu_vli_usbhub_i2c_device_to_string (FuDevice *device, guint idt, GString *str)
28 {
29 FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device);
30 fu_common_string_append_kv (str, idt, "ChipId",
31 fu_vli_usbhub_i2c_chip_to_string (self->chip));
32 }
33
34 static gboolean
35 fu_vli_usbhub_i2c_device_setup (FuDevice *device, GError **error)
36 {
37 FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device);
38 guint8 buf[11] = { 0x0 };
39 g_autofree gchar *instance_id = NULL;
40 g_autofree gchar *version = NULL;
41 g_autoptr(FuVliUsbhubDevice) parent = g_steal_pointer (&self->parent);
42
43 /* get versions */
44 if (!fu_vli_usbhub_device_i2c_read (parent,
45 FU_VLI_USBHUB_I2C_CMD_READ_VERSIONS,
46 buf, sizeof(buf), error)) {
47 g_prefix_error (error, "failed to read versions: ");
48 return FALSE;
49 }
50 if ((buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00) ||
51 (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff)) {
52 g_set_error (error,
53 FWUPD_ERROR,
54 FWUPD_ERROR_NOT_FOUND,
55 "no %s device detected",
56 fu_vli_usbhub_i2c_chip_to_string (self->chip));
57 return FALSE;
58 }
59
60 /* add instance ID */
61 instance_id = g_strdup_printf ("VLI_USBHUB_I2C\\%s",
62 fu_vli_usbhub_i2c_chip_to_string (self->chip));
63 fu_device_add_instance_id (device, instance_id);
64
65 /* set version */
66 version = g_strdup_printf ("%x.%x.%x", buf[0], buf[1], buf[2]);
67 fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_TRIPLET);
68 return TRUE;
69 }
70
71 static gboolean
72 fu_vli_usbhub_i2c_device_detach (FuDevice *device, GError **error)
73 {
74 FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device));
75 const guint8 buf[] = {
76 FU_VLI_USBHUB_I2C_ADDR_WRITE,
77 FU_VLI_USBHUB_I2C_CMD_UPGRADE,
78 };
79 if (!fu_vli_usbhub_device_i2c_write_data (parent, 0, 0, buf, sizeof(buf), error))
80 return FALSE;
81
82 /* avoid power instability */
83 fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART);
84 g_usleep (5000);
85
86 /* success */
87 return TRUE;
88 }
89
90 static FuFirmware *
91 fu_vli_usbhub_i2c_device_prepare_firmware (FuDevice *device,
92 GBytes *fw,
93 FwupdInstallFlags flags,
94 GError **error)
95 {
96 g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new ();
97 fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
98 if (!fu_firmware_tokenize (firmware, fw, flags, error))
99 return NULL;
100 return g_steal_pointer (&firmware);
101 }
102
103 static gboolean
104 fu_vli_usbhub_i2c_device_write_firmware (FuDevice *device,
105 FuFirmware *firmware,
106 FwupdInstallFlags flags,
107 GError **error)
108 {
109 FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device));
110 GPtrArray *records = fu_ihex_firmware_get_records (FU_IHEX_FIRMWARE (firmware));
111 guint16 usbver = fu_usb_device_get_spec (FU_USB_DEVICE (device));
112 g_autoptr(FuDeviceLocker) locker = NULL;
113
114 /* open device */
115 locker = fu_device_locker_new (parent, error);
116 if (locker == NULL)
117 return FALSE;
118
119 /* transfer by I²C write, and check status by I²C read */
120 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
121 for (guint j = 0; j < records->len; j++) {
122 FuIhexFirmwareRecord *rcd = g_ptr_array_index (records, j);
123 const gchar *line = rcd->buf->str;
124 gsize bufsz;
125 guint8 buf[0x40] = { 0x0 };
126 guint8 req_len;
127 guint retry;
128
129 /* check there's enough data for the smallest possible record */
130 if (rcd->buf->len < 11) {
131 g_set_error (error,
132 FWUPD_ERROR,
133 FWUPD_ERROR_INVALID_FILE,
134 "line %u is incomplete, length %u",
135 rcd->ln, (guint) rcd->buf->len);
136 return FALSE;
137 }
138
139 /* check starting token */
140 if (line[0] != ':') {
141 g_set_error (error,
142 FWUPD_ERROR,
143 FWUPD_ERROR_INVALID_FILE,
144 "invalid starting token on line %u: %s",
145 rcd->ln, line);
146 return FALSE;
147 }
148
149 /* length, 16-bit address, type */
150 req_len = fu_firmware_strparse_uint8 (line + 1);
151 if (req_len > 64) {
152 g_set_error_literal (error,
153 FWUPD_ERROR,
154 FWUPD_ERROR_NOT_SUPPORTED,
155 "max write is 64 bytes");
156 return FALSE;
157 }
158 if (9 + (guint) req_len * 2 > (guint) rcd->buf->len) {
159 g_set_error (error,
160 FWUPD_ERROR,
161 FWUPD_ERROR_INVALID_FILE,
162 "line %u malformed", rcd->ln);
163 return FALSE;
164 }
165
166 /* write each record directly to the hardware */
167 buf[0] = FU_VLI_USBHUB_I2C_ADDR_WRITE;
168 buf[1] = FU_VLI_USBHUB_I2C_CMD_WRITE;
169 buf[2] = 0x3a; /* ':' */
170 buf[3] = req_len;
171 buf[4] = fu_firmware_strparse_uint8 (line + 3);
172 buf[5] = fu_firmware_strparse_uint8 (line + 5);
173 buf[6] = fu_firmware_strparse_uint8 (line + 7);
174 for (guint8 i = 0; i < req_len; i++)
175 buf[7 + i] = fu_firmware_strparse_uint8 (line + 9 + (i * 2));
176 buf[7 + req_len] = fu_firmware_strparse_uint8 (line + 9+ (req_len * 2));
177 bufsz = req_len + 8;
178
179 for (retry = 0; retry < 5; retry++) {
180 FuVliUsbhubI2cStatus status = 0xff;
181 g_autoptr(GError) error_local = NULL;
182
183 g_usleep (5 * 1000);
184 if (usbver >= 0x0300 || bufsz <= 32) {
185 if (!fu_vli_usbhub_device_i2c_write_data (parent,
186 0, 0,
187 buf,
188 bufsz,
189 error))
190 return FALSE;
191 } else {
192 /* for U2, hub data buffer <= 32 bytes */
193 if (!fu_vli_usbhub_device_i2c_write_data (parent,
194 0, 1,
195 buf,
196 32,
197 error))
198 return FALSE;
199 if (!fu_vli_usbhub_device_i2c_write_data (parent,
200 1, 0,
201 buf + 32,
202 bufsz - 32,
203 error))
204 return FALSE;
205 }
206
207 /* end of file, no need to check status */
208 if (req_len == 0 && buf[6] == 0x01 && buf[7] == 0xFF)
209 break;
210
211 /* read data to check status */
212 g_usleep (5 * 1000);
213 if (!fu_vli_usbhub_device_i2c_read_status (parent,
214 &status,
215 error))
216 return FALSE;
217 if (!fu_vli_usbhub_i2c_check_status (status, &error_local)) {
218 g_warning ("error on try %u: %s",
219 retry + 1, error_local->message);
220 } else {
221 break;
222 }
223 }
224 if (retry >= 5) {
225 g_set_error_literal (error,
226 G_IO_ERROR,
227 G_IO_ERROR_NOT_SUPPORTED,
228 "I²C status retry failed");
229 return FALSE;
230 }
231 fu_device_set_progress_full (device, (gsize) j, (gsize) records->len);
232 }
233
234 /* success */
235 return TRUE;
236 }
237
238 static gboolean
239 fu_vli_usbhub_i2c_device_probe (FuDevice *device, GError **error)
240 {
241 FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (device);
242 self->chip = FU_VLI_USBHUB_I2C_CHIP_MSP430;
243 fu_device_set_name (device, fu_vli_usbhub_i2c_chip_to_string (self->chip));
244 return TRUE;
245 }
246
247 static void
248 fu_vli_usbhub_i2c_device_init (FuVliUsbhubI2cDevice *self)
249 {
250 fu_device_add_icon (FU_DEVICE (self), "audio-card");
251 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
252 fu_device_set_logical_id (FU_DEVICE (self), "I2C");
253 fu_device_set_summary (FU_DEVICE (self), "I²C Dock Management Device");
254 }
255
256 static void
257 fu_vli_usbhub_i2c_device_finalize (GObject *object)
258 {
259 FuVliUsbhubI2cDevice *self = FU_VLI_USBHUB_I2C_DEVICE (object);
260 g_clear_object (&self->parent);
261 G_OBJECT_CLASS (fu_vli_usbhub_i2c_device_parent_class)->finalize (object);
262 }
263
264 static void
265 fu_vli_usbhub_i2c_device_class_init (FuVliUsbhubI2cDeviceClass *klass)
266 {
267 GObjectClass *object_class = G_OBJECT_CLASS (klass);
268 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
269 object_class->finalize = fu_vli_usbhub_i2c_device_finalize;
270 klass_device->to_string = fu_vli_usbhub_i2c_device_to_string;
271 klass_device->probe = fu_vli_usbhub_i2c_device_probe;
272 klass_device->setup = fu_vli_usbhub_i2c_device_setup;
273 klass_device->detach = fu_vli_usbhub_i2c_device_detach;
274 klass_device->write_firmware = fu_vli_usbhub_i2c_device_write_firmware;
275 klass_device->prepare_firmware = fu_vli_usbhub_i2c_device_prepare_firmware;
276 }
277
278 FuDevice *
279 fu_vli_usbhub_i2c_device_new (FuVliUsbhubDevice *parent)
280 {
281 FuVliUsbhubI2cDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_I2C_DEVICE, NULL);
282 self->parent = g_object_ref (parent);
283 return FU_DEVICE (self);
284 }
0 /*
1 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-plugin.h"
9
10 #define FU_TYPE_VLI_USBHUB_I2C_DEVICE (fu_vli_usbhub_i2c_device_get_type ())
11 G_DECLARE_FINAL_TYPE (FuVliUsbhubI2cDevice, fu_vli_usbhub_i2c_device, FU, VLI_USBHUB_I2C_DEVICE, FuDevice)
12
13 struct _FuVliUsbhubI2cDeviceClass
14 {
15 FuDeviceClass parent_class;
16 };
17
18 FuDevice *fu_vli_usbhub_i2c_device_new (FuVliUsbhubDevice *parent);
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #include "config.h"
8
9 #include "fu-vli-usbhub-pd-common.h"
10
11 guint16
12 fu_vli_usbhub_pd_crc16 (const guint8 *buf, gsize bufsz)
13 {
14 guint16 crc = 0xffff;
15 for (gsize len = bufsz; len > 0; len--) {
16 crc = (guint16) (crc ^ (*buf++));
17 for (guint8 i = 0; i < 8; i++) {
18 if (crc & 0x1) {
19 crc = (crc >> 1) ^ 0xa001;
20 } else {
21 crc >>= 1;
22 }
23 }
24 }
25 return ~crc;
26 }
27
28 FuVliUsbhubPdChip
29 fu_vli_usbhub_pd_guess_chip (guint32 fwver)
30 {
31 guint32 tmp = (fwver & 0x0f000000) >> 24;
32 if (tmp == 0x01 || tmp == 0x02 || tmp == 0x03)
33 return FU_VLI_USBHUB_PD_CHIP_VL100;
34 if (tmp == 0x04 || tmp == 0x05 || tmp == 0x06)
35 return FU_VLI_USBHUB_PD_CHIP_VL101;
36 if (tmp == 0x07 || tmp == 0x08)
37 return FU_VLI_USBHUB_PD_CHIP_VL102;
38 if (tmp == 0x09 || tmp == 0x0a)
39 return FU_VLI_USBHUB_PD_CHIP_VL103;
40 if (tmp == 0x0b)
41 return FU_VLI_USBHUB_PD_CHIP_VL104;
42 if (tmp == 0x0c)
43 return FU_VLI_USBHUB_PD_CHIP_VL105;
44 return FU_VLI_USBHUB_PD_CHIP_UNKNOWN;
45 }
46
47 const gchar *
48 fu_vli_usbhub_pd_chip_to_string (FuVliUsbhubPdChip chip)
49 {
50 if (chip == FU_VLI_USBHUB_PD_CHIP_VL100)
51 return "VL100";
52 if (chip == FU_VLI_USBHUB_PD_CHIP_VL101)
53 return "VL101";
54 if (chip == FU_VLI_USBHUB_PD_CHIP_VL102)
55 return "VL102";
56 if (chip == FU_VLI_USBHUB_PD_CHIP_VL103)
57 return "VL103";
58 if (chip == FU_VLI_USBHUB_PD_CHIP_VL104)
59 return "VL104";
60 if (chip == FU_VLI_USBHUB_PD_CHIP_VL105)
61 return "VL105";
62 return NULL;
63 }
64
65 guint32
66 fu_vli_usbhub_pd_chip_get_offset (FuVliUsbhubPdChip chip)
67 {
68 if (chip == FU_VLI_USBHUB_PD_CHIP_VL100)
69 return 0x10000;
70 if (chip == FU_VLI_USBHUB_PD_CHIP_VL101)
71 return 0x10000;
72 if (chip == FU_VLI_USBHUB_PD_CHIP_VL102)
73 return 0x20000;
74 if (chip == FU_VLI_USBHUB_PD_CHIP_VL103)
75 return 0x20000;
76 if (chip == FU_VLI_USBHUB_PD_CHIP_VL104)
77 return 0x20000;
78 if (chip == FU_VLI_USBHUB_PD_CHIP_VL105)
79 return 0x20000;
80 return 0x0;
81 }
82
83 guint32
84 fu_vli_usbhub_pd_chip_get_size (FuVliUsbhubPdChip chip)
85 {
86 if (chip == FU_VLI_USBHUB_PD_CHIP_VL100)
87 return 0x8000; /* 32KB */
88 if (chip == FU_VLI_USBHUB_PD_CHIP_VL101)
89 return 0xc000; /* 48KB */
90 if (chip == FU_VLI_USBHUB_PD_CHIP_VL102)
91 return 0x8000; /* 32KB */
92 if (chip == FU_VLI_USBHUB_PD_CHIP_VL103)
93 return 0x8000; /* 32KB */
94 if (chip == FU_VLI_USBHUB_PD_CHIP_VL104)
95 return 0xc000; /* 48KB */
96 if (chip == FU_VLI_USBHUB_PD_CHIP_VL105)
97 return 0xc000; /* 48KB */
98 return 0x0;
99 }
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #pragma once
8
9 #include "fu-plugin.h"
10
11 typedef enum {
12 FU_VLI_USBHUB_PD_CHIP_UNKNOWN = 0x0,
13 FU_VLI_USBHUB_PD_CHIP_VL100 = 0x100,
14 FU_VLI_USBHUB_PD_CHIP_VL101 = 0x101,
15 FU_VLI_USBHUB_PD_CHIP_VL102 = 0x102,
16 FU_VLI_USBHUB_PD_CHIP_VL103 = 0x103,
17 FU_VLI_USBHUB_PD_CHIP_VL104 = 0x104,
18 FU_VLI_USBHUB_PD_CHIP_VL105 = 0x105,
19 } FuVliUsbhubPdChip;
20
21 typedef struct __attribute__ ((packed)) {
22 guint32 fwver; /* BE */
23 guint16 vid; /* LE */
24 guint16 pid; /* LE */
25 } FuVliUsbhubPdHdr;
26
27 #define VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY 0x4000
28 #define VLI_USBHUB_PD_FLASHMAP_ADDR 0x1003
29
30 guint16 fu_vli_usbhub_pd_crc16 (const guint8 *buf,
31 gsize bufsz);
32 guint32 fu_vli_usbhub_pd_chip_get_offset (FuVliUsbhubPdChip chip);
33 guint32 fu_vli_usbhub_pd_chip_get_size (FuVliUsbhubPdChip chip);
34 const gchar *fu_vli_usbhub_pd_chip_to_string (FuVliUsbhubPdChip chip);
35 FuVliUsbhubPdChip fu_vli_usbhub_pd_guess_chip (guint32 fwver);
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #include "config.h"
8
9 #include <string.h>
10
11 #include "fu-vli-usbhub-common.h"
12 #include "fu-vli-usbhub-device.h"
13 #include "fu-vli-usbhub-pd-common.h"
14 #include "fu-vli-usbhub-pd-device.h"
15 #include "fu-vli-usbhub-pd-firmware.h"
16
17 struct _FuVliUsbhubPdDevice
18 {
19 FuDevice parent_instance;
20 FuVliUsbhubPdHdr hdr;
21 FuVliUsbhubPdChip chip;
22 };
23
24 G_DEFINE_TYPE (FuVliUsbhubPdDevice, fu_vli_usbhub_pd_device, FU_TYPE_DEVICE)
25
26 static void
27 fu_vli_usbhub_pd_device_to_string (FuDevice *device, guint idt, GString *str)
28 {
29 FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device);
30 fu_common_string_append_kv (str, idt, "ChipId",
31 fu_vli_usbhub_pd_chip_to_string (self->chip));
32 fu_common_string_append_kx (str, idt, "FwOffset",
33 fu_vli_usbhub_pd_chip_get_offset (self->chip));
34 fu_common_string_append_kx (str, idt, "FwSize",
35 fu_vli_usbhub_pd_chip_get_size (self->chip));
36 }
37
38 static gboolean
39 fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error)
40 {
41 FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device);
42
43 guint32 fwver;
44 g_autofree gchar *fwver_str = NULL;
45 g_autofree gchar *instance_id1 = NULL;
46
47 /* get version */
48 fwver = GUINT32_FROM_BE (self->hdr.fwver);
49 self->chip = fu_vli_usbhub_pd_guess_chip (fwver);
50 if (self->chip == FU_VLI_USBHUB_PD_CHIP_UNKNOWN) {
51 g_set_error (error,
52 FWUPD_ERROR,
53 FWUPD_ERROR_NOT_SUPPORTED,
54 "PD version invalid [0x%x]", fwver);
55 return FALSE;
56 }
57 fu_device_set_firmware_size (device, fu_vli_usbhub_pd_chip_get_size (self->chip));
58 fu_device_set_name (device, fu_vli_usbhub_pd_chip_to_string (self->chip));
59
60 /* use header to populate device info */
61 fwver_str = fu_common_version_from_uint32 (fwver, FWUPD_VERSION_FORMAT_QUAD);
62 fu_device_set_version (device, fwver_str, FWUPD_VERSION_FORMAT_QUAD);
63 instance_id1 = g_strdup_printf ("VLI_USBHUB_PD\\VID_%04X&PID_%04X",
64 GUINT16_FROM_LE (self->hdr.vid),
65 GUINT16_FROM_LE (self->hdr.pid));
66 fu_device_add_instance_id (device, instance_id1);
67
68 /* these have a backup section */
69 if (fu_vli_usbhub_pd_chip_get_offset (self->chip) == VLI_USBHUB_FLASHMAP_ADDR_PD)
70 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY);
71
72 /* success */
73 return TRUE;
74 }
75
76 static FuFirmware *
77 fu_vli_usbhub_pd_device_prepare_firmware (FuDevice *device,
78 GBytes *fw,
79 FwupdInstallFlags flags,
80 GError **error)
81 {
82 FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device);
83 FuVliUsbhubPdChip chip;
84 g_autoptr(FuFirmware) firmware = fu_vli_usbhub_pd_firmware_new ();
85
86 /* check size */
87 if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) {
88 g_set_error (error,
89 FWUPD_ERROR,
90 FWUPD_ERROR_INVALID_FILE,
91 "firmware too small, got 0x%x, expected >= 0x%x",
92 (guint) g_bytes_get_size (fw),
93 (guint) fu_device_get_firmware_size_min (device));
94 return NULL;
95 }
96 if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) {
97 g_set_error (error,
98 FWUPD_ERROR,
99 FWUPD_ERROR_INVALID_FILE,
100 "firmware too large, got 0x%x, expected <= 0x%x",
101 (guint) g_bytes_get_size (fw),
102 (guint) fu_device_get_firmware_size_max (device));
103 return NULL;
104 }
105
106 /* check is compatible with firmware */
107 fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING);
108 if (!fu_firmware_parse (firmware, fw, flags, error))
109 return NULL;
110 chip = fu_vli_usbhub_pd_firmware_get_chip (FU_VLI_USBHUB_PD_FIRMWARE (firmware));
111 if (self->chip != chip) {
112 g_set_error (error,
113 FWUPD_ERROR,
114 FWUPD_ERROR_INVALID_FILE,
115 "firmware incompatible, got %s, expected %s",
116 fu_vli_usbhub_pd_chip_to_string (chip),
117 fu_vli_usbhub_pd_chip_to_string (self->chip));
118 return NULL;
119 }
120
121 /* we could check this against flags */
122 g_debug ("parsed version: %s", fu_firmware_get_version (firmware));
123 return g_steal_pointer (&firmware);
124 }
125
126 static FuFirmware *
127 fu_vli_usbhub_pd_device_read_firmware (FuDevice *device, GError **error)
128 {
129 FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device));
130 FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device);
131 g_autoptr(FuDeviceLocker) locker = NULL;
132 g_autoptr(GBytes) fw = NULL;
133
134 /* open device */
135 locker = fu_device_locker_new (parent, error);
136 if (locker == NULL)
137 return FALSE;
138
139 /* read */
140 fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY);
141 fw = fu_vli_usbhub_device_spi_read (parent,
142 fu_vli_usbhub_pd_chip_get_offset (self->chip),
143 fu_device_get_firmware_size_max (device),
144 error);
145 if (fw == NULL)
146 return NULL;
147 return fu_firmware_new_from_bytes (fw);
148 }
149
150 static gboolean
151 fu_vli_usbhub_pd_device_write_firmware (FuDevice *device,
152 FuFirmware *firmware,
153 FwupdInstallFlags flags,
154 GError **error)
155 {
156 FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device);
157 FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device));
158 gsize bufsz = 0;
159 const guint8 *buf;
160 g_autoptr(FuDeviceLocker) locker = NULL;
161 g_autoptr(GBytes) fw = NULL;
162
163 /* simple image */
164 fw = fu_firmware_get_image_default_bytes (firmware, error);
165 if (fw == NULL)
166 return FALSE;
167
168 /* open device */
169 locker = fu_device_locker_new (parent, error);
170 if (locker == NULL)
171 return FALSE;
172
173 /* erase */
174 fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE);
175 buf = g_bytes_get_data (fw, &bufsz);
176 if (!fu_vli_usbhub_device_spi_erase (parent,
177 fu_vli_usbhub_pd_chip_get_offset (self->chip),
178 bufsz,
179 error))
180 return FALSE;
181
182 /* write */
183 fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE);
184 if (!fu_vli_usbhub_device_spi_write (parent,
185 fu_vli_usbhub_pd_chip_get_offset (self->chip),
186 buf,
187 bufsz,
188 error))
189 return FALSE;
190
191 /* success */
192 return TRUE;
193 }
194
195 static void
196 fu_vli_usbhub_pd_device_init (FuVliUsbhubPdDevice *self)
197 {
198 fu_device_add_icon (FU_DEVICE (self), "audio-card");
199 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
200 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE);
201 fu_device_set_install_duration (FU_DEVICE (self), 15); /* seconds */
202 fu_device_set_logical_id (FU_DEVICE (self), "PD");
203 fu_device_set_summary (FU_DEVICE (self), "USB-C Power Delivery Device");
204 }
205
206 static void
207 fu_vli_usbhub_pd_device_class_init (FuVliUsbhubPdDeviceClass *klass)
208 {
209 FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass);
210 klass_device->to_string = fu_vli_usbhub_pd_device_to_string;
211 klass_device->probe = fu_vli_usbhub_pd_device_probe;
212 klass_device->read_firmware = fu_vli_usbhub_pd_device_read_firmware;
213 klass_device->write_firmware = fu_vli_usbhub_pd_device_write_firmware;
214 klass_device->prepare_firmware = fu_vli_usbhub_pd_device_prepare_firmware;
215 }
216
217 FuDevice *
218 fu_vli_usbhub_pd_device_new (FuVliUsbhubPdHdr *hdr)
219 {
220 FuVliUsbhubPdDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_PD_DEVICE, NULL);
221 memcpy (&self->hdr, hdr, sizeof(self->hdr));
222 return FU_DEVICE (self);
223 }
0 /*
1 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
2 *
3 * SPDX-License-Identifier: LGPL-2.1+
4 */
5
6 #pragma once
7
8 #include "fu-plugin.h"
9
10 #define FU_TYPE_VLI_USBHUB_PD_DEVICE (fu_vli_usbhub_pd_device_get_type ())
11 G_DECLARE_FINAL_TYPE (FuVliUsbhubPdDevice, fu_vli_usbhub_pd_device, FU, VLI_USBHUB_PD_DEVICE, FuDevice)
12
13 struct _FuVliUsbhubPdDeviceClass
14 {
15 FuDeviceClass parent_class;
16 };
17
18 FuDevice *fu_vli_usbhub_pd_device_new (FuVliUsbhubPdHdr *hdr);
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #include "config.h"
8
9 #include "fu-vli-usbhub-pd-firmware.h"
10
11 struct _FuVliUsbhubPdFirmware {
12 FuFirmwareClass parent_instance;
13 FuVliUsbhubPdChip chip;
14 FuVliUsbhubPdHdr hdr;
15 };
16
17 G_DEFINE_TYPE (FuVliUsbhubPdFirmware, fu_vli_usbhub_pd_firmware, FU_TYPE_FIRMWARE)
18
19 FuVliUsbhubPdChip
20 fu_vli_usbhub_pd_firmware_get_chip (FuVliUsbhubPdFirmware *self)
21 {
22 g_return_val_if_fail (FU_IS_VLI_USBHUB_PD_FIRMWARE (self), 0);
23 return self->chip;
24 }
25
26 guint16
27 fu_vli_usbhub_pd_firmware_get_vid (FuVliUsbhubPdFirmware *self)
28 {
29 g_return_val_if_fail (FU_IS_VLI_USBHUB_PD_FIRMWARE (self), 0);
30 return GUINT16_FROM_LE (self->hdr.vid);
31 }
32
33 guint16
34 fu_vli_usbhub_pd_firmware_get_pid (FuVliUsbhubPdFirmware *self)
35 {
36 g_return_val_if_fail (FU_IS_VLI_USBHUB_PD_FIRMWARE (self), 0);
37 return GUINT16_FROM_LE (self->hdr.pid);
38 }
39
40 static void
41 fu_vli_usbhub_pd_firmware_to_string (FuFirmware *firmware, guint idt, GString *str)
42 {
43 FuVliUsbhubPdFirmware *self = FU_VLI_USBHUB_PD_FIRMWARE (firmware);
44 fu_common_string_append_kv (str, idt, "ChipId",
45 fu_vli_usbhub_pd_chip_to_string (self->chip));
46 fu_common_string_append_kx (str, idt, "VID",
47 fu_vli_usbhub_pd_firmware_get_vid (self));
48 fu_common_string_append_kx (str, idt, "PID",
49 fu_vli_usbhub_pd_firmware_get_pid (self));
50 }
51
52 static gboolean
53 fu_vli_usbhub_pd_firmware_parse (FuFirmware *firmware,
54 GBytes *fw,
55 guint64 addr_start,
56 guint64 addr_end,
57 FwupdInstallFlags flags,
58 GError **error)
59 {
60 FuVliUsbhubPdFirmware *self = FU_VLI_USBHUB_PD_FIRMWARE (firmware);
61 gsize bufsz = 0;
62 guint32 fwver;
63 const guint8 *buf = g_bytes_get_data (fw, &bufsz);
64 g_autofree gchar *fwver_str = NULL;
65 g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw);
66
67 /* map into header */
68 if (!fu_memcpy_safe ((guint8 *) &self->hdr, sizeof(self->hdr), 0x0,
69 buf, bufsz, VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY,
70 sizeof(self->hdr), error)) {
71 g_prefix_error (error, "failed to read header @0x%x: ", (guint) 0x4000);
72 return FALSE;
73 }
74
75 /* look for info @0x1000 (for anything newer) */
76 if (GUINT16_FROM_LE (self->hdr.vid) != 0x2109) {
77 g_debug ("VID was 0x%04x trying new location",
78 GUINT16_FROM_LE (self->hdr.vid));
79 if (!fu_memcpy_safe ((guint8 *) &self->hdr, sizeof(self->hdr), 0x0,
80 buf, bufsz, VLI_USBHUB_PD_FLASHMAP_ADDR,
81 sizeof(self->hdr), error)) {
82 g_prefix_error (error, "failed to read header @0x%x: ", (guint) 0x1003);
83 return FALSE;
84 }
85 }
86 fwver = GUINT32_FROM_BE (self->hdr.fwver);
87 self->chip = fu_vli_usbhub_pd_guess_chip (fwver);
88 if (self->chip == FU_VLI_USBHUB_PD_CHIP_UNKNOWN) {
89 g_set_error (error,
90 FWUPD_ERROR,
91 FWUPD_ERROR_INVALID_FILE,
92 "version invalid, using 0x%x", fwver);
93 return FALSE;
94 }
95 fwver_str = fu_common_version_from_uint32 (fwver, FWUPD_VERSION_FORMAT_QUAD);
96 fu_firmware_set_version (firmware, fwver_str);
97
98 /* check size */
99 if (bufsz != fu_vli_usbhub_pd_chip_get_size (self->chip)) {
100 g_set_error (error,
101 FWUPD_ERROR,
102 FWUPD_ERROR_INVALID_FILE,
103 "size invalid, got 0x%x expected 0x%x",
104 (guint) bufsz,
105 fu_vli_usbhub_pd_chip_get_size (self->chip));
106 return FALSE;
107 }
108
109 /* check CRC */
110 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
111 guint16 crc_actual;
112 guint16 crc_file = 0x0;
113 if (!fu_common_read_uint16_safe (buf, bufsz, bufsz - 2, &crc_file,
114 G_LITTLE_ENDIAN, error)) {
115 g_prefix_error (error, "failed to read file CRC: ");
116 return FALSE;
117 }
118 crc_actual = fu_vli_usbhub_pd_crc16 (buf, bufsz - 2);
119 if (crc_actual != crc_file) {
120 g_set_error (error,
121 FWUPD_ERROR,
122 FWUPD_ERROR_INVALID_FILE,
123 "CRC invalid, got 0x%x expected 0x%x",
124 crc_file, crc_actual);
125 return FALSE;
126 }
127 }
128
129 /* whole image */
130 fu_firmware_add_image (firmware, img);
131 return TRUE;
132 }
133
134 static void
135 fu_vli_usbhub_pd_firmware_init (FuVliUsbhubPdFirmware *self)
136 {
137 }
138
139 static void
140 fu_vli_usbhub_pd_firmware_class_init (FuVliUsbhubPdFirmwareClass *klass)
141 {
142 FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass);
143 klass_firmware->parse = fu_vli_usbhub_pd_firmware_parse;
144 klass_firmware->to_string = fu_vli_usbhub_pd_firmware_to_string;
145 }
146
147 FuFirmware *
148 fu_vli_usbhub_pd_firmware_new (void)
149 {
150 return FU_FIRMWARE (g_object_new (FU_TYPE_VLI_USBHUB_PD_FIRMWARE, NULL));
151 }
0 /*
1 * Copyright (C) 2017-2019 VIA Corporation
2 * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #pragma once
8
9 #include "fu-firmware.h"
10
11 #include "fu-vli-usbhub-pd-common.h"
12
13 #define FU_TYPE_VLI_USBHUB_PD_FIRMWARE (fu_vli_usbhub_pd_firmware_get_type ())
14 G_DECLARE_FINAL_TYPE (FuVliUsbhubPdFirmware, fu_vli_usbhub_pd_firmware, FU, VLI_USBHUB_PD_FIRMWARE, FuFirmware)
15
16 FuFirmware *fu_vli_usbhub_pd_firmware_new (void);
17 FuVliUsbhubPdChip fu_vli_usbhub_pd_firmware_get_chip (FuVliUsbhubPdFirmware *self);
18 guint16 fu_vli_usbhub_pd_firmware_get_vid (FuVliUsbhubPdFirmware *self);
19 guint16 fu_vli_usbhub_pd_firmware_get_pid (FuVliUsbhubPdFirmware *self);
1313 'fu-vli-usbhub-common.c',
1414 'fu-vli-usbhub-device.c',
1515 'fu-vli-usbhub-firmware.c',
16 'fu-vli-usbhub-i2c-common.c',
17 'fu-vli-usbhub-i2c-device.c',
18 'fu-vli-usbhub-pd-common.c',
19 'fu-vli-usbhub-pd-device.c',
20 'fu-vli-usbhub-pd-firmware.c',
1621 ],
1722 include_directories : [
1823 include_directories('../..'),
1010 ---------------
1111
1212 The HID DeviceInstanceId values are used, e.g. `HIDRAW\VEN_056A&DEV_4875`.
13
14 Additionally, for supported AES devices an extra GUID is added for the hardware
15 ID (e.g. `WACOM\HWID_%04X`) to further disambiguate the panels.
1613
1714 Firmware Format
1815 ---------------
1212 #include "fu-wacom-common.h"
1313 #include "fu-wacom-aes-device.h"
1414
15 typedef struct __attribute__((packed)) {
16 guint8 report_id;
17 guint8 cmd;
18 guint8 echo;
19 guint32 addr;
20 guint8 size8;
21 guint8 data[128];
22 } FuWacomRawVerifyResponse;
23
1524 struct _FuWacomAesDevice {
1625 FuWacomDevice parent_instance;
17 guint32 hwid;
1826 };
1927
2028 G_DEFINE_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU_TYPE_WACOM_DEVICE)
2129
2230 static gboolean
23 fu_wacom_aes_device_obtain_hwid (FuWacomAesDevice *self, GError **error)
24 {
25 guint8 cmd[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 };
26 guint8 buf[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 };
27
28 cmd[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID;
29 cmd[1] = 0x01; /* ?? */
30 cmd[2] = 0x01; /* ?? */
31 cmd[3] = 0x0f; /* ?? */
32
33 if (!fu_wacom_device_set_feature (FU_WACOM_DEVICE (self),
34 cmd, sizeof(cmd), error)) {
31 fu_wacom_aes_add_recovery_hwid (FuDevice *device, GError **error)
32 {
33 FuWacomRawRequest cmd = {
34 .report_id = FU_WACOM_RAW_BL_REPORT_ID_SET,
35 .cmd = FU_WACOM_RAW_BL_CMD_VERIFY_FLASH,
36 .echo = 0x01,
37 .addr = FU_WACOM_RAW_BL_START_ADDR,
38 .size8 = FU_WACOM_RAW_BL_BYTES_CHECK/8,
39 };
40 FuWacomRawVerifyResponse rsp = {
41 .report_id = FU_WACOM_RAW_BL_REPORT_ID_GET,
42 .size8 = 0x00,
43 .data = { 0x00 }
44 };
45 g_autofree gchar *devid1 = NULL;
46 g_autofree gchar *devid2 = NULL;
47 guint16 pid;
48
49
50 if (!fu_wacom_device_set_feature (FU_WACOM_DEVICE (device),
51 (guint8*) &cmd, sizeof(cmd), error)) {
3552 g_prefix_error (error, "failed to send: ");
3653 return FALSE;
3754 }
38 buf[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID;
39 if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self),
40 buf, sizeof(buf), error)) {
55 if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (device),
56 (guint8*) &rsp, sizeof(rsp), error)) {
4157 g_prefix_error (error, "failed to receive: ");
4258 return FALSE;
4359 }
44 if (buf[1] == 0xff) {
60 if (rsp.size8 != cmd.size8) {
4561 g_set_error_literal (error,
4662 G_IO_ERROR,
4763 G_IO_ERROR_NOT_SUPPORTED,
4965 return FALSE;
5066 }
5167
52 /* check magic number */
53 if (memcmp (buf, "\x34\x12\x78\x56\x65\x87\x21\x43", 8) != 0) {
54 g_set_error_literal (error,
55 G_IO_ERROR,
56 G_IO_ERROR_NOT_SUPPORTED,
57 "incorrect magic number");
58 return FALSE;
59 }
60
61 /* format the value */
62 self->hwid = ((guint32) buf[9]) << 24 |
63 ((guint32) buf[8]) << 16 |
64 ((guint32) buf[11]) << 8 |
65 ((guint32) buf[10]);
68 pid = (rsp.data[7] << 8) + (rsp.data[6]);
69 if( (pid == 0xFFFF) || (pid == 0x0000) ) {
70 g_set_error (error,
71 G_IO_ERROR,
72 G_IO_ERROR_NOT_SUPPORTED,
73 "invalid recovery product ID %04x", pid);
74 return FALSE;
75 }
76
77 devid1 = g_strdup_printf ("HIDRAW\\VEN_2D1F&DEV_%04X", pid);
78 devid2 = g_strdup_printf ("HIDRAW\\VEN_056A&DEV_%04X", pid);
79 fu_device_add_instance_id (device, devid1);
80 fu_device_add_instance_id (device, devid2);
81
6682 return TRUE;
6783
6884 }
100116 fu_wacom_aes_device_setup (FuDevice *device, GError **error)
101117 {
102118 FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device);
119 g_autoptr(GError) error_local = NULL;
103120
104121 /* find out if in bootloader mode already */
105122 if (!fu_wacom_aes_query_operation_mode (self, error))
108125 /* get firmware version */
109126 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
110127 fu_device_set_version (device, "0.0", FWUPD_VERSION_FORMAT_PAIR);
128 /* get the recovery PID if supported */
129 if (!fu_wacom_aes_add_recovery_hwid (device, &error_local))
130 g_debug ("failed to get HwID: %s", error_local->message);
111131 } else {
112132 guint32 fw_ver;
113133 guint8 data[FU_WACOM_RAW_STATUS_REPORT_SZ] = {
115135 0x0
116136 };
117137 g_autofree gchar *version = NULL;
118 g_autoptr(GError) error_local = NULL;
119138
120139 if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self),
121140 data, sizeof(data), error))
123142 fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN);
124143 version = g_strdup_printf ("%04x.%02x", fw_ver, data[13]);
125144 fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_PAIR);
126
127 /* get the optional 32 byte HWID and add it as a GUID */
128 if (!fu_wacom_aes_device_obtain_hwid (self, &error_local)) {
129 g_debug ("failed to get HwID: %s", error_local->message);
130 } else {
131 g_autofree gchar *devid = NULL;
132 devid = g_strdup_printf ("WACOM\\HWID_%04X", self->hwid);
133 fu_device_add_instance_id (device, devid);
134 }
135145 }
136146
137147 /* success */
224234 static void
225235 fu_wacom_aes_device_init (FuWacomAesDevice *self)
226236 {
227 fu_device_set_name (FU_DEVICE (self), "Embedded Wacom AES Device");
237 fu_device_set_name (FU_DEVICE (self), "Wacom AES Device");
228238 }
229239
230240 static void
1717 #define FU_WACOM_RAW_FW_CMD_DETACH 0x02
1818 #define FU_WACOM_RAW_FW_REPORT_SZ 2
1919
20 #define FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID 0x09
21 #define FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ 64
20 #define FU_WACOM_RAW_BL_START_ADDR (0x11FF8)
21 #define FU_WACOM_RAW_BL_BYTES_CHECK 8
2222
2323 #define FU_WACOM_RAW_BL_REPORT_ID_SET 0x07
2424 #define FU_WACOM_RAW_BL_REPORT_ID_GET 0x08
339339 fu_wacom_device_init (FuWacomDevice *self)
340340 {
341341 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE);
342 fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL);
342343 }
343344
344345 static void
224224 static void
225225 fu_wacom_emr_device_init (FuWacomEmrDevice *self)
226226 {
227 fu_device_set_name (FU_DEVICE (self), "Embedded Wacom EMR Device");
227 fu_device_set_name (FU_DEVICE (self), "Wacom EMR Device");
228228 }
229229
230230 static void
00 # Devices that do "replug" and thus don't change VID:PID to the bootloader
11 # need to have an extra GUID of WacomAES or WacomEMR added so that the flash
22 # constants are set correctly.
3
4 # Dell Chromebook Enterprise 5300
5 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4946]
6 Plugin = wacom_raw
7 Guid = WacomAES
8
9 # Moffet 14-LGD-TPK
10 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4970]
11 Plugin = wacom_raw
12 Guid = WacomAES
13
14 # Moffet 14-Sharp-HH
15 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4971]
16 Plugin = wacom_raw
17 Guid = WacomAES
18
19 # Moffet 14-Sharp-VIA
20 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4972]
21 Plugin = wacom_raw
22 Guid = WacomAES
23
24 # Moffet 14-Coretronic-TPK
25 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4973]
26 Plugin = wacom_raw
27 Guid = WacomAES
28
29 # Moffet 14-Coretronic-HH
30 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4974]
31 Plugin = wacom_raw
32 Guid = WacomAES
33
34 # Dell Latitude 5175
35 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_4807]
36 Plugin = wacom_raw
37 Guid = WacomAES
38
39 # Dell XPS 12 9250
40 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_4822]
41 Plugin = wacom_raw
42 Guid = WacomAES
43
44 # Dell Venue 8 Pro 5855
45 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_4824]
46 Plugin = wacom_raw
47 Guid = WacomAES
48
49 # Dell XPS 13 9365
50 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_4831]
51 Plugin = wacom_raw
52 Guid = WacomAES
53
54 # Dell Latitude 5285
55 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_484C]
56 Plugin = wacom_raw
57 Guid = WacomAES
58
59 # Dell Latitude 7390 2-in-1
60 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_4841]
61 Plugin = wacom_raw
62 Guid = WacomAES
363
464 # Dell XPS-15 9575
565 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_4875]
666 Plugin = wacom_raw
767 Guid = WacomAES
868
69 # Dell Latitude 7400 2-in-1
70 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_48C9]
71 Plugin = wacom_raw
72 Guid = WacomAES
73
74 # Dell XPS-15 9570
75 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_488F]
76 Plugin = wacom_raw
77 Guid = WacomAES
78
79 # Dell XPS 13 7390 2-in-1
80 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_48ED]
81 Plugin = wacom_raw
82 Guid = WacomAES
83
984 # AES bootloader mode
1085 [DeviceInstanceId=HIDRAW\VEN_056A&DEV_0094]
11 Plugin = wacom_raw
12 Guid = WacomAES
13 Flags = is-bootloader
14
15 # AES bootloader mode
16 [DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_0094]
1786 Plugin = wacom_raw
1887 Guid = WacomAES
1988 Flags = is-bootloader
8080 msgid "%s Update"
8181 msgstr "Actualització de %s"
8282
83 #. TRANSLATORS: warn the user before updating, %1 is a device name
84 #, c-format
85 msgid "%s and all connected devices may not be usable while updating."
86 msgstr "%s i tots els dispositius connectats poden no ser usables en actualitzar."
87
88 #. TRANSLATORS: warn the user before updating, %1 is a device name
89 #, c-format
90 msgid "%s must remain connected for the duration of the update to avoid damage."
91 msgstr "%s haurà d'estar connectat durant tota l'actualització per evitar danys."
92
93 #. TRANSLATORS: warn the user before updating, %1 is a machine name
94 #, c-format
95 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
96 msgstr "%s haurà de romandre connectat a una font d'alimentació durant tota l'actualització per evitar danys."
97
8398 #. TRANSLATORS: duration in days!
8499 #, c-format
85100 msgid "%u day"
259274 msgid "Changed"
260275 msgstr "S'ha canviat"
261276
277 #. TRANSLATORS: command description
278 msgid "Checks cryptographic hash matches firmware"
279 msgstr "Comprova que la suma criptogràfica coincideix amb el microprogramari"
280
262281 #. TRANSLATORS: remote checksum
263282 msgid "Checksum"
264283 msgstr "Suma de comprovació"
268287 msgstr "Trieu un dispositiu:"
269288
270289 #. TRANSLATORS: get interactive prompt
290 msgid "Choose a firmware type:"
291 msgstr "Trieu un tipus de microprogramari:"
292
293 #. TRANSLATORS: get interactive prompt
271294 msgid "Choose a release:"
272295 msgstr "Trieu un alliberament:"
273296
283306 msgid "Command not found"
284307 msgstr "No s'ha trobat cap ordre"
285308
309 #. TRANSLATORS: prompt to apply the update
310 msgid "Continue with update?"
311 msgstr "Continuo amb l'actualització?"
312
286313 #. TRANSLATORS: command description
287314 msgid "Convert firmware to DFU format"
288315 msgstr "Converteix el microprogramari al format DFU"
316
317 #. TRANSLATORS: Device supports some form of checksum verification
318 msgid "Cryptographic hash verification is available"
319 msgstr "Està disponible la verificació de la suma criptogràfica"
289320
290321 #. TRANSLATORS: version number of current firmware
291322 msgid "Current version"
315346 msgid "Details"
316347 msgstr "Detalls"
317348
349 #. TRANSLATORS: description of device ability
350 msgid "Device Flags"
351 msgstr "Etiquetes del dispositiu"
352
318353 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
319354 msgid "Device ID"
320355 msgstr "ID del dispositiu"
323358 msgid "Device added:"
324359 msgstr "S'ha afegit el dispositiu:"
325360
361 #. TRANSLATORS: Device supports a safety mechanism for flashing
362 msgid "Device can recover flash failures"
363 msgstr "El dispositiu pot recuperar fallades de flaix"
364
326365 #. TRANSLATORS: this is when a device has been updated
327366 msgid "Device changed:"
328367 msgstr "S'ha canviat el dispositiu:"
329368
369 #. TRANSLATORS: Is locked and can be unlocked
370 msgid "Device is locked"
371 msgstr "El dispositiu està bloquejat"
372
373 #. TRANSLATORS: Device remains usable during update
374 msgid "Device is usable for the duration of the update"
375 msgstr "El dispositiu es podrà usar durant tota l'actualització"
376
330377 #. TRANSLATORS: this is when a device is hotplugged
331378 msgid "Device removed:"
332379 msgstr "S'ha eliminat el dispositiu:"
333380
381 #. TRANSLATORS: Device supports a safety mechanism for flashing
382 msgid "Device stages updates"
383 msgstr "Etapes d'actualització del dispositiu"
384
385 #. TRANSLATORS: Device update needs to be separately activated
386 msgid "Device update needs activation"
387 msgstr "Cal activar l'actualització del dispositiu"
388
389 #. TRANSLATORS: Device will not return after update completes
390 msgid "Device will not re-appear after update completes"
391 msgstr "El dispositiu no tornarà a aparèixer un cop finalitzada l'actualització"
392
334393 #. TRANSLATORS: a list of successful updates
335394 msgid "Devices that have been updated successfully:"
336395 msgstr "Els dispositius que s'han actualitzat correctament:"
369428 #. TRANSLATORS: turn on all debugging
370429 msgid "Do not include timestamp prefix"
371430 msgstr "No incloure el prefix de la marca de temps"
431
432 #. TRANSLATORS: command line option
433 msgid "Do not perform device safety checks"
434 msgstr "No realitzar les comprovacions de seguretat al dispositiu"
372435
373436 msgid "Do not upload report at this time, but prompt again for future updates"
374437 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
616679 msgid "Gets the results from the last update"
617680 msgstr "Obté els resultats de l'última actualització"
618681
682 #. TRANSLATORS: The hardware is waiting to be replugged
683 msgid "Hardware is waiting to be replugged"
684 msgstr "El maquinari està esperant a ser endollat"
685
619686 #. TRANSLATORS: daemon is inactive
620687 msgid "Idle…"
621688 msgstr "Està ociós..."
624691 msgid "Ignore SSL strict checks when downloading files"
625692 msgstr "Ignora les comprovacions estrictes de SSL quan es baixin els fitxers"
626693
694 #. TRANSLATORS: Ignore validation safety checks when flashing this device
695 msgid "Ignore validation safety checks"
696 msgstr "Ignora les comprovacions de seguretat de validació"
697
627698 #. TRANSLATORS: length of time the update takes to apply
628699 msgid "Install Duration"
629700 msgstr "Durada de la instal·lació"
645716 msgid "Install signed system firmware"
646717 msgstr "Instal·la microprogramari signat per al sistema"
647718
719 #. TRANSLATORS: Install composite firmware on the parent before the child
720 msgid "Install to parent device first"
721 msgstr "Instal·la primer al dispositiu pare"
722
648723 msgid "Install unsigned device firmware"
649724 msgstr "Instal·la microprogramari sense signar per al dispositiu"
650725
663738 #, c-format
664739 msgid "Installing on %s…"
665740 msgstr "S'està intal·lant a %s…"
741
742 #. TRANSLATORS: Device cannot be removed easily
743 msgid "Internal device"
744 msgstr "Dispositiu intern"
745
746 #. TRANSLATORS: Is currently in bootloader mode
747 msgid "Is in bootloader mode"
748 msgstr "Està en el mode carregador d'arrencada"
666749
667750 #. TRANSLATORS: issue fixed with the release, e.g. CVE
668751 msgid "Issue"
695778 msgid "List supported firmware updates"
696779 msgstr "Llista les actualitzacions de microprogramari compatibles"
697780
781 #. TRANSLATORS: command description
782 msgid "List the available firmware types"
783 msgstr "Llista els tipus de microprogramari disponibles"
784
698785 #. TRANSLATORS: parsing the firmware information
699786 msgid "Loading…"
700787 msgstr "S'està carregant..."
746833 msgid "Monitor the daemon for events"
747834 msgstr "Monitora el dimoni pels esdeveniments"
748835
836 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
837 msgid "Needs a reboot after installation"
838 msgstr "Requereix un reinici després de la instal·lació"
839
840 #. TRANSLATORS: Requires system shutdown to apply firmware
841 msgid "Needs shutdown after installation"
842 msgstr "Requereix aturar després de la instal·lació"
843
749844 #. TRANSLATORS: version number of new firmware
750845 msgid "New version"
751846 msgstr "Versió nova"
753848 msgid "No action specified!"
754849 msgstr "No s'ha especificat cap acció!"
755850
851 #. TRANSLATORS: nothing found
852 msgid "No firmware IDs found"
853 msgstr "No s'ha trobat cap ID de microprogramari"
854
756855 #. TRANSLATORS: nothing attached that can be upgraded
757856 msgid "No hardware detected with firmware update capability"
758857 msgstr "No s'ha detectat cap maquinari amb capacitat per a l'actualització del microprogramari"
789888 msgid "Override warnings and force the action"
790889 msgstr "Anul·la els avisos i força l'acció"
791890
891 #. TRANSLATORS: command description
892 msgid "Parse and show details about a firmware file"
893 msgstr "Analitza i mostra els detalls sobre un fitxer de microprogramari"
894
792895 #. TRANSLATORS: remote filename base
793896 msgid "Password"
794897 msgstr "Contrasenya"
831934 msgstr "Consulta el suport per a l'actualització del microprogramari"
832935
833936 #. TRANSLATORS: command description
937 msgid "Read a firmware blob from a device"
938 msgstr "Llegeix un blob de microprogramari des d'un dispositiu"
939
940 #. TRANSLATORS: command description
834941 msgid "Read firmware from device into a file"
835942 msgstr "Llegeix el microprogramari des del dispositiu a un fitxer"
836943
837944 #. TRANSLATORS: command description
838945 msgid "Read firmware from one partition into a file"
839946 msgstr "Llegeix el microprogramari des d'una partició a un fitxer"
947
948 #. TRANSLATORS: %1 is a device name
949 #, c-format
950 msgid "Reading from %s…"
951 msgstr "Llegint des de %s…"
840952
841953 #. TRANSLATORS: reading from the flash chips
842954 msgid "Reading…"
878990 msgid "Report URI"
879991 msgstr "URI de l'informe"
880992
993 #. TRANSLATORS: Has been reported to a metadata server
994 msgid "Reported to remote server"
995 msgstr "Informat al servidor remot"
996
997 #. TRANSLATORS: Must be plugged in to an outlet
998 msgid "Requires AC power"
999 msgstr "Requereix una font d'alimentació"
1000
1001 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1002 msgid "Requires a bootloader"
1003 msgstr "Requereix un carregador d’arrencada"
1004
8811005 #. TRANSLATORS: metadata is downloaded from the Internet
8821006 msgid "Requires internet connection"
8831007 msgstr "Requereix connexió a Internet"
9171041 #. TRANSLATORS: scheduing an update to be done on the next boot
9181042 msgid "Scheduling…"
9191043 msgstr "Planificació..."
1044
1045 #. TRANSLATORS: Device has been chosen by the daemon for the user
1046 msgid "Selected device"
1047 msgstr "Dispositiu seleccionat"
9201048
9211049 #. TRANSLATORS: serial number of hardware
9221050 msgid "Serial Number"
10521180 msgid "Successfully modified configuration value"
10531181 msgstr "S'ha modificat amb èxit el valor de la configuració"
10541182
1183 #. TRANSLATORS: success message for a per-remote setting change
1184 msgid "Successfully modified remote"
1185 msgstr "El remot ha estat modificat amb èxit"
1186
10551187 #. TRANSLATORS: success message -- the user can do this by-hand too
10561188 msgid "Successfully refreshed metadata manually"
10571189 msgstr "S'han refrescat manualment amb èxit les metadades"
1190
1191 #. TRANSLATORS: success message when user refreshes device checksums
1192 msgid "Successfully updated device checksums"
1193 msgstr "S'han actualitzat correctament les sumes de verificació del dispositiu"
10581194
10591195 #. TRANSLATORS: success message -- where the user has uploaded
10601196 #. * success and/or failure reports to the remote server
10641200 msgstr[0] "S'ha enviat %u informe correctament"
10651201 msgstr[1] "S'han enviat %u informes correctament"
10661202
1203 #. TRANSLATORS: success message when user verified device checksums
1204 msgid "Successfully verified device checksums"
1205 msgstr "S'han verificat correctament les sumes de verificació del dispositiu"
1206
10671207 #. TRANSLATORS: one line summary of device
10681208 msgid "Summary"
10691209 msgstr "Resum"
1210
1211 #. TRANSLATORS: Is found in current metadata
1212 msgid "Supported on remote server"
1213 msgstr "Admès en el servidor remot"
10701214
10711215 msgid "Target"
10721216 msgstr "Objectiu"
11241268 msgid "Unsupported daemon version %s, client version is %s"
11251269 msgstr "Versió %s no admesa del dimoni, la versió del client és %s"
11261270
1271 #. TRANSLATORS: Device is updatable in this or any other mode
1272 msgid "Updatable"
1273 msgstr "Actualitzable"
1274
11271275 #. TRANSLATORS: error message from last update attempt
11281276 msgid "Update Error"
11291277 msgstr "Error en actualitzar"
11491297 msgid "Update now?"
11501298 msgstr "Actualitzo ara?"
11511299
1300 #. TRANSLATORS: Update can only be done from offline mode
1301 msgid "Update requires a reboot"
1302 msgstr "L'actualització requereix un reinici"
1303
1304 #. TRANSLATORS: command description
1305 msgid "Update the stored cryptographic hash with current ROM contents"
1306 msgstr "Actualitza la suma criptogràfica emmagatzemada amb el contingut actual de la ROM"
1307
11521308 msgid "Update the stored device verification information"
11531309 msgstr "Actualitza la informació de verificació dels dispositius emmagatzemats"
11541310
11711327 #, c-format
11721328 msgid "Updating %s…"
11731329 msgstr "S'està actualitzant %s…"
1330
1331 #. TRANSLATORS: message letting the user know an upgrade is available
1332 #. * %1 is the device name and %2 and %3 are version strings
1333 #, c-format
1334 msgid "Upgrade available for %s from %s to %s"
1335 msgstr "Actualització disponible per a %s des de %s a %s"
11741336
11751337 #. TRANSLATORS: the server sent the user a small message
11761338 msgid "Upload message:"
11981360 msgid "Use quirk flags when installing firmware"
11991361 msgstr "Usa les etiquetes peculiars en instal·lar el microprogramari"
12001362
1363 #. TRANSLATORS: User has been notified
1364 msgid "User has been notified"
1365 msgstr "S'ha notificat a l'usuari"
1366
12011367 #. TRANSLATORS: remote filename base
12021368 msgid "Username"
12031369 msgstr "Nom d'usuari"
8080 msgid "%s Update"
8181 msgstr "Opdatering for %s"
8282
83 #. TRANSLATORS: warn the user before updating, %1 is a device name
84 #, c-format
85 msgid "%s and all connected devices may not be usable while updating."
86 msgstr "%s og alle tilsluttede enheder vil måske ikke være anvendelige under opdatering."
87
88 #. TRANSLATORS: warn the user before updating, %1 is a device name
89 #, c-format
90 msgid "%s must remain connected for the duration of the update to avoid damage."
91 msgstr "%s skal være tilsluttet under hele opdateringen, for at undgå skade."
92
93 #. TRANSLATORS: warn the user before updating, %1 is a machine name
94 #, c-format
95 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
96 msgstr "%s skal være tilsluttet en strømkilde under hele opdateringen, for at undgå skade."
97
8398 #. TRANSLATORS: duration in days!
8499 #, c-format
85100 msgid "%u day"
259274 msgid "Changed"
260275 msgstr "Ændret"
261276
277 #. TRANSLATORS: command description
278 msgid "Checks cryptographic hash matches firmware"
279 msgstr "Tjekker om den kryptografiske hash passer med firmwaren"
280
262281 #. TRANSLATORS: remote checksum
263282 msgid "Checksum"
264283 msgstr "Checksum"
268287 msgstr "Vælg en enhed:"
269288
270289 #. TRANSLATORS: get interactive prompt
290 msgid "Choose a firmware type:"
291 msgstr "Vælg en firmwaretype:"
292
293 #. TRANSLATORS: get interactive prompt
271294 msgid "Choose a release:"
272295 msgstr "Vælg en udgivelse:"
273296
283306 msgid "Command not found"
284307 msgstr "Kommandoen blev ikke fundet"
285308
309 #. TRANSLATORS: prompt to apply the update
310 msgid "Continue with update?"
311 msgstr "Fortsæt opdateringen?"
312
286313 #. TRANSLATORS: command description
287314 msgid "Convert firmware to DFU format"
288315 msgstr "Konverter firmware til DFU-format"
316
317 #. TRANSLATORS: Device supports some form of checksum verification
318 msgid "Cryptographic hash verification is available"
319 msgstr "Bekræftelse af kryptografisk hash er tilgængelig"
289320
290321 #. TRANSLATORS: version number of current firmware
291322 msgid "Current version"
315346 msgid "Details"
316347 msgstr "Detaljer"
317348
349 #. TRANSLATORS: description of device ability
350 msgid "Device Flags"
351 msgstr "Enhedsflag"
352
318353 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
319354 msgid "Device ID"
320355 msgstr "Enheds-id"
323358 msgid "Device added:"
324359 msgstr "Enhed tilføjet:"
325360
361 #. TRANSLATORS: Device supports a safety mechanism for flashing
362 msgid "Device can recover flash failures"
363 msgstr "Enheden kan gendannes efter mislykkedes flash"
364
326365 #. TRANSLATORS: this is when a device has been updated
327366 msgid "Device changed:"
328367 msgstr "Enhed ændret:"
329368
369 #. TRANSLATORS: Is locked and can be unlocked
370 msgid "Device is locked"
371 msgstr "Enheden er låst"
372
373 #. TRANSLATORS: Device remains usable during update
374 msgid "Device is usable for the duration of the update"
375 msgstr "Enheden kan anvendes under hele opdateringen"
376
330377 #. TRANSLATORS: this is when a device is hotplugged
331378 msgid "Device removed:"
332379 msgstr "Enhed fjernet:"
333380
381 #. TRANSLATORS: Device supports a safety mechanism for flashing
382 msgid "Device stages updates"
383 msgstr "Enhedstrin-opdateringer"
384
385 #. TRANSLATORS: Device update needs to be separately activated
386 msgid "Device update needs activation"
387 msgstr "Enhedsopdatering behøver aktivering"
388
389 #. TRANSLATORS: Device will not return after update completes
390 msgid "Device will not re-appear after update completes"
391 msgstr "Enheden vises ikke igen når opdateringen er færdig"
392
334393 #. TRANSLATORS: a list of successful updates
335394 msgid "Devices that have been updated successfully:"
336395 msgstr "Enheder som det lykkedes at opdatere:"
369428 #. TRANSLATORS: turn on all debugging
370429 msgid "Do not include timestamp prefix"
371430 msgstr "Medtag ikke tidsstempelpræfiks"
431
432 #. TRANSLATORS: command line option
433 msgid "Do not perform device safety checks"
434 msgstr "Udfør ikke sikkerhedstjek af enhed"
372435
373436 msgid "Do not upload report at this time, but prompt again for future updates"
374437 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
616679 msgid "Gets the results from the last update"
617680 msgstr "Henter resultaterne fra den sidste opdatering"
618681
682 #. TRANSLATORS: The hardware is waiting to be replugged
683 msgid "Hardware is waiting to be replugged"
684 msgstr "Hardwaren venter på at bliver gentilkoblet"
685
619686 #. TRANSLATORS: daemon is inactive
620687 msgid "Idle…"
621688 msgstr "Inaktiv …"
624691 msgid "Ignore SSL strict checks when downloading files"
625692 msgstr "Ignorer strikse SSL-tjek ved download af filer"
626693
694 #. TRANSLATORS: Ignore validation safety checks when flashing this device
695 msgid "Ignore validation safety checks"
696 msgstr "Ignorer sikkerhedstjek af bekræftelse"
697
627698 #. TRANSLATORS: length of time the update takes to apply
628699 msgid "Install Duration"
629700 msgstr "Varighed for installation"
645716 msgid "Install signed system firmware"
646717 msgstr "Installer systemfirmware der er underskrevet"
647718
719 #. TRANSLATORS: Install composite firmware on the parent before the child
720 msgid "Install to parent device first"
721 msgstr "Installer først til forælderenhed"
722
648723 msgid "Install unsigned device firmware"
649724 msgstr "Installer enhedsfirmware der ikke er underskrevet"
650725
663738 #, c-format
664739 msgid "Installing on %s…"
665740 msgstr "Installerer på %s …"
741
742 #. TRANSLATORS: Device cannot be removed easily
743 msgid "Internal device"
744 msgstr "Intern enhed"
745
746 #. TRANSLATORS: Is currently in bootloader mode
747 msgid "Is in bootloader mode"
748 msgstr "Er i opstartsindlæsertilstand"
666749
667750 #. TRANSLATORS: issue fixed with the release, e.g. CVE
668751 msgid "Issue"
695778 msgid "List supported firmware updates"
696779 msgstr "Vis understøttede firmwareopdateringer"
697780
781 #. TRANSLATORS: command description
782 msgid "List the available firmware types"
783 msgstr "Vis de tilgængelige firmwaretyper"
784
698785 #. TRANSLATORS: parsing the firmware information
699786 msgid "Loading…"
700787 msgstr "Indlæser …"
746833 msgid "Monitor the daemon for events"
747834 msgstr "Overvåg dæmonen for hændelser"
748835
836 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
837 msgid "Needs a reboot after installation"
838 msgstr "Genstart efter installation er nødvendig"
839
840 #. TRANSLATORS: Requires system shutdown to apply firmware
841 msgid "Needs shutdown after installation"
842 msgstr "Nedlukning efter installation er nødvendig"
843
749844 #. TRANSLATORS: version number of new firmware
750845 msgid "New version"
751846 msgstr "Ny version"
753848 msgid "No action specified!"
754849 msgstr "Der er ikke angivet nogen handling!"
755850
851 #. TRANSLATORS: nothing found
852 msgid "No firmware IDs found"
853 msgstr "Fandt ingen firmware-id'er"
854
756855 #. TRANSLATORS: nothing attached that can be upgraded
757856 msgid "No hardware detected with firmware update capability"
758857 msgstr "Der blev ikke fundet nogen hardware med firmware som kan opdateres"
789888 msgid "Override warnings and force the action"
790889 msgstr "Tilsidesæt advarsler og gennemtving handlingen"
791890
891 #. TRANSLATORS: command description
892 msgid "Parse and show details about a firmware file"
893 msgstr "Fortolk og vis deltaljer om en firmwarefil"
894
792895 #. TRANSLATORS: remote filename base
793896 msgid "Password"
794897 msgstr "Adgangskode"
831934 msgstr "Forespørg om understøttelse af firmwareopdatering"
832935
833936 #. TRANSLATORS: command description
937 msgid "Read a firmware blob from a device"
938 msgstr "Læs en firmwareblob fra en enhed"
939
940 #. TRANSLATORS: command description
834941 msgid "Read firmware from device into a file"
835942 msgstr "Læs firmware fra enhed ind i en fil"
836943
837944 #. TRANSLATORS: command description
838945 msgid "Read firmware from one partition into a file"
839946 msgstr "Læs firmware fra en partition ind i en fil"
947
948 #. TRANSLATORS: %1 is a device name
949 #, c-format
950 msgid "Reading from %s…"
951 msgstr "Læser fra %s …"
840952
841953 #. TRANSLATORS: reading from the flash chips
842954 msgid "Reading…"
878990 msgid "Report URI"
879991 msgstr "Rapport-URI"
880992
993 #. TRANSLATORS: Has been reported to a metadata server
994 msgid "Reported to remote server"
995 msgstr "Rapporteret til fjernserver"
996
997 #. TRANSLATORS: Must be plugged in to an outlet
998 msgid "Requires AC power"
999 msgstr "Kræver strømforsygning"
1000
1001 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1002 msgid "Requires a bootloader"
1003 msgstr "Kræver en opstartsindlæser"
1004
8811005 #. TRANSLATORS: metadata is downloaded from the Internet
8821006 msgid "Requires internet connection"
8831007 msgstr "Kræver internetforbindelse"
9171041 #. TRANSLATORS: scheduing an update to be done on the next boot
9181042 msgid "Scheduling…"
9191043 msgstr "Planlægger …"
1044
1045 #. TRANSLATORS: Device has been chosen by the daemon for the user
1046 msgid "Selected device"
1047 msgstr "Valgte enhed"
9201048
9211049 #. TRANSLATORS: serial number of hardware
9221050 msgid "Serial Number"
10521180 msgid "Successfully modified configuration value"
10531181 msgstr "Det lykkedes at redigere konfigurationsværdi"
10541182
1183 #. TRANSLATORS: success message for a per-remote setting change
1184 msgid "Successfully modified remote"
1185 msgstr "Det lykkedes at redigere fjern"
1186
10551187 #. TRANSLATORS: success message -- the user can do this by-hand too
10561188 msgid "Successfully refreshed metadata manually"
10571189 msgstr "Det lykkedes at opdatere metadata manuelt"
1190
1191 #. TRANSLATORS: success message when user refreshes device checksums
1192 msgid "Successfully updated device checksums"
1193 msgstr "Opdatering af enhedens tjeksumme lykkedes"
10581194
10591195 #. TRANSLATORS: success message -- where the user has uploaded
10601196 #. * success and/or failure reports to the remote server
10641200 msgstr[0] "Det lykkedes at uploade %u rapport"
10651201 msgstr[1] "Det lykkedes at uploade %u rapporter"
10661202
1203 #. TRANSLATORS: success message when user verified device checksums
1204 msgid "Successfully verified device checksums"
1205 msgstr "Bekræftelse af enhedens tjeksumme lykkedes"
1206
10671207 #. TRANSLATORS: one line summary of device
10681208 msgid "Summary"
10691209 msgstr "Opsummering"
1210
1211 #. TRANSLATORS: Is found in current metadata
1212 msgid "Supported on remote server"
1213 msgstr "Understøttes på fjernserver"
10701214
10711215 msgid "Target"
10721216 msgstr "Mål"
11241268 msgid "Unsupported daemon version %s, client version is %s"
11251269 msgstr "Uunderstøttet dæmonversion %s, klientversionen er %s"
11261270
1271 #. TRANSLATORS: Device is updatable in this or any other mode
1272 msgid "Updatable"
1273 msgstr "Kan opdateres"
1274
11271275 #. TRANSLATORS: error message from last update attempt
11281276 msgid "Update Error"
11291277 msgstr "Fejl ved opdatering"
11491297 msgid "Update now?"
11501298 msgstr "Opdater nu?"
11511299
1300 #. TRANSLATORS: Update can only be done from offline mode
1301 msgid "Update requires a reboot"
1302 msgstr "Opdatering kræver en genstart"
1303
1304 #. TRANSLATORS: command description
1305 msgid "Update the stored cryptographic hash with current ROM contents"
1306 msgstr "Opdater den gemte kryptografiske hash med indholdet fra den nuværende ROM"
1307
11521308 msgid "Update the stored device verification information"
11531309 msgstr "Opdaterer de gemte informationer om enhedsverifikation"
11541310
11711327 #, c-format
11721328 msgid "Updating %s…"
11731329 msgstr "Opdaterer %s …"
1330
1331 #. TRANSLATORS: message letting the user know an upgrade is available
1332 #. * %1 is the device name and %2 and %3 are version strings
1333 #, c-format
1334 msgid "Upgrade available for %s from %s to %s"
1335 msgstr "Opgradering tilgængelig for %s fra %s til %s"
11741336
11751337 #. TRANSLATORS: the server sent the user a small message
11761338 msgid "Upload message:"
11981360 msgid "Use quirk flags when installing firmware"
11991361 msgstr "Brug quirk-flag ved installation af firmware"
12001362
1363 #. TRANSLATORS: User has been notified
1364 msgid "User has been notified"
1365 msgstr "Brugeren er blevet underrettet"
1366
12011367 #. TRANSLATORS: remote filename base
12021368 msgid "Username"
12031369 msgstr "Brugernavn"
8080 msgid "%s Update"
8181 msgstr "%sPäivitys"
8282
83 #. TRANSLATORS: warn the user before updating, %1 is a device name
84 #, c-format
85 msgid "%s and all connected devices may not be usable while updating."
86 msgstr "%s ja kaikki kytketyt laitteet eivät välttämättä ole käyttökelpoisia päivityksen aikana."
87
88 #. TRANSLATORS: warn the user before updating, %1 is a device name
89 #, c-format
90 msgid "%s must remain connected for the duration of the update to avoid damage."
91 msgstr "%s on oltava kytkettynä päivityksen ajaksi vaurioiden välttämiseksi."
92
93 #. TRANSLATORS: warn the user before updating, %1 is a machine name
94 #, c-format
95 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
96 msgstr "%s on oltava kytkettynä virtalähteeseen päivityksen ajaksi vaurioiden välttämiseksi."
97
8398 #. TRANSLATORS: duration in days!
8499 #, c-format
85100 msgid "%u day"
259274 msgid "Changed"
260275 msgstr "Muutettu"
261276
277 #. TRANSLATORS: command description
278 msgid "Checks cryptographic hash matches firmware"
279 msgstr "Tarkistaa salaustekniikan, joka vastaa laiteohjelmistoa"
280
262281 #. TRANSLATORS: remote checksum
263282 msgid "Checksum"
264283 msgstr "Tarkistussumma"
268287 msgstr "Valitse laite:"
269288
270289 #. TRANSLATORS: get interactive prompt
290 msgid "Choose a firmware type:"
291 msgstr "Valitse laiteohjelman tyyppi:"
292
293 #. TRANSLATORS: get interactive prompt
271294 msgid "Choose a release:"
272295 msgstr "Valitse julkaisu:"
273296
283306 msgid "Command not found"
284307 msgstr "Komentoa ei löytynyt"
285308
309 #. TRANSLATORS: prompt to apply the update
310 msgid "Continue with update?"
311 msgstr "Jatketaanko päivitystä?"
312
286313 #. TRANSLATORS: command description
287314 msgid "Convert firmware to DFU format"
288315 msgstr "Muunna firmware DFU-muotoon"
316
317 #. TRANSLATORS: Device supports some form of checksum verification
318 msgid "Cryptographic hash verification is available"
319 msgstr "Salauksen algoritmin tarkistus on käytettävissä"
289320
290321 #. TRANSLATORS: version number of current firmware
291322 msgid "Current version"
315346 msgid "Details"
316347 msgstr "Tiedot"
317348
349 #. TRANSLATORS: description of device ability
350 msgid "Device Flags"
351 msgstr "Laitteen liput"
352
318353 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
319354 msgid "Device ID"
320355 msgstr "Laitteen tunnus"
323358 msgid "Device added:"
324359 msgstr "Laite lisätty:"
325360
361 #. TRANSLATORS: Device supports a safety mechanism for flashing
362 msgid "Device can recover flash failures"
363 msgstr "Laite voi palauttaa virheitä"
364
326365 #. TRANSLATORS: this is when a device has been updated
327366 msgid "Device changed:"
328367 msgstr "Laite muutettu:"
329368
369 #. TRANSLATORS: Is locked and can be unlocked
370 msgid "Device is locked"
371 msgstr "Laite on lukittu"
372
373 #. TRANSLATORS: Device remains usable during update
374 msgid "Device is usable for the duration of the update"
375 msgstr "Laitetta voidaan käyttää päivityksen aikana"
376
330377 #. TRANSLATORS: this is when a device is hotplugged
331378 msgid "Device removed:"
332379 msgstr "Laite poistettu:"
333380
381 #. TRANSLATORS: Device supports a safety mechanism for flashing
382 msgid "Device stages updates"
383 msgstr "Laitevyöhykkeen päivitykset"
384
385 #. TRANSLATORS: Device update needs to be separately activated
386 msgid "Device update needs activation"
387 msgstr "Laitteen päivitys tarvitsee aktivointia"
388
389 #. TRANSLATORS: Device will not return after update completes
390 msgid "Device will not re-appear after update completes"
391 msgstr "Laitetta ei näytetä uudelleen päivityksen päätyttyä"
392
334393 #. TRANSLATORS: a list of successful updates
335394 msgid "Devices that have been updated successfully:"
336395 msgstr "Laitteet, jotka on päivitetty onnistuneesti:"
369428 #. TRANSLATORS: turn on all debugging
370429 msgid "Do not include timestamp prefix"
371430 msgstr "Älä sisällytä aikaleiman etuliitettä"
431
432 #. TRANSLATORS: command line option
433 msgid "Do not perform device safety checks"
434 msgstr "Älä suorita laitteen turvallisuustarkastuksia"
372435
373436 msgid "Do not upload report at this time, but prompt again for future updates"
374437 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
616679 msgid "Gets the results from the last update"
617680 msgstr "Saat viimeisimmän päivityksen tulokset"
618681
682 #. TRANSLATORS: The hardware is waiting to be replugged
683 msgid "Hardware is waiting to be replugged"
684 msgstr "Laitteisto odottaa uudelleen kytkemistä"
685
619686 #. TRANSLATORS: daemon is inactive
620687 msgid "Idle…"
621688 msgstr "Jouten…"
624691 msgid "Ignore SSL strict checks when downloading files"
625692 msgstr "Ohita tiukat SSL tarkistukset tiedostoja ladattaessa"
626693
694 #. TRANSLATORS: Ignore validation safety checks when flashing this device
695 msgid "Ignore validation safety checks"
696 msgstr "Ohita turvatarkastukset"
697
627698 #. TRANSLATORS: length of time the update takes to apply
628699 msgid "Install Duration"
629700 msgstr "Asennuksen kesto"
645716 msgid "Install signed system firmware"
646717 msgstr "Asenna allekirjoitettu järjestelmän firmware"
647718
719 #. TRANSLATORS: Install composite firmware on the parent before the child
720 msgid "Install to parent device first"
721 msgstr "Asenna ensin päälaitteelle"
722
648723 msgid "Install unsigned device firmware"
649724 msgstr "Asenna allekirjoittamattoman laitteen firmware"
650725
663738 #, c-format
664739 msgid "Installing on %s…"
665740 msgstr "Asentaa %s…"
741
742 #. TRANSLATORS: Device cannot be removed easily
743 msgid "Internal device"
744 msgstr "Sisäinen laite"
745
746 #. TRANSLATORS: Is currently in bootloader mode
747 msgid "Is in bootloader mode"
748 msgstr "On käynnistyslatain moodissa"
666749
667750 #. TRANSLATORS: issue fixed with the release, e.g. CVE
668751 msgid "Issue"
695778 msgid "List supported firmware updates"
696779 msgstr "Lista tuetuista firmware-päivityksistä"
697780
781 #. TRANSLATORS: command description
782 msgid "List the available firmware types"
783 msgstr "Luettelo käytettävissä olevista laiteohjelmistotyypeistä"
784
698785 #. TRANSLATORS: parsing the firmware information
699786 msgid "Loading…"
700787 msgstr "Ladataan…"
746833 msgid "Monitor the daemon for events"
747834 msgstr "Seuraa tapahtumien taustaprosessia"
748835
836 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
837 msgid "Needs a reboot after installation"
838 msgstr "Tarvitsee käynnistyksen asennuksen jälkeen"
839
840 #. TRANSLATORS: Requires system shutdown to apply firmware
841 msgid "Needs shutdown after installation"
842 msgstr "Tarvitsee sammutuksen asennuksen jälkeen"
843
749844 #. TRANSLATORS: version number of new firmware
750845 msgid "New version"
751846 msgstr "Uusi versio"
753848 msgid "No action specified!"
754849 msgstr "Toimintoa ei ole määritetty!"
755850
851 #. TRANSLATORS: nothing found
852 msgid "No firmware IDs found"
853 msgstr "Laiteohjelmiston tunnuksia ei löytynyt"
854
756855 #. TRANSLATORS: nothing attached that can be upgraded
757856 msgid "No hardware detected with firmware update capability"
758857 msgstr "Ei havaittu sopivaa laitteistoa firmware päivitykselle"
789888 msgid "Override warnings and force the action"
790889 msgstr "Ohita varoitukset ja pakota toiminto"
791890
891 #. TRANSLATORS: command description
892 msgid "Parse and show details about a firmware file"
893 msgstr "Analysoi ja näytä tiedot laiteohjelmiston tiedostosta"
894
792895 #. TRANSLATORS: remote filename base
793896 msgid "Password"
794897 msgstr "Salasana"
831934 msgstr "Kysely firmware-päivityksen tuesta"
832935
833936 #. TRANSLATORS: command description
937 msgid "Read a firmware blob from a device"
938 msgstr "Lue laiteohjelmiston BLOB laitteesta"
939
940 #. TRANSLATORS: command description
834941 msgid "Read firmware from device into a file"
835942 msgstr "Lue firmware laitteesta tiedostoon"
836943
837944 #. TRANSLATORS: command description
838945 msgid "Read firmware from one partition into a file"
839946 msgstr "Lue firmware osiolta tiedostoon"
947
948 #. TRANSLATORS: %1 is a device name
949 #, c-format
950 msgid "Reading from %s…"
951 msgstr "Lukeminen %s…"
840952
841953 #. TRANSLATORS: reading from the flash chips
842954 msgid "Reading…"
878990 msgid "Report URI"
879991 msgstr "Ilmoita URI"
880992
993 #. TRANSLATORS: Has been reported to a metadata server
994 msgid "Reported to remote server"
995 msgstr "Raportoitu etäpalvelimelle"
996
997 #. TRANSLATORS: Must be plugged in to an outlet
998 msgid "Requires AC power"
999 msgstr "Vaatii verkkovirtaa"
1000
1001 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1002 msgid "Requires a bootloader"
1003 msgstr "Vaatii käynnistyslataimen"
1004
8811005 #. TRANSLATORS: metadata is downloaded from the Internet
8821006 msgid "Requires internet connection"
8831007 msgstr "Vaatii Internet-yhteyden"
9171041 #. TRANSLATORS: scheduing an update to be done on the next boot
9181042 msgid "Scheduling…"
9191043 msgstr "Ajoitetaan…"
1044
1045 #. TRANSLATORS: Device has been chosen by the daemon for the user
1046 msgid "Selected device"
1047 msgstr "Valittu laite"
9201048
9211049 #. TRANSLATORS: serial number of hardware
9221050 msgid "Serial Number"
10521180 msgid "Successfully modified configuration value"
10531181 msgstr "Konfigurointiarvo on muokattu onnistuneesti"
10541182
1183 #. TRANSLATORS: success message for a per-remote setting change
1184 msgid "Successfully modified remote"
1185 msgstr "Etäkäytön muokkaus onnistui"
1186
10551187 #. TRANSLATORS: success message -- the user can do this by-hand too
10561188 msgid "Successfully refreshed metadata manually"
10571189 msgstr "Päivitetty metatiedot manuaalisesti"
1190
1191 #. TRANSLATORS: success message when user refreshes device checksums
1192 msgid "Successfully updated device checksums"
1193 msgstr "Laitteiden tarkistussummat päivitettiin onnistuneesti"
10581194
10591195 #. TRANSLATORS: success message -- where the user has uploaded
10601196 #. * success and/or failure reports to the remote server
10641200 msgstr[0] "Raporttien lataus %u onnistui"
10651201 msgstr[1] "Raporttien lataus %u onnistui"
10661202
1203 #. TRANSLATORS: success message when user verified device checksums
1204 msgid "Successfully verified device checksums"
1205 msgstr "Laitteiden tarkistussummat vahvistettu onnistuneesti"
1206
10671207 #. TRANSLATORS: one line summary of device
10681208 msgid "Summary"
10691209 msgstr "Yhteenveto"
1210
1211 #. TRANSLATORS: Is found in current metadata
1212 msgid "Supported on remote server"
1213 msgstr "Tuettu etäpalvelimella"
10701214
10711215 msgid "Target"
10721216 msgstr "Kohde"
11241268 msgid "Unsupported daemon version %s, client version is %s"
11251269 msgstr "Ei tuettu taustaprosessin versio %s, asiakasversio on %s"
11261270
1271 #. TRANSLATORS: Device is updatable in this or any other mode
1272 msgid "Updatable"
1273 msgstr "Päivitettävissä"
1274
11271275 #. TRANSLATORS: error message from last update attempt
11281276 msgid "Update Error"
11291277 msgstr "Päivitys virhe"
11491297 msgid "Update now?"
11501298 msgstr "Päivitä nyt?"
11511299
1300 #. TRANSLATORS: Update can only be done from offline mode
1301 msgid "Update requires a reboot"
1302 msgstr "Päivitys edellyttää käynnistyksen"
1303
1304 #. TRANSLATORS: command description
1305 msgid "Update the stored cryptographic hash with current ROM contents"
1306 msgstr "Päivitä tallennettu salaus nykyisellä ROM-sisällöllä"
1307
11521308 msgid "Update the stored device verification information"
11531309 msgstr "Päivitä laitteen tallennetut vahvistustiedot"
11541310
11711327 #, c-format
11721328 msgid "Updating %s…"
11731329 msgstr "Päivittää %s…"
1330
1331 #. TRANSLATORS: message letting the user know an upgrade is available
1332 #. * %1 is the device name and %2 and %3 are version strings
1333 #, c-format
1334 msgid "Upgrade available for %s from %s to %s"
1335 msgstr "Päivitys saatavilla %s alkaen %s kohde %s"
11741336
11751337 #. TRANSLATORS: the server sent the user a small message
11761338 msgid "Upload message:"
11981360 msgid "Use quirk flags when installing firmware"
11991361 msgstr "Käytä Quirk-lippuja asennettaessa laiteohjelmistoa"
12001362
1363 #. TRANSLATORS: User has been notified
1364 msgid "User has been notified"
1365 msgstr "Käyttäjälle on ilmoitettu"
1366
12011367 #. TRANSLATORS: remote filename base
12021368 msgid "Username"
12031369 msgstr "Käyttäjätunnus"
2424 msgstr[0] "%.0f perc van hátra"
2525 msgstr[1] "%.0f perc van hátra"
2626
27 #. TRANSLATORS: ME stands for Management Engine, where
28 #. * the first %s is the device name, e.g. 'ThinkPad P50`
29 #, c-format
30 msgid "%s Consumer ME Update"
31 msgstr "%s fogyasztói ME frissítés"
32
2733 #. TRANSLATORS: the controller is a device that has other devices
2834 #. * plugged into it, for example ThunderBolt, FireWire or USB,
2935 #. * the first %s is the device name, e.g. 'Intel ThunderBolt`
3036 #, c-format
3137 msgid "%s Controller Update"
3238 msgstr "%s vezérlőfrissítés"
39
40 #. TRANSLATORS: ME stands for Management Engine (with Intel AMT),
41 #. * where the first %s is the device name, e.g. 'ThinkPad P50`
42 #, c-format
43 msgid "%s Corporate ME Update"
44 msgstr "%s vállalati ME frissítés"
3345
3446 #. TRANSLATORS: a specific part of hardware,
3547 #. * the first %s is the device name, e.g. 'Unifying Receiver`
7082 msgid "%s Update"
7183 msgstr "%s frissítés"
7284
85 #. TRANSLATORS: warn the user before updating, %1 is a device name
86 #, c-format
87 msgid "%s and all connected devices may not be usable while updating."
88 msgstr "Lehet, hogy a(z) %s és az összes kapcsolódó eszköz használhatatlan lesz a frissítés alatt."
89
90 #. TRANSLATORS: warn the user before updating, %1 is a device name
91 #, c-format
92 msgid "%s must remain connected for the duration of the update to avoid damage."
93 msgstr "A károsodás elkerülése miatt szükséges, hogy a(z) %s kapcsolódva maradjon a frissítés során."
94
95 #. TRANSLATORS: warn the user before updating, %1 is a machine name
96 #, c-format
97 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
98 msgstr "A károsodás elkerülése miatt szükséges, hogy a(z) %s csatlakoztatva maradjon egy áramforráshoz a frissítés során."
99
73100 #. TRANSLATORS: duration in days!
74101 #, c-format
75102 msgid "%u day"
83110 msgid_plural "%u hours"
84111 msgstr[0] "%u óra"
85112 msgstr[1] "%u óra"
113
114 #. TRANSLATORS: how many local devices can expect updates now
115 #, c-format
116 msgid "%u local device supported"
117 msgid_plural "%u local devices supported"
118 msgstr[0] "%u helyi eszköz támogatott"
119 msgstr[1] "%u helyi eszköz támogatott"
86120
87121 #. TRANSLATORS: duration in minutes
88122 #, c-format
242276 msgid "Changed"
243277 msgstr "Módosítva"
244278
279 #. TRANSLATORS: command description
280 msgid "Checks cryptographic hash matches firmware"
281 msgstr "Ellenőrzi, hogy a kriptográfiai hash egyezik-e a firmware-rel"
282
245283 #. TRANSLATORS: remote checksum
246284 msgid "Checksum"
247285 msgstr "Ellenőrzőösszeg"
251289 msgstr "Válasszon eszközt:"
252290
253291 #. TRANSLATORS: get interactive prompt
292 msgid "Choose a firmware type:"
293 msgstr "Válasszon firmware típust:"
294
295 #. TRANSLATORS: get interactive prompt
254296 msgid "Choose a release:"
255297 msgstr "Válasszon kiadást:"
256298
266308 msgid "Command not found"
267309 msgstr "A parancs nem található"
268310
311 #. TRANSLATORS: prompt to apply the update
312 msgid "Continue with update?"
313 msgstr "Folytatja a frissítést?"
314
269315 #. TRANSLATORS: command description
270316 msgid "Convert firmware to DFU format"
271317 msgstr "Firmware átalakítása DFU formátumra"
318
319 #. TRANSLATORS: Device supports some form of checksum verification
320 msgid "Cryptographic hash verification is available"
321 msgstr "Kriptográfiai hash ellenőrzés érhető el"
272322
273323 #. TRANSLATORS: version number of current firmware
274324 msgid "Current version"
292342
293343 #. TRANSLATORS: command description
294344 msgid "Detach to bootloader mode"
295 msgstr "Leválasztás a indítóbetöltő módhoz"
345 msgstr "Leválasztás a rendszerbetöltő módhoz"
296346
297347 #. TRANSLATORS: more details about the update link
298348 msgid "Details"
299349 msgstr "Részletek"
300350
351 #. TRANSLATORS: description of device ability
352 msgid "Device Flags"
353 msgstr "Eszközjelzők"
354
301355 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
302356 msgid "Device ID"
303357 msgstr "Eszközazonosító"
306360 msgid "Device added:"
307361 msgstr "Eszköz hozzáadva:"
308362
363 #. TRANSLATORS: Device supports a safety mechanism for flashing
364 msgid "Device can recover flash failures"
365 msgstr "Az eszköz képes helyreállni a felülírási hibák után"
366
309367 #. TRANSLATORS: this is when a device has been updated
310368 msgid "Device changed:"
311369 msgstr "Eszköz módosítva:"
312370
371 #. TRANSLATORS: Is locked and can be unlocked
372 msgid "Device is locked"
373 msgstr "Az eszköz zárolt"
374
375 #. TRANSLATORS: Device remains usable during update
376 msgid "Device is usable for the duration of the update"
377 msgstr "Az eszköz használható marad a frissítés ideje alatt"
378
313379 #. TRANSLATORS: this is when a device is hotplugged
314380 msgid "Device removed:"
315381 msgstr "Eszköz eltávolítva:"
316382
383 #. TRANSLATORS: Device supports a safety mechanism for flashing
384 msgid "Device stages updates"
385 msgstr "Az eszköz szakaszosan frissít"
386
387 #. TRANSLATORS: Device update needs to be separately activated
388 msgid "Device update needs activation"
389 msgstr "Az eszközfrissítés aktiválást igényel"
390
391 #. TRANSLATORS: Device will not return after update completes
392 msgid "Device will not re-appear after update completes"
393 msgstr "Az eszköz a frissítés végeztével újra meg fog jelenni"
394
317395 #. TRANSLATORS: a list of successful updates
318396 msgid "Devices that have been updated successfully:"
319397 msgstr "Eszközök, melyek sikeresen frissítve lettek:"
354432 msgstr "Ne tartalmazza az időbélyeg előtagot"
355433
356434 #. TRANSLATORS: command line option
435 msgid "Do not perform device safety checks"
436 msgstr "Ne végezzen eszköz biztonsági ellenőrzéseket"
437
438 msgid "Do not upload report at this time, but prompt again for future updates"
439 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
440 msgstr[0] "Most ne töltsön fel jelentést, de kérdezzen rá a jövőben"
441 msgstr[1] "Most ne töltsön fel jelentéseket, de kérdezzen rá a jövőben"
442
443 msgid "Do not upload report, and never ask to upload reports for future updates"
444 msgid_plural "Do not upload reports, and never ask to upload reports for future updates"
445 msgstr[0] "Ne töltsön fel jelentést, és sose kérdezzen rá a jövőben"
446 msgstr[1] "Ne töltsön fel jelentéseket, és sose kérdezzen rá a jövőben"
447
448 #. TRANSLATORS: command line option
357449 msgid "Do not write to the history database"
358450 msgstr "Ne írjon az előzmények adatbázisába"
359451
462554 #. TRANSLATORS: the user didn't read the man page
463555 msgid "Failed to parse arguments"
464556 msgstr "Nem sikerült feldolgozni az argumentumokat"
557
558 #. TRANSLATORS: the user didn't read the man page
559 msgid "Failed to parse flags for --filter"
560 msgstr "A --filter jelzőinek feldolgozása sikertelen"
465561
466562 #. TRANSLATORS: we could not reboot for some reason
467563 msgid "Failed to reboot"
585681 msgid "Gets the results from the last update"
586682 msgstr "A legutóbbi frissítésből származó eredményeket kéri le"
587683
684 #. TRANSLATORS: The hardware is waiting to be replugged
685 msgid "Hardware is waiting to be replugged"
686 msgstr "A hardver újracsatlakoztatásra vár"
687
588688 #. TRANSLATORS: daemon is inactive
589689 msgid "Idle…"
590690 msgstr "Üresjárat…"
593693 msgid "Ignore SSL strict checks when downloading files"
594694 msgstr "A szogorú SSL ellenőrzések mellőzése a fájlok letöltésekor"
595695
696 #. TRANSLATORS: Ignore validation safety checks when flashing this device
697 msgid "Ignore validation safety checks"
698 msgstr "Biztonsági ellenőrzések mellőzése"
699
596700 #. TRANSLATORS: length of time the update takes to apply
597701 msgid "Install Duration"
598702 msgstr "Telepítés hossza"
614718 msgid "Install signed system firmware"
615719 msgstr "Aláírt rendszer firmware telepítése"
616720
721 #. TRANSLATORS: Install composite firmware on the parent before the child
722 msgid "Install to parent device first"
723 msgstr "Elsőként telepítés a szülő eszközre"
724
617725 msgid "Install unsigned device firmware"
618726 msgstr "Nem aláírt eszköz firmware telepítése"
619727
632740 #, c-format
633741 msgid "Installing on %s…"
634742 msgstr "%s telepítése…"
743
744 #. TRANSLATORS: Device cannot be removed easily
745 msgid "Internal device"
746 msgstr "Belső eszköz"
747
748 #. TRANSLATORS: Is currently in bootloader mode
749 msgid "Is in bootloader mode"
750 msgstr "Rendszerbetöltő módban van"
635751
636752 #. TRANSLATORS: issue fixed with the release, e.g. CVE
637753 msgid "Issue"
664780 msgid "List supported firmware updates"
665781 msgstr "A támogatott firmware-frissítések listázása"
666782
783 #. TRANSLATORS: command description
784 msgid "List the available firmware types"
785 msgstr "Az elérhető firmware típusok listázása"
786
667787 #. TRANSLATORS: parsing the firmware information
668788 msgid "Loading…"
669789 msgstr "Betöltés…"
670790
671791 #. TRANSLATORS: command line option
792 msgid "Log output to FILE (typically for scripting use)"
793 msgstr "Kimenet naplózása FÁJLba (jellemzően parancsfájlokhoz)"
794
795 #. TRANSLATORS: command line option
672796 msgid "Manually whitelist specific plugins"
673797 msgstr "Egyes bővítmények kézi fehérlistára tétele"
674798
688812 msgid "Minimum Version"
689813 msgstr "Legkisebb verzió"
690814
815 #. TRANSLATORS: error message
816 #, c-format
817 msgid "Mismatched daemon and client, use %s instead"
818 msgstr "Eltérő démon és kliens, inkább ezt használja: %s"
819
820 #. TRANSLATORS: sets something in daemon.conf
821 msgid "Modifies a daemon configuration value."
822 msgstr "Módosítja a démon egy konfigurációs értékét."
823
691824 #. TRANSLATORS: command description
692825 msgid "Modifies a given remote"
693826 msgstr "A megadott távoli tároló módosítása"
701834 #. TRANSLATORS: command description
702835 msgid "Monitor the daemon for events"
703836 msgstr "A démon eseményeinek figyelése"
837
838 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
839 msgid "Needs a reboot after installation"
840 msgstr "A telepítés után újraindítást igényel"
841
842 #. TRANSLATORS: Requires system shutdown to apply firmware
843 msgid "Needs shutdown after installation"
844 msgstr "A telepítés után kikapcsolást igényel"
704845
705846 #. TRANSLATORS: version number of new firmware
706847 msgid "New version"
709850 msgid "No action specified!"
710851 msgstr "Nincs művelet megadva!"
711852
853 #. TRANSLATORS: nothing found
854 msgid "No firmware IDs found"
855 msgstr "Nem találhatók firmware azonosítók"
856
712857 #. TRANSLATORS: nothing attached that can be upgraded
713858 msgid "No hardware detected with firmware update capability"
714859 msgstr "Nem észlelhető firmware frissítési képességgel rendelkező hardver"
717862 msgid "No plugins found"
718863 msgstr "Nem található bővítmény"
719864
865 #. TRANSLATORS: no repositories to download from
866 msgid "No releases available"
867 msgstr "Nincsenek elérhető kiadások"
868
720869 #. TRANSLATORS: explain why no metadata available
721870 msgid "No remotes are currently enabled so no metadata is available."
722871 msgstr "Jelenleg nincsenek engedélyezett távoli tárolók, így nem érhetőek el metaadatok."
723872
873 #. TRANSLATORS: no repositories to download from
874 msgid "No remotes available"
875 msgstr "Nincsenek elérhető távoli tárolók"
876
724877 #. TRANSLATORS: nothing was updated offline
725878 msgid "No updates were applied"
726879 msgstr "Nem lett frissítés alkalmazva"
733886 msgid "Override the default ESP path"
734887 msgstr "Az alapértelmezett ESP útvonal felülbírálása"
735888
889 #. TRANSLATORS: command line option
890 msgid "Override warnings and force the action"
891 msgstr "Figyelmeztetések felülbírálása, és a művelet kényszerítése"
892
893 #. TRANSLATORS: command description
894 msgid "Parse and show details about a firmware file"
895 msgstr "A firmware fájl részleteinek értelmezése és megjelenítése"
896
736897 #. TRANSLATORS: remote filename base
737898 msgid "Password"
738899 msgstr "Jelszó"
775936 msgstr "Firmware frissítési támogatás lekérdezése"
776937
777938 #. TRANSLATORS: command description
939 msgid "Read a firmware blob from a device"
940 msgstr "Egy firmware blob beolvasása egy eszközről"
941
942 #. TRANSLATORS: command description
778943 msgid "Read firmware from device into a file"
779944 msgstr "Firmware beolvasása eszközről egy fájlba"
780945
781946 #. TRANSLATORS: command description
782947 msgid "Read firmware from one partition into a file"
783948 msgstr "Firmware beolvasása egy partícióról fájlba"
949
950 #. TRANSLATORS: %1 is a device name
951 #, c-format
952 msgid "Reading from %s…"
953 msgstr "Olvasás a(z) %s eszközről…"
784954
785955 #. TRANSLATORS: reading from the flash chips
786956 msgid "Reading…"
793963 #. TRANSLATORS: command description
794964 msgid "Refresh metadata from remote server"
795965 msgstr "Metaadatok frissítése a távoli kiszolgálóról"
966
967 #. TRANSLATORS: command description
968 msgid "Reinstall current firmware on the device."
969 msgstr "Újratelepíti a jelenlegi firmware-t az eszközön."
796970
797971 #. TRANSLATORS: the first replacement is a display name
798972 #. * e.g. "ColorHugALS" and the second is a version number
818992 msgid "Report URI"
819993 msgstr "Jelentési URI"
820994
995 #. TRANSLATORS: Has been reported to a metadata server
996 msgid "Reported to remote server"
997 msgstr "Jelentve a távoli kiszolgálónak"
998
999 #. TRANSLATORS: Must be plugged in to an outlet
1000 msgid "Requires AC power"
1001 msgstr "Hálózati áramforrás szükséges"
1002
1003 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1004 msgid "Requires a bootloader"
1005 msgstr "Rendszerbetöltő szükséges"
1006
8211007 #. TRANSLATORS: metadata is downloaded from the Internet
8221008 msgid "Requires internet connection"
8231009 msgstr "Internetkapcsolat szükséges"
8261012 msgid "Restart now?"
8271013 msgstr "Újraindítja most?"
8281014
1015 #. TRANSLATORS: configuration changes only take effect on restart
1016 msgid "Restart the daemon to make the change effective?"
1017 msgstr "Újraindítja a démont a változás életbe léptetéséhez?"
1018
8291019 #. TRANSLATORS: restarting the device to pick up new F/W
8301020 msgid "Restarting device…"
8311021 msgstr "Eszköz újraindítása…"
8351025 msgstr "A géphez tartozó összes hardverazonosító visszaadása"
8361026
8371027 #. TRANSLATORS: command line option
1028 msgid "Run the plugin composite cleanup routine when using install-blob"
1029 msgstr "A bővítmény összetett tisztítási rutinjának futtatása az install-blob használatakor"
1030
1031 #. TRANSLATORS: command line option
1032 msgid "Run the plugin composite prepare routine when using install-blob"
1033 msgstr "A bővítmény összetett előkészítési rutinjának futtatása az install-blob használatakor"
1034
1035 #. TRANSLATORS: command line option
8381036 msgid "Save device state into a JSON file between executions"
8391037 msgstr "Eszköz állapotának mentése JSON fájlba a végrehajtások között"
8401038
8461044 msgid "Scheduling…"
8471045 msgstr "Ütemezés…"
8481046
1047 #. TRANSLATORS: Device has been chosen by the daemon for the user
1048 msgid "Selected device"
1049 msgstr "Kiválasztott eszköz"
1050
8491051 #. TRANSLATORS: serial number of hardware
8501052 msgid "Serial Number"
8511053 msgstr "Sorozatszám"
9491151 msgid "Specify the number of bytes per USB transfer"
9501152 msgstr "Adja meg az USB átvitelek bájtjainak számát"
9511153
1154 #. TRANSLATORS: success message -- where activation is making the new
1155 #. * firmware take effect, usually after updating offline
1156 msgid "Successfully activated all devices"
1157 msgstr "Az összes eszköz sikeresen aktiválva"
1158
1159 #. TRANSLATORS: success message
1160 msgid "Successfully disabled remote"
1161 msgstr "Távoli tároló sikeresen letiltva"
1162
1163 #. TRANSLATORS: success message where we made the firmware on the
1164 #. * device older than it was before
1165 msgid "Successfully downgraded device"
1166 msgstr "Eszköz sikeresen visszaállítva"
1167
1168 #. TRANSLATORS: success message -- where 'metadata' is information
1169 #. * about available firmware on the remote server
1170 msgid "Successfully downloaded new metadata: "
1171 msgstr "Új metaadatok sikeresen letöltve:"
1172
1173 #. TRANSLATORS: success message
1174 msgid "Successfully enabled remote"
1175 msgstr "Távoli tároló sikeresen engedélyezve"
1176
1177 #. TRANSLATORS: success message
1178 msgid "Successfully installed firmware"
1179 msgstr "Firmware sikeresen telepítve"
1180
1181 #. TRANSLATORS: success message -- a per-system setting value
1182 msgid "Successfully modified configuration value"
1183 msgstr "Konfigurációs érték sikeresen módosítva"
1184
1185 #. TRANSLATORS: success message for a per-remote setting change
1186 msgid "Successfully modified remote"
1187 msgstr "Távoli tároló sikeresen módosítva"
1188
1189 #. TRANSLATORS: success message -- the user can do this by-hand too
1190 msgid "Successfully refreshed metadata manually"
1191 msgstr "Metaadatok kézi frissítése sikeres"
1192
1193 #. TRANSLATORS: success message when user refreshes device checksums
1194 msgid "Successfully updated device checksums"
1195 msgstr "Eszköz ellenőrzőösszegek sikeresen frissítve"
1196
1197 #. TRANSLATORS: success message -- where the user has uploaded
1198 #. * success and/or failure reports to the remote server
1199 #, c-format
1200 msgid "Successfully uploaded %u report"
1201 msgid_plural "Successfully uploaded %u reports"
1202 msgstr[0] "%u jelentés sikeresen feltöltve"
1203 msgstr[1] "%u jelentés sikeresen feltöltve"
1204
1205 #. TRANSLATORS: success message when user verified device checksums
1206 msgid "Successfully verified device checksums"
1207 msgstr "Eszköz ellenőrzőösszegek sikeresen ellenőrizve"
1208
9521209 #. TRANSLATORS: one line summary of device
9531210 msgid "Summary"
9541211 msgstr "Összegzés"
1212
1213 #. TRANSLATORS: Is found in current metadata
1214 msgid "Supported on remote server"
1215 msgstr "Távoli kiszolgálón nem támogatott "
9551216
9561217 msgid "Target"
9571218 msgstr "Cél"
10041265 msgid "Unset the debugging flag during update"
10051266 msgstr "A hibakeresési jelző kikapcsolása frissítéskor"
10061267
1268 #. TRANSLATORS: error message
1269 #, c-format
1270 msgid "Unsupported daemon version %s, client version is %s"
1271 msgstr "Nem támogatott démonverzió: %s, a kliensverzió %s"
1272
1273 #. TRANSLATORS: Device is updatable in this or any other mode
1274 msgid "Updatable"
1275 msgstr "Frissíthet"
1276
10071277 #. TRANSLATORS: error message from last update attempt
10081278 msgid "Update Error"
10091279 msgstr "Frissítési hiba"
10291299 msgid "Update now?"
10301300 msgstr "Frissíti most?"
10311301
1302 #. TRANSLATORS: Update can only be done from offline mode
1303 msgid "Update requires a reboot"
1304 msgstr "A frissítés újraindítást igényel"
1305
1306 #. TRANSLATORS: command description
1307 msgid "Update the stored cryptographic hash with current ROM contents"
1308 msgstr "A tárolt kriptográfiai hash frissítése a jelenlegi ROM tartalmával"
1309
10321310 msgid "Update the stored device verification information"
10331311 msgstr "A tárolt eszközellenőrzési információk frissítése"
10341312
10521330 msgid "Updating %s…"
10531331 msgstr "%s frissítése…"
10541332
1333 #. TRANSLATORS: message letting the user know an upgrade is available
1334 #. * %1 is the device name and %2 and %3 are version strings
1335 #, c-format
1336 msgid "Upgrade available for %s from %s to %s"
1337 msgstr "%s frissítés érhető el, erről: %s, erre: %s"
1338
10551339 #. TRANSLATORS: the server sent the user a small message
10561340 msgid "Upload message:"
10571341 msgstr "Feltöltési üzenet:"
10581342
1343 msgid "Upload report just this one time, but prompt again for future updates"
1344 msgid_plural "Upload reports just this one time, but prompt again for future updates"
1345 msgstr[0] "Most töltse fel a jelentést, de kérdezzen rá a jövőben"
1346 msgstr[1] "Most töltse fel a jelentéseket, de kérdezzen rá a jövőben"
1347
10591348 #. TRANSLATORS: ask the user to upload
10601349 msgid "Upload report now?"
10611350 msgstr "Feltölti most a jelentést?"
10621351
1352 msgid "Upload report this time and automatically upload reports after completing future updates"
1353 msgid_plural "Upload reports this time and automatically upload reports after completing future updates"
1354 msgstr[0] "Most töltse fel a jelentést, és automatikusan tegye meg ezt a jövőben"
1355 msgstr[1] "Most töltse fel a jelentéseket, és automatikusan tegye meg ezt a jövőben"
1356
10631357 #. TRANSLATORS: explain why we want to upload
10641358 msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices."
10651359 msgstr "A firmware jelentések segítenek a hardvergyártóknak, hogy gyorsan azonosítsák a hibás és sikeres frissítéseket valós eszközökön."
10661360
1361 #. TRANSLATORS: command line option
1362 msgid "Use quirk flags when installing firmware"
1363 msgstr "Kerülőmegoldás jelzők használata a firmware telepítésekor"
1364
1365 #. TRANSLATORS: User has been notified
1366 msgid "User has been notified"
1367 msgstr "A felhasználó értesítve"
1368
10671369 #. TRANSLATORS: remote filename base
10681370 msgid "Username"
10691371 msgstr "Felhasználónév"
10801382 msgid "Verifying…"
10811383 msgstr "Ellenőrzés…"
10821384
1385 #. TRANSLATORS: try to help
1386 msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment"
1387 msgstr "FIGYELMEZTETÉS: A szigorú SSL ellenőrzések mellőzése, ahhoz hogy ezt automatikusan megtegye a jövőben, exportálja a DISABLE_SSL_STRICT változót a környezetében"
1388
10831389 #. TRANSLATORS: waiting for device to do something
10841390 msgid "Waiting…"
10851391 msgstr "Várakozás…"
8080 msgid "%s Update"
8181 msgstr "Aggiornamento di %s"
8282
83 #. TRANSLATORS: warn the user before updating, %1 is a device name
84 #, c-format
85 msgid "%s and all connected devices may not be usable while updating."
86 msgstr "%s e tutti i dispositivi collegati potrebbero non essere utilizzabili durante l'aggiornamento."
87
88 #. TRANSLATORS: warn the user before updating, %1 is a device name
89 #, c-format
90 msgid "%s must remain connected for the duration of the update to avoid damage."
91 msgstr "%s deve rimanere collegato durante l'aggiornamento per evitare possibili danni."
92
93 #. TRANSLATORS: warn the user before updating, %1 is a machine name
94 #, c-format
95 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
96 msgstr "%s deve rimanere collegato alla rete elettrica durante l'aggiornamento per evitare possibili danni."
97
8398 #. TRANSLATORS: duration in days!
8499 #, c-format
85100 msgid "%u day"
259274 msgid "Changed"
260275 msgstr "Modificato"
261276
277 #. TRANSLATORS: command description
278 msgid "Checks cryptographic hash matches firmware"
279 msgstr "Verifica che l'hash crittografico corrisponda col firmware"
280
262281 #. TRANSLATORS: remote checksum
263282 msgid "Checksum"
264283 msgstr "Codice di controllo"
268287 msgstr "Scegliere un dispositivo:"
269288
270289 #. TRANSLATORS: get interactive prompt
290 msgid "Choose a firmware type:"
291 msgstr "Scegliere un tipo di firmware:"
292
293 #. TRANSLATORS: get interactive prompt
271294 msgid "Choose a release:"
272295 msgstr "Scegliere un rilascio:"
273296
283306 msgid "Command not found"
284307 msgstr "Comando non trovato"
285308
309 #. TRANSLATORS: prompt to apply the update
310 msgid "Continue with update?"
311 msgstr "Continuare con l'aggiornamento?"
312
286313 #. TRANSLATORS: command description
287314 msgid "Convert firmware to DFU format"
288315 msgstr "Converte il firmware nel formato DFU"
316
317 #. TRANSLATORS: Device supports some form of checksum verification
318 msgid "Cryptographic hash verification is available"
319 msgstr "È disponibile la verifica dell'hash crittografico"
289320
290321 #. TRANSLATORS: version number of current firmware
291322 msgid "Current version"
315346 msgid "Details"
316347 msgstr "Dettagli"
317348
349 #. TRANSLATORS: description of device ability
350 msgid "Device Flags"
351 msgstr "Flag dispositivo"
352
318353 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
319354 msgid "Device ID"
320355 msgstr "ID dispositivo"
323358 msgid "Device added:"
324359 msgstr "Dispositivo aggiunto:"
325360
361 #. TRANSLATORS: Device supports a safety mechanism for flashing
362 msgid "Device can recover flash failures"
363 msgstr "Il dispositivo è in grado di correggere problemi di flash"
364
326365 #. TRANSLATORS: this is when a device has been updated
327366 msgid "Device changed:"
328367 msgstr "Dispositivo modificato:"
329368
369 #. TRANSLATORS: Is locked and can be unlocked
370 msgid "Device is locked"
371 msgstr "Il dispositivo è bloccato"
372
373 #. TRANSLATORS: Device remains usable during update
374 msgid "Device is usable for the duration of the update"
375 msgstr "Il dispositivo è utilizzabile per la durata dell'aggiornamento"
376
330377 #. TRANSLATORS: this is when a device is hotplugged
331378 msgid "Device removed:"
332379 msgstr "Dispositivo rimosso:"
333380
381 #. TRANSLATORS: Device supports a safety mechanism for flashing
382 msgid "Device stages updates"
383 msgstr "Il dispositivo applica gli aggiornamenti a fasi"
384
385 #. TRANSLATORS: Device update needs to be separately activated
386 msgid "Device update needs activation"
387 msgstr "L'aggiornamento del dispositivo richiede l'attivazione"
388
389 #. TRANSLATORS: Device will not return after update completes
390 msgid "Device will not re-appear after update completes"
391 msgstr "Il dispositivo non comparirà nuovamente dopo l'aggiornamento"
392
334393 #. TRANSLATORS: a list of successful updates
335394 msgid "Devices that have been updated successfully:"
336395 msgstr "Dispositivi aggiornati con successo:"
369428 #. TRANSLATORS: turn on all debugging
370429 msgid "Do not include timestamp prefix"
371430 msgstr "Non include il prefisso della marcatura temporale"
431
432 #. TRANSLATORS: command line option
433 msgid "Do not perform device safety checks"
434 msgstr "Non esegue i controlli di sicurezza del dispositivo"
372435
373436 msgid "Do not upload report at this time, but prompt again for future updates"
374437 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
616679 msgid "Gets the results from the last update"
617680 msgstr "Ottiene i risultati dell'ultimo aggiornamento"
618681
682 #. TRANSLATORS: The hardware is waiting to be replugged
683 msgid "Hardware is waiting to be replugged"
684 msgstr "L'hardware è in attesa di essere ricollegato"
685
619686 #. TRANSLATORS: daemon is inactive
620687 msgid "Idle…"
621688 msgstr "Inattivo…"
624691 msgid "Ignore SSL strict checks when downloading files"
625692 msgstr "Ignora controlli SSL nello scaricare i file"
626693
694 #. TRANSLATORS: Ignore validation safety checks when flashing this device
695 msgid "Ignore validation safety checks"
696 msgstr "Ignora i controlli di sicurezza di validazione"
697
627698 #. TRANSLATORS: length of time the update takes to apply
628699 msgid "Install Duration"
629700 msgstr "Tempo di installazione"
645716 msgid "Install signed system firmware"
646717 msgstr "Installa firmware firmato di sistema"
647718
719 #. TRANSLATORS: Install composite firmware on the parent before the child
720 msgid "Install to parent device first"
721 msgstr "Installare sul dispositivo genitore prima"
722
648723 msgid "Install unsigned device firmware"
649724 msgstr "Installa firmware non firmato del dispositivo"
650725
663738 #, c-format
664739 msgid "Installing on %s…"
665740 msgstr "Installazione su %s…"
741
742 #. TRANSLATORS: Device cannot be removed easily
743 msgid "Internal device"
744 msgstr "Dispositivo interno"
745
746 #. TRANSLATORS: Is currently in bootloader mode
747 msgid "Is in bootloader mode"
748 msgstr "È in modalità bootloader"
666749
667750 #. TRANSLATORS: issue fixed with the release, e.g. CVE
668751 msgid "Issue"
695778 msgid "List supported firmware updates"
696779 msgstr "Elenca gli aggiornamenti firmware supportati"
697780
781 #. TRANSLATORS: command description
782 msgid "List the available firmware types"
783 msgstr "Elenca tutti i tipi di firmware disponibili"
784
698785 #. TRANSLATORS: parsing the firmware information
699786 msgid "Loading…"
700787 msgstr "Caricamento…"
746833 msgid "Monitor the daemon for events"
747834 msgstr "Controlla il demone per gli eventi"
748835
836 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
837 msgid "Needs a reboot after installation"
838 msgstr "Necessita un riavvio dopo l'installazione"
839
840 #. TRANSLATORS: Requires system shutdown to apply firmware
841 msgid "Needs shutdown after installation"
842 msgstr "Necessita l'arresto dopo l'installazione"
843
749844 #. TRANSLATORS: version number of new firmware
750845 msgid "New version"
751846 msgstr "Nuova versione"
753848 msgid "No action specified!"
754849 msgstr "Nessuna azione specificata."
755850
851 #. TRANSLATORS: nothing found
852 msgid "No firmware IDs found"
853 msgstr "Nessun ID firmware trovato"
854
756855 #. TRANSLATORS: nothing attached that can be upgraded
757856 msgid "No hardware detected with firmware update capability"
758857 msgstr "Non è stato rilevato nessun hardware con capacità di aggiornamento del firmware"
789888 msgid "Override warnings and force the action"
790889 msgstr "Scavalca gli avvisi e forza l'azione"
791890
891 #. TRANSLATORS: command description
892 msgid "Parse and show details about a firmware file"
893 msgstr "Legge e mostra i dettagli riguardo a un file firmware"
894
792895 #. TRANSLATORS: remote filename base
793896 msgid "Password"
794897 msgstr "Password"
831934 msgstr "Interroga il supporto per gli aggiornamenti firmware"
832935
833936 #. TRANSLATORS: command description
937 msgid "Read a firmware blob from a device"
938 msgstr "Legge un blob firmware da un dispositivo"
939
940 #. TRANSLATORS: command description
834941 msgid "Read firmware from device into a file"
835942 msgstr "Legge il firmware dal dispositivo in un file"
836943
837944 #. TRANSLATORS: command description
838945 msgid "Read firmware from one partition into a file"
839946 msgstr "Legge il firmware da una partizione in un file"
947
948 #. TRANSLATORS: %1 is a device name
949 #, c-format
950 msgid "Reading from %s…"
951 msgstr "Lettura da %s…"
840952
841953 #. TRANSLATORS: reading from the flash chips
842954 msgid "Reading…"
878990 msgid "Report URI"
879991 msgstr "URI del rapporto"
880992
993 #. TRANSLATORS: Has been reported to a metadata server
994 msgid "Reported to remote server"
995 msgstr "Segnalato al server remoto"
996
997 #. TRANSLATORS: Must be plugged in to an outlet
998 msgid "Requires AC power"
999 msgstr "Richiede corrente elettrica"
1000
1001 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1002 msgid "Requires a bootloader"
1003 msgstr "Richiede un bootloader"
1004
8811005 #. TRANSLATORS: metadata is downloaded from the Internet
8821006 msgid "Requires internet connection"
8831007 msgstr "Richiede una connessione a Internet"
9171041 #. TRANSLATORS: scheduing an update to be done on the next boot
9181042 msgid "Scheduling…"
9191043 msgstr "Pianificazione…"
1044
1045 #. TRANSLATORS: Device has been chosen by the daemon for the user
1046 msgid "Selected device"
1047 msgstr "Dispositivo selezionato"
9201048
9211049 #. TRANSLATORS: serial number of hardware
9221050 msgid "Serial Number"
10521180 msgid "Successfully modified configuration value"
10531181 msgstr "Valore della configurazione modificato con successo"
10541182
1183 #. TRANSLATORS: success message for a per-remote setting change
1184 msgid "Successfully modified remote"
1185 msgstr "Remoto modificato con successo"
1186
10551187 #. TRANSLATORS: success message -- the user can do this by-hand too
10561188 msgid "Successfully refreshed metadata manually"
10571189 msgstr "Metadati aggiornati manualmente con successo"
1190
1191 #. TRANSLATORS: success message when user refreshes device checksums
1192 msgid "Successfully updated device checksums"
1193 msgstr "Codici di controllo del dispositivo aggiornati con successo"
10581194
10591195 #. TRANSLATORS: success message -- where the user has uploaded
10601196 #. * success and/or failure reports to the remote server
10641200 msgstr[0] "%u rapporto caricato con successo"
10651201 msgstr[1] "%u rapporti caricati con successo"
10661202
1203 #. TRANSLATORS: success message when user verified device checksums
1204 msgid "Successfully verified device checksums"
1205 msgstr "Codici di controllo del dispositivo verificati con successo"
1206
10671207 #. TRANSLATORS: one line summary of device
10681208 msgid "Summary"
10691209 msgstr "Riepilogo"
1210
1211 #. TRANSLATORS: Is found in current metadata
1212 msgid "Supported on remote server"
1213 msgstr "Supportato sul server remoto"
10701214
10711215 msgid "Target"
10721216 msgstr "Obiettivo"
11241268 msgid "Unsupported daemon version %s, client version is %s"
11251269 msgstr "Demone versione %s non supportato, la versione del client è %s"
11261270
1271 #. TRANSLATORS: Device is updatable in this or any other mode
1272 msgid "Updatable"
1273 msgstr "Aggiornabile"
1274
11271275 #. TRANSLATORS: error message from last update attempt
11281276 msgid "Update Error"
11291277 msgstr "Errore aggiornamento"
11491297 msgid "Update now?"
11501298 msgstr "Aggiornare ora?"
11511299
1300 #. TRANSLATORS: Update can only be done from offline mode
1301 msgid "Update requires a reboot"
1302 msgstr "L'aggiornamento richiede il riavvio"
1303
1304 #. TRANSLATORS: command description
1305 msgid "Update the stored cryptographic hash with current ROM contents"
1306 msgstr "Aggiorna l'hash crittografico archiviato con il contenuto della ROM"
1307
11521308 msgid "Update the stored device verification information"
11531309 msgstr "Aggiornamento delle informazioni di verifica del dispositivo salvate"
11541310
11711327 #, c-format
11721328 msgid "Updating %s…"
11731329 msgstr "Aggiornamento di %s…"
1330
1331 #. TRANSLATORS: message letting the user know an upgrade is available
1332 #. * %1 is the device name and %2 and %3 are version strings
1333 #, c-format
1334 msgid "Upgrade available for %s from %s to %s"
1335 msgstr "Aggiornamento disponibile per %s da %s a %s"
11741336
11751337 #. TRANSLATORS: the server sent the user a small message
11761338 msgid "Upload message:"
11981360 msgid "Use quirk flags when installing firmware"
11991361 msgstr "Usa flag quirk nell'installare il firmware"
12001362
1363 #. TRANSLATORS: User has been notified
1364 msgid "User has been notified"
1365 msgstr "Notifica inviata all'utente"
1366
12011367 #. TRANSLATORS: remote filename base
12021368 msgid "Username"
12031369 msgstr "Nome utente"
8181 msgid "%s Update"
8282 msgstr "Aktualizacja urządzenia %s"
8383
84 #. TRANSLATORS: warn the user before updating, %1 is a device name
85 #, c-format
86 msgid "%s and all connected devices may not be usable while updating."
87 msgstr "%s i wszystkie podłączone urządzenia nie będą mogły być używane podczas aktualizacji."
88
89 #. TRANSLATORS: warn the user before updating, %1 is a device name
90 #, c-format
91 msgid "%s must remain connected for the duration of the update to avoid damage."
92 msgstr "Urządzenie %s musi być podłączone podczas trwania aktualizacji, aby uniknąć uszkodzenia."
93
94 #. TRANSLATORS: warn the user before updating, %1 is a machine name
95 #, c-format
96 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
97 msgstr "Urządzenie %s musi być podłączone do prądu podczas trwania aktualizacji, aby uniknąć uszkodzenia."
98
8499 #. TRANSLATORS: duration in days!
85100 #, c-format
86101 msgid "%u day"
272287 msgid "Changed"
273288 msgstr "Zmieniono"
274289
290 #. TRANSLATORS: command description
291 msgid "Checks cryptographic hash matches firmware"
292 msgstr "Sprawdza, czy kryptograficzna suma kontrolna pasuje do oprogramowania sprzętowego"
293
275294 #. TRANSLATORS: remote checksum
276295 msgid "Checksum"
277296 msgstr "Suma kontrolna"
281300 msgstr "Wybór urządzenia:"
282301
283302 #. TRANSLATORS: get interactive prompt
303 msgid "Choose a firmware type:"
304 msgstr "Wybór typu oprogramowania sprzętowego:"
305
306 #. TRANSLATORS: get interactive prompt
284307 msgid "Choose a release:"
285308 msgstr "Wybór wydania:"
286309
296319 msgid "Command not found"
297320 msgstr "Nie odnaleziono polecenia"
298321
322 #. TRANSLATORS: prompt to apply the update
323 msgid "Continue with update?"
324 msgstr "Kontynuować aktualizację?"
325
299326 #. TRANSLATORS: command description
300327 msgid "Convert firmware to DFU format"
301328 msgstr "Konwertuje oprogramowanie sprzętowe do formatu DFU"
329
330 #. TRANSLATORS: Device supports some form of checksum verification
331 msgid "Cryptographic hash verification is available"
332 msgstr "Dostępne jest sprawdzenie poprawności kryptograficznej sumy kontrolnej"
302333
303334 #. TRANSLATORS: version number of current firmware
304335 msgid "Current version"
328359 msgid "Details"
329360 msgstr "Informacje"
330361
362 #. TRANSLATORS: description of device ability
363 msgid "Device Flags"
364 msgstr "Flagi urządzenia"
365
331366 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
332367 msgid "Device ID"
333368 msgstr "Identyfikator urządzenia"
336371 msgid "Device added:"
337372 msgstr "Dodano urządzenie:"
338373
374 #. TRANSLATORS: Device supports a safety mechanism for flashing
375 msgid "Device can recover flash failures"
376 msgstr "Urządzenie może przywrócić się po niepowodzeniu wgrywania"
377
339378 #. TRANSLATORS: this is when a device has been updated
340379 msgid "Device changed:"
341380 msgstr "Zmieniono urządzenie:"
342381
382 #. TRANSLATORS: Is locked and can be unlocked
383 msgid "Device is locked"
384 msgstr "Urządzenie jest zablokowane"
385
386 #. TRANSLATORS: Device remains usable during update
387 msgid "Device is usable for the duration of the update"
388 msgstr "Urządzenie może być używane podczas trwania aktualizacji"
389
343390 #. TRANSLATORS: this is when a device is hotplugged
344391 msgid "Device removed:"
345392 msgstr "Usunięto urządzenie:"
346393
394 #. TRANSLATORS: Device supports a safety mechanism for flashing
395 msgid "Device stages updates"
396 msgstr "Urządzenie przygotowuje aktualizacje"
397
398 #. TRANSLATORS: Device update needs to be separately activated
399 msgid "Device update needs activation"
400 msgstr "Aktualizacja urządzenia wymaga aktywacji"
401
402 #. TRANSLATORS: Device will not return after update completes
403 msgid "Device will not re-appear after update completes"
404 msgstr "Urządzenie nie pojawi się z powrotem po ukończeniu aktualizacji"
405
347406 #. TRANSLATORS: a list of successful updates
348407 msgid "Devices that have been updated successfully:"
349408 msgstr "Pomyślnie zaktualizowane urządzenia:"
382441 #. TRANSLATORS: turn on all debugging
383442 msgid "Do not include timestamp prefix"
384443 msgstr "Bez dołączania przedrostka czasu"
444
445 #. TRANSLATORS: command line option
446 msgid "Do not perform device safety checks"
447 msgstr "Bez wykonywania testów bezpieczeństwa urządzenia"
385448
386449 msgid "Do not upload report at this time, but prompt again for future updates"
387450 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
637700 msgid "Gets the results from the last update"
638701 msgstr "Uzyskuje wyniki z ostatniej aktualizacji"
639702
703 #. TRANSLATORS: The hardware is waiting to be replugged
704 msgid "Hardware is waiting to be replugged"
705 msgstr "Sprzęt czeka na ponowne podłączenie"
706
640707 #. TRANSLATORS: daemon is inactive
641708 msgid "Idle…"
642709 msgstr "Bezczynne…"
645712 msgid "Ignore SSL strict checks when downloading files"
646713 msgstr "Ignoruje ścisłe testy SSL podczas pobierania plików"
647714
715 #. TRANSLATORS: Ignore validation safety checks when flashing this device
716 msgid "Ignore validation safety checks"
717 msgstr "Ignoruje testy bezpieczeństwa i sprawdzanie poprawności"
718
648719 #. TRANSLATORS: length of time the update takes to apply
649720 msgid "Install Duration"
650721 msgstr "Czas trwania instalacji"
666737 msgid "Install signed system firmware"
667738 msgstr "Instalacja podpisanego oprogramowania sprzętowego komputera"
668739
740 #. TRANSLATORS: Install composite firmware on the parent before the child
741 msgid "Install to parent device first"
742 msgstr "Instaluje najpierw na urządzeniu nadrzędnym"
743
669744 msgid "Install unsigned device firmware"
670745 msgstr "Instalacja niepodpisanego oprogramowania sprzętowego urządzenia"
671746
684759 #, c-format
685760 msgid "Installing on %s…"
686761 msgstr "Instalowanie na urządzeniu %s…"
762
763 #. TRANSLATORS: Device cannot be removed easily
764 msgid "Internal device"
765 msgstr "Wewnętrzne urządzenie"
766
767 #. TRANSLATORS: Is currently in bootloader mode
768 msgid "Is in bootloader mode"
769 msgstr "Jest w trybie programu startowego"
687770
688771 #. TRANSLATORS: issue fixed with the release, e.g. CVE
689772 msgid "Issue"
718801 msgid "List supported firmware updates"
719802 msgstr "Wyświetla listę obsługiwanych aktualizacji oprogramowania sprzętowego"
720803
804 #. TRANSLATORS: command description
805 msgid "List the available firmware types"
806 msgstr "Wyświetla listę dostępnych typów oprogramowania sprzętowego"
807
721808 #. TRANSLATORS: parsing the firmware information
722809 msgid "Loading…"
723810 msgstr "Wczytywanie…"
769856 msgid "Monitor the daemon for events"
770857 msgstr "Monitoruje zdarzenia usługi"
771858
859 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
860 msgid "Needs a reboot after installation"
861 msgstr "Wymaga ponownego uruchomienia po instalacji"
862
863 #. TRANSLATORS: Requires system shutdown to apply firmware
864 msgid "Needs shutdown after installation"
865 msgstr "Wymaga wyłączenia komputera po instalacji"
866
772867 #. TRANSLATORS: version number of new firmware
773868 msgid "New version"
774869 msgstr "Nowa wersja"
776871 msgid "No action specified!"
777872 msgstr "Nie podano działania."
778873
874 #. TRANSLATORS: nothing found
875 msgid "No firmware IDs found"
876 msgstr "Nie odnaleziono identyfikatorów oprogramowania sprzętowego"
877
779878 #. TRANSLATORS: nothing attached that can be upgraded
780879 msgid "No hardware detected with firmware update capability"
781880 msgstr "Nie wykryto sprzętu z możliwością aktualizacji jego oprogramowania"
812911 msgid "Override warnings and force the action"
813912 msgstr "Zastępuje ostrzeżenia i wymusza działanie"
814913
914 #. TRANSLATORS: command description
915 msgid "Parse and show details about a firmware file"
916 msgstr "Przetwarza i wyświetla informacje o pliku oprogramowania sprzętowego"
917
815918 #. TRANSLATORS: remote filename base
816919 msgid "Password"
817920 msgstr "Hasło"
854957 msgstr "Odpytuje obsługę aktualizacji oprogramowania sprzętowego"
855958
856959 #. TRANSLATORS: command description
960 msgid "Read a firmware blob from a device"
961 msgstr "Odczytuje zamknięte oprogramowanie sprzętowe z urządzenia"
962
963 #. TRANSLATORS: command description
857964 msgid "Read firmware from device into a file"
858965 msgstr "Odczytuje oprogramowanie sprzętowe z urządzenia do pliku"
859966
860967 #. TRANSLATORS: command description
861968 msgid "Read firmware from one partition into a file"
862969 msgstr "Odczytuje oprogramowanie sprzętowe z jednej partycji do pliku"
970
971 #. TRANSLATORS: %1 is a device name
972 #, c-format
973 msgid "Reading from %s…"
974 msgstr "Odczytywanie z urządzenia %s…"
863975
864976 #. TRANSLATORS: reading from the flash chips
865977 msgid "Reading…"
9011013 msgid "Report URI"
9021014 msgstr "Adres URI zgłoszenia"
9031015
1016 #. TRANSLATORS: Has been reported to a metadata server
1017 msgid "Reported to remote server"
1018 msgstr "Zgłoszone do zdalnego serwera"
1019
1020 #. TRANSLATORS: Must be plugged in to an outlet
1021 msgid "Requires AC power"
1022 msgstr "Wymaga zasilania z gniazdka"
1023
1024 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1025 msgid "Requires a bootloader"
1026 msgstr "Wymaga programu startowego"
1027
9041028 #. TRANSLATORS: metadata is downloaded from the Internet
9051029 msgid "Requires internet connection"
9061030 msgstr "Wymaga połączenia z Internetem"
9401064 #. TRANSLATORS: scheduing an update to be done on the next boot
9411065 msgid "Scheduling…"
9421066 msgstr "Planowanie…"
1067
1068 #. TRANSLATORS: Device has been chosen by the daemon for the user
1069 msgid "Selected device"
1070 msgstr "Wybrane urządzenie"
9431071
9441072 #. TRANSLATORS: serial number of hardware
9451073 msgid "Serial Number"
10751203 msgid "Successfully modified configuration value"
10761204 msgstr "Pomyślnie zmodyfikowano wartość konfiguracji"
10771205
1206 #. TRANSLATORS: success message for a per-remote setting change
1207 msgid "Successfully modified remote"
1208 msgstr "Pomyślnie zmodyfikowano repozytorium"
1209
10781210 #. TRANSLATORS: success message -- the user can do this by-hand too
10791211 msgid "Successfully refreshed metadata manually"
10801212 msgstr "Pomyślnie ręcznie odświeżono metadane"
1213
1214 #. TRANSLATORS: success message when user refreshes device checksums
1215 msgid "Successfully updated device checksums"
1216 msgstr "Pomyślnie zaktualizowano sumy kontrolne urządzenia"
10811217
10821218 #. TRANSLATORS: success message -- where the user has uploaded
10831219 #. * success and/or failure reports to the remote server
10891225 msgstr[2] "Pomyślnie wysłano %u zgłoszeń"
10901226 msgstr[3] "Pomyślnie wysłano %u zgłoszeń"
10911227
1228 #. TRANSLATORS: success message when user verified device checksums
1229 msgid "Successfully verified device checksums"
1230 msgstr "Pomyślnie sprawdzono poprawność sum kontrolnych urządzenia"
1231
10921232 #. TRANSLATORS: one line summary of device
10931233 msgid "Summary"
10941234 msgstr "Podsumowanie"
1235
1236 #. TRANSLATORS: Is found in current metadata
1237 msgid "Supported on remote server"
1238 msgstr "Obsługiwane na zdalnym serwerze"
10951239
10961240 msgid "Target"
10971241 msgstr "Cel"
11491293 msgid "Unsupported daemon version %s, client version is %s"
11501294 msgstr "Nieobsługiwana wersja usługi %s, wersja klienta to %s"
11511295
1296 #. TRANSLATORS: Device is updatable in this or any other mode
1297 msgid "Updatable"
1298 msgstr "Można aktualizować"
1299
11521300 #. TRANSLATORS: error message from last update attempt
11531301 msgid "Update Error"
11541302 msgstr "Błąd aktualizacji"
11741322 msgid "Update now?"
11751323 msgstr "Zaktualizować teraz?"
11761324
1325 #. TRANSLATORS: Update can only be done from offline mode
1326 msgid "Update requires a reboot"
1327 msgstr "Aktualizacja wymaga ponownego uruchomienia"
1328
1329 #. TRANSLATORS: command description
1330 msgid "Update the stored cryptographic hash with current ROM contents"
1331 msgstr "Aktualizuje przechowywaną kryptograficzną sumę kontrolną bieżącą zawartością pamięci ROM"
1332
11771333 msgid "Update the stored device verification information"
11781334 msgstr "Aktualizacja przechowywanych informacji o poprawności urządzenia"
11791335
11961352 #, c-format
11971353 msgid "Updating %s…"
11981354 msgstr "Aktualizowanie urządzenia %s…"
1355
1356 #. TRANSLATORS: message letting the user know an upgrade is available
1357 #. * %1 is the device name and %2 and %3 are version strings
1358 #, c-format
1359 msgid "Upgrade available for %s from %s to %s"
1360 msgstr "Dostępna jest aktualizacja urządzenia %s z wersji %s do %s"
11991361
12001362 #. TRANSLATORS: the server sent the user a small message
12011363 msgid "Upload message:"
12271389 msgid "Use quirk flags when installing firmware"
12281390 msgstr "Używa flag poprawek podczas instalowania oprogramowania sprzętowego"
12291391
1392 #. TRANSLATORS: User has been notified
1393 msgid "User has been notified"
1394 msgstr "Użytkownik został powiadomiony"
1395
12301396 #. TRANSLATORS: remote filename base
12311397 msgid "Username"
12321398 msgstr "Nazwa użytkownika"
8383 msgid "%s Update"
8484 msgstr "Atualização de %s"
8585
86 #. TRANSLATORS: warn the user before updating, %1 is a device name
87 #, c-format
88 msgid "%s and all connected devices may not be usable while updating."
89 msgstr "%s e todos os dispositivos conectados não podem ser usados durante a atualização."
90
91 #. TRANSLATORS: warn the user before updating, %1 is a device name
92 #, c-format
93 msgid "%s must remain connected for the duration of the update to avoid damage."
94 msgstr "%s deve permanecer conectado durante a atualização para evitar danos."
95
96 #. TRANSLATORS: warn the user before updating, %1 is a machine name
97 #, c-format
98 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
99 msgstr "%s deve permanecer conectado a uma fonte de energia durante a atualização para evitar danos."
100
86101 #. TRANSLATORS: duration in days!
87102 #, c-format
88103 msgid "%u day"
243258
244259 #. TRANSLATORS: firmware version of bootloader
245260 msgid "Bootloader Version"
246 msgstr "Versão do gerenciador de inicialização"
261 msgstr "Versão do gerenciador de boot"
247262
248263 #. TRANSLATORS: command description
249264 msgid "Build firmware using a sandbox"
262277 msgid "Changed"
263278 msgstr "Alterado"
264279
280 #. TRANSLATORS: command description
281 msgid "Checks cryptographic hash matches firmware"
282 msgstr "Verifica se o hash criptográfico corresponde ao firmware"
283
265284 #. TRANSLATORS: remote checksum
266285 msgid "Checksum"
267286 msgstr "Soma de verificação"
271290 msgstr "Escolha um dispositivo:"
272291
273292 #. TRANSLATORS: get interactive prompt
293 msgid "Choose a firmware type:"
294 msgstr "Escolha um tipo de firmware:"
295
296 #. TRANSLATORS: get interactive prompt
274297 msgid "Choose a release:"
275298 msgstr "Escolha um lançamento:"
276299
286309 msgid "Command not found"
287310 msgstr "Comando não encontrado"
288311
312 #. TRANSLATORS: prompt to apply the update
313 msgid "Continue with update?"
314 msgstr "Continuar com a atualização?"
315
289316 #. TRANSLATORS: command description
290317 msgid "Convert firmware to DFU format"
291318 msgstr "Converte um firmware para formato DFU"
319
320 #. TRANSLATORS: Device supports some form of checksum verification
321 msgid "Cryptographic hash verification is available"
322 msgstr "A verificação criptográfica de hash está disponível"
292323
293324 #. TRANSLATORS: version number of current firmware
294325 msgid "Current version"
318349 msgid "Details"
319350 msgstr "Detalhes"
320351
352 #. TRANSLATORS: description of device ability
353 msgid "Device Flags"
354 msgstr "Opções do dispositivo"
355
321356 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
322357 msgid "Device ID"
323358 msgstr "ID do dispositivo"
326361 msgid "Device added:"
327362 msgstr "Dispositivo adicionado:"
328363
364 #. TRANSLATORS: Device supports a safety mechanism for flashing
365 msgid "Device can recover flash failures"
366 msgstr "O dispositivo pode recuperar falhas de flashing"
367
329368 #. TRANSLATORS: this is when a device has been updated
330369 msgid "Device changed:"
331370 msgstr "Dispositivo modificado:"
332371
372 #. TRANSLATORS: Is locked and can be unlocked
373 msgid "Device is locked"
374 msgstr "O dispositivo está travado"
375
376 #. TRANSLATORS: Device remains usable during update
377 msgid "Device is usable for the duration of the update"
378 msgstr "O dispositivo pode ser usado durante a atualização"
379
333380 #. TRANSLATORS: this is when a device is hotplugged
334381 msgid "Device removed:"
335382 msgstr "Dispositivo removido:"
336383
384 #. TRANSLATORS: Device supports a safety mechanism for flashing
385 msgid "Device stages updates"
386 msgstr "Atualizações de estágios do dispositivo"
387
388 #. TRANSLATORS: Device update needs to be separately activated
389 msgid "Device update needs activation"
390 msgstr "A atualização do dispositivo precisa de ativação"
391
392 #. TRANSLATORS: Device will not return after update completes
393 msgid "Device will not re-appear after update completes"
394 msgstr "O dispositivo não aparecerá novamente após a atualização ser concluída"
395
337396 #. TRANSLATORS: a list of successful updates
338397 msgid "Devices that have been updated successfully:"
339398 msgstr "Dispositivos que foram atualizados com sucesso:"
372431 #. TRANSLATORS: turn on all debugging
373432 msgid "Do not include timestamp prefix"
374433 msgstr "Não inclui prefixo com marca de tempo"
434
435 #. TRANSLATORS: command line option
436 msgid "Do not perform device safety checks"
437 msgstr "Não realiza verificações de segurança de dispositivo"
375438
376439 msgid "Do not upload report at this time, but prompt again for future updates"
377440 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
619682 msgid "Gets the results from the last update"
620683 msgstr "Obtém os resultados da última atualização"
621684
685 #. TRANSLATORS: The hardware is waiting to be replugged
686 msgid "Hardware is waiting to be replugged"
687 msgstr "O hardware está aguardando para ser reconectado"
688
622689 #. TRANSLATORS: daemon is inactive
623690 msgid "Idle…"
624691 msgstr "Ocioso…"
627694 msgid "Ignore SSL strict checks when downloading files"
628695 msgstr "Ignora verificações estritas de SSL ao baixar arquivos"
629696
697 #. TRANSLATORS: Ignore validation safety checks when flashing this device
698 msgid "Ignore validation safety checks"
699 msgstr "Ignorar verificações de segurança de validação"
700
630701 #. TRANSLATORS: length of time the update takes to apply
631702 msgid "Install Duration"
632703 msgstr "Duração de instalação"
648719 msgid "Install signed system firmware"
649720 msgstr "Instalar firmware assinado no sistema"
650721
722 #. TRANSLATORS: Install composite firmware on the parent before the child
723 msgid "Install to parent device first"
724 msgstr "Instalar primeiro no dispositivo pai"
725
651726 msgid "Install unsigned device firmware"
652727 msgstr "Instalar firmware não assinado no dispositivo"
653728
666741 #, c-format
667742 msgid "Installing on %s…"
668743 msgstr "Instalando em %s…"
744
745 #. TRANSLATORS: Device cannot be removed easily
746 msgid "Internal device"
747 msgstr "Dispositivo interno"
748
749 #. TRANSLATORS: Is currently in bootloader mode
750 msgid "Is in bootloader mode"
751 msgstr "Está no modo gerenciador de boot"
669752
670753 #. TRANSLATORS: issue fixed with the release, e.g. CVE
671754 msgid "Issue"
698781 msgid "List supported firmware updates"
699782 msgstr "Lista atualizações de firmware suportadas"
700783
784 #. TRANSLATORS: command description
785 msgid "List the available firmware types"
786 msgstr "Lista os tipos de firmware disponível"
787
701788 #. TRANSLATORS: parsing the firmware information
702789 msgid "Loading…"
703790 msgstr "Carregando…"
749836 msgid "Monitor the daemon for events"
750837 msgstr "Monitora o daemon por eventos"
751838
839 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
840 msgid "Needs a reboot after installation"
841 msgstr "Precisa de uma reinicialização após a instalação"
842
843 #. TRANSLATORS: Requires system shutdown to apply firmware
844 msgid "Needs shutdown after installation"
845 msgstr "Precisa de desligamento após a instalação"
846
752847 #. TRANSLATORS: version number of new firmware
753848 msgid "New version"
754849 msgstr "Nova versão"
756851 msgid "No action specified!"
757852 msgstr "Nenhuma ação especificada!"
758853
854 #. TRANSLATORS: nothing found
855 msgid "No firmware IDs found"
856 msgstr "Nenhum ID de firmware encontrado"
857
759858 #. TRANSLATORS: nothing attached that can be upgraded
760859 msgid "No hardware detected with firmware update capability"
761860 msgstr "Nenhum periférico com capacidade de atualização de firmware foi detectado"
792891 msgid "Override warnings and force the action"
793892 msgstr "Anula avisos e força a ação"
794893
894 #. TRANSLATORS: command description
895 msgid "Parse and show details about a firmware file"
896 msgstr "Analisa e mostra detalhes sobre um arquivo de firmware"
897
795898 #. TRANSLATORS: remote filename base
796899 msgid "Password"
797900 msgstr "Senha"
834937 msgstr "Consulta por suporte a atualização de firmware"
835938
836939 #. TRANSLATORS: command description
940 msgid "Read a firmware blob from a device"
941 msgstr "Lê um blob de firmware de um dispositivo"
942
943 #. TRANSLATORS: command description
837944 msgid "Read firmware from device into a file"
838945 msgstr "Lê o firmware do dispositivo para um arquivo"
839946
840947 #. TRANSLATORS: command description
841948 msgid "Read firmware from one partition into a file"
842949 msgstr "Lê o firmware de uma partição para um arquivo"
950
951 #. TRANSLATORS: %1 is a device name
952 #, c-format
953 msgid "Reading from %s…"
954 msgstr "Lendo de %s…"
843955
844956 #. TRANSLATORS: reading from the flash chips
845957 msgid "Reading…"
881993 msgid "Report URI"
882994 msgstr "URI do relatório"
883995
996 #. TRANSLATORS: Has been reported to a metadata server
997 msgid "Reported to remote server"
998 msgstr "Relatado ao servidor remoto"
999
1000 #. TRANSLATORS: Must be plugged in to an outlet
1001 msgid "Requires AC power"
1002 msgstr "Requer alimentação CA"
1003
1004 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1005 msgid "Requires a bootloader"
1006 msgstr "Requer um gerenciador de boot"
1007
8841008 #. TRANSLATORS: metadata is downloaded from the Internet
8851009 msgid "Requires internet connection"
8861010 msgstr "Requer conexão com a Internet"
9201044 #. TRANSLATORS: scheduing an update to be done on the next boot
9211045 msgid "Scheduling…"
9221046 msgstr "Agendando…"
1047
1048 #. TRANSLATORS: Device has been chosen by the daemon for the user
1049 msgid "Selected device"
1050 msgstr "Dispositivo selecionado"
9231051
9241052 #. TRANSLATORS: serial number of hardware
9251053 msgid "Serial Number"
10551183 msgid "Successfully modified configuration value"
10561184 msgstr "Valor da configuração modificada com sucesso"
10571185
1186 #. TRANSLATORS: success message for a per-remote setting change
1187 msgid "Successfully modified remote"
1188 msgstr "Remoto modificado com sucesso"
1189
10581190 #. TRANSLATORS: success message -- the user can do this by-hand too
10591191 msgid "Successfully refreshed metadata manually"
10601192 msgstr "Metadados atualizados manualmente com sucesso"
1193
1194 #. TRANSLATORS: success message when user refreshes device checksums
1195 msgid "Successfully updated device checksums"
1196 msgstr "Somas de verificação de dispositivo atualizadas com sucesso"
10611197
10621198 #. TRANSLATORS: success message -- where the user has uploaded
10631199 #. * success and/or failure reports to the remote server
10671203 msgstr[0] "Enviado com sucesso %u relatório"
10681204 msgstr[1] "Enviados com sucesso %u relatórios"
10691205
1206 #. TRANSLATORS: success message when user verified device checksums
1207 msgid "Successfully verified device checksums"
1208 msgstr "Somas de verificação de dispositivo verificadas com sucesso"
1209
10701210 #. TRANSLATORS: one line summary of device
10711211 msgid "Summary"
10721212 msgstr "Resumo"
1213
1214 #. TRANSLATORS: Is found in current metadata
1215 msgid "Supported on remote server"
1216 msgstr "Suporte no servidor remoto"
10731217
10741218 msgid "Target"
10751219 msgstr "Alvo"
11271271 msgid "Unsupported daemon version %s, client version is %s"
11281272 msgstr "Sem suporte ao daemon na versão %s, a versão do cliente é %s"
11291273
1274 #. TRANSLATORS: Device is updatable in this or any other mode
1275 msgid "Updatable"
1276 msgstr "Atualizável"
1277
11301278 #. TRANSLATORS: error message from last update attempt
11311279 msgid "Update Error"
11321280 msgstr "Erro na atualização"
11521300 msgid "Update now?"
11531301 msgstr "Atualizar agora?"
11541302
1303 #. TRANSLATORS: Update can only be done from offline mode
1304 msgid "Update requires a reboot"
1305 msgstr "A atualização requer uma reinicialização"
1306
1307 #. TRANSLATORS: command description
1308 msgid "Update the stored cryptographic hash with current ROM contents"
1309 msgstr "Atualiza o hash criptográfico armazenado com o atual conteúdo da ROM"
1310
11551311 msgid "Update the stored device verification information"
11561312 msgstr "Atualizar as informações de verificação do dispositivo armazenado"
11571313
11741330 #, c-format
11751331 msgid "Updating %s…"
11761332 msgstr "Atualizando %s…"
1333
1334 #. TRANSLATORS: message letting the user know an upgrade is available
1335 #. * %1 is the device name and %2 and %3 are version strings
1336 #, c-format
1337 msgid "Upgrade available for %s from %s to %s"
1338 msgstr "Atualização disponível para %s de %s para %s"
11771339
11781340 #. TRANSLATORS: the server sent the user a small message
11791341 msgid "Upload message:"
12011363 msgid "Use quirk flags when installing firmware"
12021364 msgstr "Usa opções de peculiaridades ao instalar firmware"
12031365
1366 #. TRANSLATORS: User has been notified
1367 msgid "User has been notified"
1368 msgstr "O usuário foi notificado"
1369
12041370 #. TRANSLATORS: remote filename base
12051371 msgid "Username"
12061372 msgstr "Nome de usuário"
8181 msgid "%s Update"
8282 msgstr "Оновлення для %s"
8383
84 #. TRANSLATORS: warn the user before updating, %1 is a device name
85 #, c-format
86 msgid "%s and all connected devices may not be usable while updating."
87 msgstr "%s і усі з'єднані пристрою можуть бути недоступними протягом оновлення."
88
89 #. TRANSLATORS: warn the user before updating, %1 is a device name
90 #, c-format
91 msgid "%s must remain connected for the duration of the update to avoid damage."
92 msgstr "Для уникнення пошкоджень %s має лишатися з'єднаним із комп'ютером протягом оновлення."
93
94 #. TRANSLATORS: warn the user before updating, %1 is a machine name
95 #, c-format
96 msgid "%s must remain plugged into a power source for the duration of the update to avoid damage."
97 msgstr "Для уникнення пошкоджень %s має лишатися з'єднаним із джерелом живлення протягом оновлення."
98
8499 #. TRANSLATORS: duration in days!
85100 #, c-format
86101 msgid "%u day"
272287 msgid "Changed"
273288 msgstr "Змінено"
274289
290 #. TRANSLATORS: command description
291 msgid "Checks cryptographic hash matches firmware"
292 msgstr "Перевірити відповідність криптографічних хешів мікропрограми"
293
275294 #. TRANSLATORS: remote checksum
276295 msgid "Checksum"
277296 msgstr "Контрольна сума"
281300 msgstr "Виберіть пристрій:"
282301
283302 #. TRANSLATORS: get interactive prompt
303 msgid "Choose a firmware type:"
304 msgstr "Виберіть тип мікропрограми:"
305
306 #. TRANSLATORS: get interactive prompt
284307 msgid "Choose a release:"
285308 msgstr "Виберіть випуск:"
286309
296319 msgid "Command not found"
297320 msgstr "Такої команди не знайдено"
298321
322 #. TRANSLATORS: prompt to apply the update
323 msgid "Continue with update?"
324 msgstr "Продовжити оновлення?"
325
299326 #. TRANSLATORS: command description
300327 msgid "Convert firmware to DFU format"
301328 msgstr "Перетворити мікропрограму у формат DFU"
329
330 #. TRANSLATORS: Device supports some form of checksum verification
331 msgid "Cryptographic hash verification is available"
332 msgstr "Доступна перевірка криптографічної хеш-суми"
302333
303334 #. TRANSLATORS: version number of current firmware
304335 msgid "Current version"
328359 msgid "Details"
329360 msgstr "Подробиці"
330361
362 #. TRANSLATORS: description of device ability
363 msgid "Device Flags"
364 msgstr "Прапорці пристрою"
365
331366 #. TRANSLATORS: ID for hardware, typically a SHA1 sum
332367 msgid "Device ID"
333368 msgstr "Ід. пристрою"
336371 msgid "Device added:"
337372 msgstr "Додано пристрій:"
338373
374 #. TRANSLATORS: Device supports a safety mechanism for flashing
375 msgid "Device can recover flash failures"
376 msgstr "Пристрій може відновлюватися при невдалих оновленнях"
377
339378 #. TRANSLATORS: this is when a device has been updated
340379 msgid "Device changed:"
341380 msgstr "Змінено пристрій:"
342381
382 #. TRANSLATORS: Is locked and can be unlocked
383 msgid "Device is locked"
384 msgstr "Пристрій заблоковано"
385
386 #. TRANSLATORS: Device remains usable during update
387 msgid "Device is usable for the duration of the update"
388 msgstr "Пристроєм можна користуватися протягом оновлення"
389
343390 #. TRANSLATORS: this is when a device is hotplugged
344391 msgid "Device removed:"
345392 msgstr "Вилучено пристрій:"
346393
394 #. TRANSLATORS: Device supports a safety mechanism for flashing
395 msgid "Device stages updates"
396 msgstr "Пристрій із покроковим оновленням"
397
398 #. TRANSLATORS: Device update needs to be separately activated
399 msgid "Device update needs activation"
400 msgstr "Оновлення пристрою потребує активації"
401
402 #. TRANSLATORS: Device will not return after update completes
403 msgid "Device will not re-appear after update completes"
404 msgstr "Пристрій не з'явиться у списку пристроїв після завершення оновлення"
405
347406 #. TRANSLATORS: a list of successful updates
348407 msgid "Devices that have been updated successfully:"
349408 msgstr "Пристрої, для яких вдалося успішно оновити дані:"
382441 #. TRANSLATORS: turn on all debugging
383442 msgid "Do not include timestamp prefix"
384443 msgstr "Не включати префікс часової позначки"
444
445 #. TRANSLATORS: command line option
446 msgid "Do not perform device safety checks"
447 msgstr "Не виконувати перевірок безпечності для пристрою"
385448
386449 msgid "Do not upload report at this time, but prompt again for future updates"
387450 msgid_plural "Do not upload reports at this time, but prompt again for future updates"
637700 msgid "Gets the results from the last update"
638701 msgstr "Отримує результати з останнього оновлення"
639702
703 #. TRANSLATORS: The hardware is waiting to be replugged
704 msgid "Hardware is waiting to be replugged"
705 msgstr "Обладнання очікує на повторне з'єднання"
706
640707 #. TRANSLATORS: daemon is inactive
641708 msgid "Idle…"
642709 msgstr "Бездіяльність…"
645712 msgid "Ignore SSL strict checks when downloading files"
646713 msgstr "Ігнорувати результати строгої перевірки SSL під час отримання файлів"
647714
715 #. TRANSLATORS: Ignore validation safety checks when flashing this device
716 msgid "Ignore validation safety checks"
717 msgstr "Ігнорувати перевірки безпечності"
718
648719 #. TRANSLATORS: length of time the update takes to apply
649720 msgid "Install Duration"
650721 msgstr "Тривалість встановлення"
666737 msgid "Install signed system firmware"
667738 msgstr "Встановити підписану мікропрограму системи"
668739
740 #. TRANSLATORS: Install composite firmware on the parent before the child
741 msgid "Install to parent device first"
742 msgstr "Встановити спочатку на батьківському пристрої"
743
669744 msgid "Install unsigned device firmware"
670745 msgstr "Встановити непідписану мікропрограму пристрою"
671746
684759 #, c-format
685760 msgid "Installing on %s…"
686761 msgstr "Встановлюємо на %s…"
762
763 #. TRANSLATORS: Device cannot be removed easily
764 msgid "Internal device"
765 msgstr "Внутрішній пристрій"
766
767 #. TRANSLATORS: Is currently in bootloader mode
768 msgid "Is in bootloader mode"
769 msgstr "Перебуває у режимі завантажувача"
687770
688771 #. TRANSLATORS: issue fixed with the release, e.g. CVE
689772 msgid "Issue"
718801 msgid "List supported firmware updates"
719802 msgstr "Показати список підтримуваних оновлень мікропрограми"
720803
804 #. TRANSLATORS: command description
805 msgid "List the available firmware types"
806 msgstr "Вивести список доступних типів мікропрограм"
807
721808 #. TRANSLATORS: parsing the firmware information
722809 msgid "Loading…"
723810 msgstr "Завантаження…"
769856 msgid "Monitor the daemon for events"
770857 msgstr "Стежити за подіями у фоновій службі"
771858
859 #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware
860 msgid "Needs a reboot after installation"
861 msgstr "Потребує перезавантаження після встановлення"
862
863 #. TRANSLATORS: Requires system shutdown to apply firmware
864 msgid "Needs shutdown after installation"
865 msgstr "Потребує вимикання після встановлення"
866
772867 #. TRANSLATORS: version number of new firmware
773868 msgid "New version"
774869 msgstr "Нова версія"
776871 msgid "No action specified!"
777872 msgstr "Не вказано дії!"
778873
874 #. TRANSLATORS: nothing found
875 msgid "No firmware IDs found"
876 msgstr "Не знайдено ідентифікаторів мікропрограм"
877
779878 #. TRANSLATORS: nothing attached that can be upgraded
780879 msgid "No hardware detected with firmware update capability"
781880 msgstr "Не виявлено обладнання із передбаченою можливістю оновлення мікропрограми"
812911 msgid "Override warnings and force the action"
813912 msgstr "Не зважати на попередження і примусово виконати дію"
814913
914 #. TRANSLATORS: command description
915 msgid "Parse and show details about a firmware file"
916 msgstr "Обробити і показати параметри файла мікропрограми"
917
815918 #. TRANSLATORS: remote filename base
816919 msgid "Password"
817920 msgstr "Пароль"
854957 msgstr "Опитати щодо підтримки оновлення мікропрограми"
855958
856959 #. TRANSLATORS: command description
960 msgid "Read a firmware blob from a device"
961 msgstr "Прочитати бінарну мікропрограму з пристрою"
962
963 #. TRANSLATORS: command description
857964 msgid "Read firmware from device into a file"
858965 msgstr "Прочитати мікропрограму з пристрою до файла"
859966
860967 #. TRANSLATORS: command description
861968 msgid "Read firmware from one partition into a file"
862969 msgstr "Прочитати мікропрограму з одного розділу до файла"
970
971 #. TRANSLATORS: %1 is a device name
972 #, c-format
973 msgid "Reading from %s…"
974 msgstr "Читаємо з %s…"
863975
864976 #. TRANSLATORS: reading from the flash chips
865977 msgid "Reading…"
9011013 msgid "Report URI"
9021014 msgstr "Адреса звіту"
9031015
1016 #. TRANSLATORS: Has been reported to a metadata server
1017 msgid "Reported to remote server"
1018 msgstr "Повідомлено на віддаленому сервері"
1019
1020 #. TRANSLATORS: Must be plugged in to an outlet
1021 msgid "Requires AC power"
1022 msgstr "Потребує сталого живлення"
1023
1024 #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user
1025 msgid "Requires a bootloader"
1026 msgstr "Потребує завантажувача"
1027
9041028 #. TRANSLATORS: metadata is downloaded from the Internet
9051029 msgid "Requires internet connection"
9061030 msgstr "Потребує з'єднання із інтернетом"
9401064 #. TRANSLATORS: scheduing an update to be done on the next boot
9411065 msgid "Scheduling…"
9421066 msgstr "Плануємо…"
1067
1068 #. TRANSLATORS: Device has been chosen by the daemon for the user
1069 msgid "Selected device"
1070 msgstr "Вибрано пристрій"
9431071
9441072 #. TRANSLATORS: serial number of hardware
9451073 msgid "Serial Number"
10751203 msgid "Successfully modified configuration value"
10761204 msgstr "Успішно змінено значення у налаштуваннях"
10771205
1206 #. TRANSLATORS: success message for a per-remote setting change
1207 msgid "Successfully modified remote"
1208 msgstr "Успішно змінено віддалене сховище"
1209
10781210 #. TRANSLATORS: success message -- the user can do this by-hand too
10791211 msgid "Successfully refreshed metadata manually"
10801212 msgstr "Метадані успішно оновлено вручну"
1213
1214 #. TRANSLATORS: success message when user refreshes device checksums
1215 msgid "Successfully updated device checksums"
1216 msgstr "Успішно оновлено контрольні суми пристрою"
10811217
10821218 #. TRANSLATORS: success message -- where the user has uploaded
10831219 #. * success and/or failure reports to the remote server
10891225 msgstr[2] "Успішно вивантажено %u звітів"
10901226 msgstr[3] "Успішно вивантажено %u звіт"
10911227
1228 #. TRANSLATORS: success message when user verified device checksums
1229 msgid "Successfully verified device checksums"
1230 msgstr "Успішно перевірено контрольні суми пристрою"
1231
10921232 #. TRANSLATORS: one line summary of device
10931233 msgid "Summary"
10941234 msgstr "Резюме"
1235
1236 #. TRANSLATORS: Is found in current metadata
1237 msgid "Supported on remote server"
1238 msgstr "Підтримуваний на віддаленому сервері"
10951239
10961240 msgid "Target"
10971241 msgstr "Ціль"
11491293 msgid "Unsupported daemon version %s, client version is %s"
11501294 msgstr "Непідтримувана версія фонової служби %s, версія клієнта — %s"
11511295
1296 #. TRANSLATORS: Device is updatable in this or any other mode
1297 msgid "Updatable"
1298 msgstr "Придатний до оновлення"
1299
11521300 #. TRANSLATORS: error message from last update attempt
11531301 msgid "Update Error"
11541302 msgstr "Помилка оновлення"
11741322 msgid "Update now?"
11751323 msgstr "Оновити зараз?"
11761324
1325 #. TRANSLATORS: Update can only be done from offline mode
1326 msgid "Update requires a reboot"
1327 msgstr "Оновлення потребує перезавантаження"
1328
1329 #. TRANSLATORS: command description
1330 msgid "Update the stored cryptographic hash with current ROM contents"
1331 msgstr "Оновити збережений криптографічний хеш на основі поточних даних ROM"
1332
11771333 msgid "Update the stored device verification information"
11781334 msgstr "Оновлення збережених даних щодо верифікації пристрою"
11791335
11961352 #, c-format
11971353 msgid "Updating %s…"
11981354 msgstr "Оновлюємо %s…"
1355
1356 #. TRANSLATORS: message letting the user know an upgrade is available
1357 #. * %1 is the device name and %2 and %3 are version strings
1358 #, c-format
1359 msgid "Upgrade available for %s from %s to %s"
1360 msgstr "Виявлено оновлення для %s з %s до %s"
11991361
12001362 #. TRANSLATORS: the server sent the user a small message
12011363 msgid "Upload message:"
12271389 msgid "Use quirk flags when installing firmware"
12281390 msgstr "Використовувати варіативні прапорці при встановленні мікропрограми"
12291391
1392 #. TRANSLATORS: User has been notified
1393 msgid "User has been notified"
1394 msgstr "Сповіщено користувача"
1395
12301396 #. TRANSLATORS: remote filename base
12311397 msgid "Username"
12321398 msgstr "Користувач"
8383 * @self: A #FuArchive
8484 * @callback: A #FuArchiveIterateFunc.
8585 * @user_data: User data.
86 * @error: A #GError, or %NULL
8687 *
8788 * Iterates over the archive contents, calling the given function for each
88 * of the files found.
89 * of the files found. If any @callback returns %FALSE scanning is aborted.
90 *
91 * Returns: True if no @callback returned FALSE
8992 */
90 void
91 fu_archive_iterate (FuArchive *self, FuArchiveIterateFunc callback, gpointer user_data)
93 gboolean
94 fu_archive_iterate (FuArchive *self,
95 FuArchiveIterateFunc callback,
96 gpointer user_data,
97 GError **error)
9298 {
9399 GHashTableIter iter;
94100 gpointer key, value;
95101
96 g_return_if_fail (FU_IS_ARCHIVE (self));
97 g_return_if_fail (callback != NULL);
102 g_return_val_if_fail (FU_IS_ARCHIVE (self), FALSE);
103 g_return_val_if_fail (callback != NULL, FALSE);
98104
99105 g_hash_table_iter_init (&iter, self->entries);
100 while (g_hash_table_iter_next (&iter, &key, &value))
101 callback (self, (const gchar *)key, (GBytes *)value, user_data);
106 while (g_hash_table_iter_next (&iter, &key, &value)) {
107 if (!callback (self, (const gchar *)key, (GBytes *)value, user_data, error))
108 return FALSE;
109 }
110 return TRUE;
102111 }
103112
104113 /* workaround the struct types of libarchive */
3434 *
3535 * Specifies the type of archive iteration function.
3636 */
37 typedef void (*FuArchiveIterateFunc) (FuArchive *self,
37 typedef gboolean (*FuArchiveIterateFunc) (FuArchive *self,
3838 const gchar *filename,
3939 GBytes *bytes,
40 gpointer user_data);
40 gpointer user_data,
41 GError **error);
4142
4243 FuArchive *fu_archive_new (GBytes *data,
4344 FuArchiveFlags flags,
4546 GBytes *fu_archive_lookup_by_fn (FuArchive *self,
4647 const gchar *fn,
4748 GError **error);
48 void fu_archive_iterate (FuArchive *self,
49 gboolean fu_archive_iterate (FuArchive *self,
4950 FuArchiveIterateFunc callback,
50 gpointer user_data);
51 gpointer user_data,
52 GError **error);
7878 (val >> 24) & 0x0f,
7979 (val >> 16) & 0xff,
8080 val & 0xffff);
81 }
82 if (kind == FWUPD_VERSION_FORMAT_SURFACE_LEGACY) {
83 /* 10b.12b.10b */
84 return g_strdup_printf ("%u.%u.%u",
85 (val >> 22) & 0x3ff,
86 (val >> 10) & 0xfff,
87 val & 0x3ff);
88 }
89 if (kind == FWUPD_VERSION_FORMAT_SURFACE) {
90 /* 8b.16b.8b */
91 return g_strdup_printf ("%u.%u.%u",
92 (val >> 24) & 0xff,
93 (val >> 8) & 0xffff,
94 val & 0xff);
8195 }
8296 g_critical ("failed to convert version format %s: %u",
8397 fwupd_version_format_to_string (kind), val);
5252 * @FU_PATH_KIND_SYSFSDIR_FW: The sysfs firmware location (IE /sys/firmware)
5353 * @FU_PATH_KIND_SYSFSDIR_DRIVERS: The platform sysfs directory (IE /sys/bus/platform/drivers)
5454 * @FU_PATH_KIND_SYSFSDIR_TPM: The TPM sysfs directory (IE /sys/class/tpm)
55 * @FU_PATH_KIND_POLKIT_ACTIONS The directory for policy kit actions (IE /usr/share/polkit-1/actions/)
55 * @FU_PATH_KIND_POLKIT_ACTIONS: The directory for policy kit actions (IE /usr/share/polkit-1/actions/)
5656 *
5757 * Path types to use when dynamically determining a path at runtime
5858 **/
10781078 fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req,
10791079 FuDevice *device, GError **error)
10801080 {
1081 guint64 depth;
1082 g_autoptr(FuDevice) device_actual = g_object_ref (device);
10811083 g_autoptr(GError) error_local = NULL;
1084
1085 /* look at the parent device */
1086 depth = xb_node_get_attr_as_uint (req, "depth");
1087 if (depth != G_MAXUINT64) {
1088 for (guint64 i = 0; i < depth; i++) {
1089 FuDevice *device_tmp = fu_device_get_parent (device_actual);
1090 if (device_actual == NULL) {
1091 g_set_error (error,
1092 FWUPD_ERROR,
1093 FWUPD_ERROR_NOT_SUPPORTED,
1094 "No parent device for %s "
1095 "(%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ")",
1096 fu_device_get_name (device_actual), i, depth);
1097 return FALSE;
1098 }
1099 g_set_object (&device_actual, device_tmp);
1100 }
1101 }
10821102
10831103 /* old firmware version */
10841104 if (xb_node_get_text (req) == NULL) {
1085 const gchar *version = fu_device_get_version (device);
1105 const gchar *version = fu_device_get_version (device_actual);
10861106 if (!fu_engine_require_vercmp (req, version, &error_local)) {
10871107 if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
10881108 g_set_error (error,
11041124
11051125 /* bootloader version */
11061126 if (g_strcmp0 (xb_node_get_text (req), "bootloader") == 0) {
1107 const gchar *version = fu_device_get_version_bootloader (device);
1127 const gchar *version = fu_device_get_version_bootloader (device_actual);
11081128 if (!fu_engine_require_vercmp (req, version, &error_local)) {
11091129 if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
11101130 g_set_error (error,
11261146
11271147 /* vendor ID */
11281148 if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) {
1129 const gchar *version = fu_device_get_vendor_id (device);
1149 const gchar *version = fu_device_get_vendor_id (device_actual);
11301150 if (!fu_engine_require_vercmp (req, version, &error_local)) {
11311151 if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
11321152 g_set_error (error,
11481168
11491169 /* child version */
11501170 if (g_strcmp0 (xb_node_get_text (req), "not-child") == 0)
1151 return fu_engine_check_requirement_not_child (self, req, device, error);
1171 return fu_engine_check_requirement_not_child (self, req, device_actual, error);
11521172
11531173 /* another device */
11541174 if (fwupd_guid_is_valid (xb_node_get_text (req))) {
11551175 const gchar *guid = xb_node_get_text (req);
11561176 const gchar *version;
1157 g_autoptr(FuDevice) device2 = NULL;
11581177
11591178 /* find if the other device exists */
1160 device2 = fu_device_list_get_by_guid (self->device_list, guid, error);
1161 if (device2 == NULL)
1162 return FALSE;
1179 if (depth == G_MAXUINT64) {
1180 g_autoptr(FuDevice) device_tmp = NULL;
1181 device_tmp = fu_device_list_get_by_guid (self->device_list, guid, error);
1182 if (device_tmp == NULL)
1183 return FALSE;
1184 g_set_object (&device_actual, device_tmp);
1185
1186 /* verify the parent device has the GUID */
1187 } else {
1188 if (!fu_device_has_guid (device_actual, guid)) {
1189 g_set_error (error,
1190 FWUPD_ERROR,
1191 FWUPD_ERROR_NOT_SUPPORTED,
1192 "No GUID of %s on parent device %s",
1193 guid, fu_device_get_name (device_actual));
1194 return FALSE;
1195 }
1196 }
11631197
11641198 /* get the version of the other device */
1165 version = fu_device_get_version (device2);
1199 version = fu_device_get_version (device_actual);
11661200 if (version != NULL &&
1201 xb_node_get_attr (req, "compare") != NULL &&
11671202 !fu_engine_require_vercmp (req, version, &error_local)) {
11681203 if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
11691204 g_set_error (error,
11701205 FWUPD_ERROR,
11711206 FWUPD_ERROR_INVALID_FILE,
11721207 "Not compatible with %s version %s, requires >= %s",
1173 fu_device_get_name (device2),
1208 fu_device_get_name (device_actual),
11741209 version,
11751210 xb_node_get_attr (req, "version"));
11761211 } else {
11781213 FWUPD_ERROR,
11791214 FWUPD_ERROR_INVALID_FILE,
11801215 "Not compatible with %s: %s",
1181 fu_device_get_name (device2),
1216 fu_device_get_name (device_actual),
11821217 error_local->message);
11831218 }
11841219 return FALSE;
18711906 FwupdInstallFlags flags,
18721907 GError **error)
18731908 {
1874 g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error);
1909 g_autoptr(FuDeviceLocker) locker = NULL;
1910
1911 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_WILL_DISAPPEAR)) {
1912 g_debug ("skipping device cleanup due to will-disappear flag");
1913 return TRUE;
1914 }
1915
1916 locker = fu_device_locker_new (device, error);
18751917 if (locker == NULL)
18761918 return FALSE;
18771919 return fu_device_cleanup (device, flags, error);
43684410 /* if loaded from fu_engine_load() open the plugin */
43694411 if (self->usb_ctx != NULL) {
43704412 if (!fu_plugin_open (plugin, filename, &error_local)) {
4371 g_warning ("failed to open plugin %s: %s",
4372 filename, error_local->message);
4413 g_warning ("%s", error_local->message);
43734414 continue;
43744415 }
43754416 }
2222 GBytes *bytes;
2323 guint64 addr;
2424 guint64 idx;
25 gchar *version;
2526 } FuFirmwareImagePrivate;
2627
2728 G_DEFINE_TYPE_WITH_PRIVATE (FuFirmwareImage, fu_firmware_image, G_TYPE_OBJECT)
2829 #define GET_PRIVATE(o) (fu_firmware_image_get_instance_private (o))
30
31 /**
32 * fu_firmware_image_get_version:
33 * @self: A #FuFirmwareImage
34 *
35 * Gets an optional version that represents the firmware image.
36 *
37 * Returns: a string, or %NULL
38 *
39 * Since: 1.3.4
40 **/
41 const gchar *
42 fu_firmware_image_get_version (FuFirmwareImage *self)
43 {
44 FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
45 g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL);
46 return priv->version;
47 }
48
49 /**
50 * fu_firmware_image_set_version:
51 * @self: A #FuFirmwareImage
52 * @version: A string version, or %NULL
53 *
54 * Sets an optional version that represents the firmware image.
55 *
56 * Since: 1.3.4
57 **/
58 void
59 fu_firmware_image_set_version (FuFirmwareImage *self, const gchar *version)
60 {
61 FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
62 g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self));
63 g_free (priv->version);
64 priv->version = g_strdup (version);
65 }
2966
3067 /**
3168 * fu_firmware_image_set_id:
260297 fu_common_string_append_kx (str, idt, "Index", priv->idx);
261298 if (priv->addr != 0x0)
262299 fu_common_string_append_kx (str, idt, "Address", priv->addr);
300 if (priv->version != NULL)
301 fu_common_string_append_kv (str, 0, "Version", priv->version);
263302 if (priv->bytes != NULL) {
264303 fu_common_string_append_kx (str, idt, "Data",
265304 g_bytes_get_size (priv->bytes));
299338 FuFirmwareImage *self = FU_FIRMWARE_IMAGE (object);
300339 FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
301340 g_free (priv->id);
341 g_free (priv->version);
302342 if (priv->bytes != NULL)
303343 g_bytes_unref (priv->bytes);
304344 G_OBJECT_CLASS (fu_firmware_image_parent_class)->finalize (object);
2727 gpointer padding[28];
2828 };
2929
30 #define FU_FIRMWARE_IMAGE_ID_PAYLOAD "payload"
31 #define FU_FIRMWARE_IMAGE_ID_SIGNATURE "signature"
32 #define FU_FIRMWARE_IMAGE_ID_HEADER "header"
33
3034 FuFirmwareImage *fu_firmware_image_new (GBytes *bytes);
31 gchar *fu_firmware_image_to_string (FuFirmwareImage *selfz);
35 gchar *fu_firmware_image_to_string (FuFirmwareImage *self);
3236
37 const gchar *fu_firmware_image_get_version (FuFirmwareImage *self);
38 void fu_firmware_image_set_version (FuFirmwareImage *self,
39 const gchar *version);
3340 const gchar *fu_firmware_image_get_id (FuFirmwareImage *self);
3441 void fu_firmware_image_set_id (FuFirmwareImage *self,
3542 const gchar *id);
1515
1616 struct _FuIhexFirmware {
1717 FuFirmware parent_instance;
18 GPtrArray *records;
1819 };
1920
2021 G_DEFINE_TYPE (FuIhexFirmware, fu_ihex_firmware, FU_TYPE_FIRMWARE)
2627 #define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04
2728 #define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05
2829 #define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd
30
31 /**
32 * fu_ihex_firmware_get_records:
33 * @self: A #FuIhexFirmware
34 *
35 * Returns the raw lines from tokenization.
36 *
37 * This might be useful if the plugin is expecting the hex file to be a list
38 * of operations, rather than a simple linear image with filled holes.
39 *
40 * Returns: (transfer none) (element-type FuIhexFirmwareRecord): records
41 *
42 * Since: 1.3.4
43 **/
44 GPtrArray *
45 fu_ihex_firmware_get_records (FuIhexFirmware *self)
46 {
47 g_return_val_if_fail (FU_IS_IHEX_FIRMWARE (self), NULL);
48 return self->records;
49 }
50
51 static void
52 fu_ihex_firmware_record_free (FuIhexFirmwareRecord *rcd)
53 {
54 g_string_free (rcd->buf, TRUE);
55 g_free (rcd);
56 }
57
58 G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuIhexFirmwareRecord, fu_ihex_firmware_record_free)
59
60 static FuIhexFirmwareRecord *
61 fu_ihex_firmware_record_new (guint ln, const gchar *buf)
62 {
63 FuIhexFirmwareRecord *rcd = g_new0 (FuIhexFirmwareRecord, 1);
64 rcd->ln = ln;
65 rcd->buf = g_string_new (buf);
66 return rcd;
67 }
2968
3069 static const gchar *
3170 fu_ihex_firmware_record_type_to_string (guint8 record_type)
4887 }
4988
5089 static gboolean
90 fu_ihex_firmware_tokenize (FuFirmware *firmware, GBytes *fw,
91 FwupdInstallFlags flags, GError **error)
92 {
93 FuIhexFirmware *self = FU_IHEX_FIRMWARE (firmware);
94 gsize sz = 0;
95 const gchar *data = g_bytes_get_data (fw, &sz);
96 g_auto(GStrv) lines = fu_common_strnsplit (data, sz, "\n", -1);
97
98 for (guint ln = 0; lines[ln] != NULL; ln++) {
99 g_autoptr(FuIhexFirmwareRecord) rcd = NULL;
100 g_strdelimit (lines[ln], "\r\x1a", '\0');
101 rcd = fu_ihex_firmware_record_new (ln + 1, lines[ln]);
102 g_ptr_array_add (self->records, g_steal_pointer (&rcd));
103 }
104 return TRUE;
105 }
106
107 static gboolean
51108 fu_ihex_firmware_parse (FuFirmware *firmware,
52109 GBytes *fw,
53110 guint64 addr_start,
55112 FwupdInstallFlags flags,
56113 GError **error)
57114 {
58 const gchar *data;
115 FuIhexFirmware *self = FU_IHEX_FIRMWARE (firmware);
59116 gboolean got_eof = FALSE;
60 gsize sz = 0;
61117 guint32 abs_addr = 0x0;
62118 guint32 addr_last = 0x0;
63119 guint32 img_addr = G_MAXUINT32;
64120 guint32 seg_addr = 0x0;
65 g_auto(GStrv) lines = NULL;
66121 g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL);
67122 g_autoptr(GBytes) img_bytes = NULL;
68123 g_autoptr(GByteArray) buf = g_byte_array_new ();
69124 g_autoptr(GByteArray) buf_signature = g_byte_array_new ();
70125
71 g_return_val_if_fail (fw != NULL, FALSE);
72
73126 /* parse records */
74 data = g_bytes_get_data (fw, &sz);
75 lines = fu_common_strnsplit (data, sz, "\n", -1);
76 for (guint ln = 0; lines[ln] != NULL; ln++) {
77 const gchar *line = lines[ln];
78 gsize linesz;
127 for (guint k = 0; k < self->records->len; k++) {
128 FuIhexFirmwareRecord *rcd = g_ptr_array_index (self->records, k);
129 const gchar *line = rcd->buf->str;
79130 guint32 addr;
80131 guint8 byte_cnt;
81132 guint8 record_type;
86137 continue;
87138
88139 /* ignore blank lines */
89 g_strdelimit (lines[ln], "\r\x1a", '\0');
90 linesz = strlen (line);
91 if (linesz == 0)
140 if (rcd->buf->len == 0)
92141 continue;
93142
94143 /* check starting token */
97146 FWUPD_ERROR,
98147 FWUPD_ERROR_INVALID_FILE,
99148 "invalid starting token on line %u: %s",
100 ln + 1, line);
149 rcd->ln, line);
101150 return FALSE;
102151 }
103152
104153 /* check there's enough data for the smallest possible record */
105 if (linesz < 11) {
154 if (rcd->buf->len < 11) {
106155 g_set_error (error,
107156 FWUPD_ERROR,
108157 FWUPD_ERROR_INVALID_FILE,
109158 "line %u is incomplete, length %u",
110 ln + 1, (guint) linesz);
159 rcd->ln, (guint) rcd->buf->len);
111160 return FALSE;
112161 }
113162
124173
125174 /* position of checksum */
126175 line_end = 9 + byte_cnt * 2;
127 if (line_end > (guint) linesz) {
176 if (line_end > (guint) rcd->buf->len) {
128177 g_set_error (error,
129178 FWUPD_ERROR,
130179 FWUPD_ERROR_INVALID_FILE,
131180 "line %u malformed, length: %u",
132 ln + 1, line_end);
181 rcd->ln, line_end);
133182 return FALSE;
134183 }
135184
145194 FWUPD_ERROR,
146195 FWUPD_ERROR_INVALID_FILE,
147196 "line %u has invalid checksum (0x%02x)",
148 ln + 1, checksum);
197 rcd->ln, checksum);
149198 return FALSE;
150199 }
151200 }
165214 "invalid address 0x%x, last was 0x%x on line %u",
166215 (guint) addr,
167216 (guint) addr_last,
168 ln + 1);
217 rcd->ln);
169218 return FALSE;
170219 }
171220
181230 FWUPD_ERROR_INVALID_FILE,
182231 "hole of 0x%x bytes too large to fill on line %u",
183232 (guint) len_hole,
184 ln + 1);
233 rcd->ln);
185234 return FALSE;
186235 }
187236 if (addr_last > 0x0 && len_hole > 1) {
188237 g_debug ("filling address 0x%08x to 0x%08x on line %u",
189 addr_last + 1, addr_last + len_hole - 1, ln + 1);
238 addr_last + 1, addr_last + len_hole - 1, rcd->ln);
190239 for (guint j = 1; j < len_hole; j++) {
191240 /* although 0xff might be clearer,
192241 * we can't write 0xffff to pic14 */
212261 break;
213262 case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR:
214263 abs_addr = fu_firmware_strparse_uint16 (line + 9) << 16;
215 g_debug (" abs_addr:\t0x%02x on line %u", abs_addr, ln + 1);
264 g_debug (" abs_addr:\t0x%02x on line %u", abs_addr, rcd->ln);
216265 break;
217266 case DFU_INHX32_RECORD_TYPE_START_LINEAR:
218267 abs_addr = fu_firmware_strparse_uint32 (line + 9);
219 g_debug (" abs_addr:\t0x%08x on line %u", abs_addr, ln + 1);
268 g_debug (" abs_addr:\t0x%08x on line %u", abs_addr, rcd->ln);
220269 break;
221270 case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT:
222271 /* segment base address, so ~1Mb addressable */
223272 seg_addr = fu_firmware_strparse_uint16 (line + 9) * 16;
224 g_debug (" seg_addr:\t0x%08x on line %u", seg_addr, ln + 1);
273 g_debug (" seg_addr:\t0x%08x on line %u", seg_addr, rcd->ln);
225274 break;
226275 case DFU_INHX32_RECORD_TYPE_START_SEGMENT:
227276 /* initial content of the CS:IP registers */
228277 seg_addr = fu_firmware_strparse_uint32 (line + 9);
229 g_debug (" seg_addr:\t0x%02x on line %u", seg_addr, ln + 1);
278 g_debug (" seg_addr:\t0x%02x on line %u", seg_addr, rcd->ln);
230279 break;
231280 case DFU_INHX32_RECORD_TYPE_SIGNATURE:
232281 for (guint i = 9; i < line_end; i += 2) {
242291 FWUPD_ERROR,
243292 FWUPD_ERROR_INVALID_FILE,
244293 "invalid ihex record type %i on line %u",
245 record_type, ln + 1);
294 record_type, rcd->ln);
246295 return FALSE;
247296 }
248297 }
267316 if (buf_signature->len > 0) {
268317 g_autoptr(GBytes) data_sig = g_bytes_new (buf_signature->data, buf_signature->len);
269318 g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (data_sig);
270 fu_firmware_image_set_id (img_sig, "signature");
319 fu_firmware_image_set_id (img_sig, FU_FIRMWARE_IMAGE_ID_SIGNATURE);
271320 fu_firmware_add_image (firmware, img_sig);
272321 }
273322 return TRUE;
312361 return FALSE;
313362
314363 /* special case */
315 if (g_strcmp0 (fu_firmware_image_get_id (img), "signature") == 0)
364 if (g_strcmp0 (fu_firmware_image_get_id (img),
365 FU_FIRMWARE_IMAGE_ID_SIGNATURE) == 0)
316366 record_type = DFU_INHX32_RECORD_TYPE_SIGNATURE;
317367
318368 /* get number of chunks */
359409 }
360410
361411 static void
412 fu_ihex_firmware_finalize (GObject *object)
413 {
414 FuIhexFirmware *self = FU_IHEX_FIRMWARE (object);
415 g_ptr_array_unref (self->records);
416 G_OBJECT_CLASS (fu_ihex_firmware_parent_class)->finalize (object);
417 }
418
419 static void
362420 fu_ihex_firmware_init (FuIhexFirmware *self)
363421 {
422 self->records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ihex_firmware_record_free);
364423 }
365424
366425 static void
367426 fu_ihex_firmware_class_init (FuIhexFirmwareClass *klass)
368427 {
428 GObjectClass *object_class = G_OBJECT_CLASS (klass);
369429 FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass);
430 object_class->finalize = fu_ihex_firmware_finalize;
370431 klass_firmware->parse = fu_ihex_firmware_parse;
432 klass_firmware->tokenize = fu_ihex_firmware_tokenize;
371433 klass_firmware->write = fu_ihex_firmware_write;
372434 }
373435
1010 #define FU_TYPE_IHEX_FIRMWARE (fu_ihex_firmware_get_type ())
1111 G_DECLARE_FINAL_TYPE (FuIhexFirmware, fu_ihex_firmware, FU, IHEX_FIRMWARE, FuFirmware)
1212
13 typedef struct {
14 guint ln;
15 GString *buf;
16 } FuIhexFirmwareRecord;
17
1318 FuFirmware *fu_ihex_firmware_new (void);
19 GPtrArray *fu_ihex_firmware_get_records (FuIhexFirmware *self);
1414 #include <glib-unix.h>
1515 #include <locale.h>
1616 #include <polkit/polkit.h>
17 #include <stdio.h>
1718 #include <stdlib.h>
1819
1920 #include "fwupd-device-private.h"
13671368
13681369 if (g_strcmp0 (property_name, "HostMachineId") == 0)
13691370 return g_variant_new_string (fu_engine_get_host_machine_id (priv->engine));
1371
1372 if (g_strcmp0 (property_name, "Interactive") == 0)
1373 return g_variant_new_boolean (isatty (fileno (stdout)) != 0);
13701374
13711375 /* return an error */
13721376 g_set_error (error,
1212 #include <errno.h>
1313 #include <string.h>
1414 #include <unistd.h>
15 #include <gio/gunixinputstream.h>
1615 #ifdef HAVE_VALGRIND
1716 #include <valgrind.h>
1817 #endif /* HAVE_VALGRIND */
353352 g_set_error (error,
354353 G_IO_ERROR,
355354 G_IO_ERROR_FAILED,
356 "failed to open plugin: %s",
357 g_module_error ());
355 "failed to open plugin %s: %s",
356 filename, g_module_error ());
358357 return FALSE;
359358 }
360359
99 #include <fwupd.h>
1010 #include <glib-object.h>
1111 #include <glib/gstdio.h>
12 #include <gio/gfiledescriptorbased.h>
1312 #include <libgcab.h>
1413 #include <stdlib.h>
1514 #include <string.h>
558557
559558 /* check this passes */
560559 task = fu_install_task_new (device1, component);
560 ret = fu_engine_check_requirements (engine, task,
561 FWUPD_INSTALL_FLAG_NONE,
562 &error);
563 g_assert_no_error (error);
564 g_assert (ret);
565 }
566
567 static void
568 fu_engine_requirements_parent_device_func (void)
569 {
570 gboolean ret;
571 g_autoptr(FuDevice) device1 = fu_device_new ();
572 g_autoptr(FuDevice) device2 = fu_device_new ();
573 g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
574 g_autoptr(FuInstallTask) task = NULL;
575 g_autoptr(GError) error = NULL;
576 g_autoptr(XbNode) component = NULL;
577 g_autoptr(XbSilo) silo = NULL;
578 g_autoptr(XbSilo) silo_empty = xb_silo_new ();
579 const gchar *xml =
580 "<component>"
581 " <requires>"
582 " <firmware depth=\"1\" compare=\"eq\" version=\"1.2.3\"/>"
583 " <firmware depth=\"1\">12345678-1234-1234-1234-123456789012</firmware>"
584 " </requires>"
585 " <provides>"
586 " <firmware type=\"flashed\">1ff60ab2-3905-06a1-b476-0371f00c9e9b</firmware>"
587 " </provides>"
588 " <releases>"
589 " <release version=\"4.5.7\">"
590 " <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
591 " </release>"
592 " </releases>"
593 "</component>";
594
595 /* no metadata in daemon */
596 fu_engine_set_silo (engine, silo_empty);
597
598 /* set up child device */
599 fu_device_set_id (device2, "child");
600 fu_device_set_name (device2, "child");
601 fu_device_set_version (device2, "4.5.6", FWUPD_VERSION_FORMAT_TRIPLET);
602 fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_UPDATABLE);
603 fu_device_add_guid (device2, "1ff60ab2-3905-06a1-b476-0371f00c9e9b");
604
605 /* set up a parent device */
606 fu_device_set_id (device1, "parent");
607 fu_device_set_name (device1, "parent");
608 fu_device_set_version (device1, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
609 fu_device_add_guid (device1, "12345678-1234-1234-1234-123456789012");
610 fu_device_add_child (device1, device2);
611 fu_engine_add_device (engine, device1);
612
613 /* import firmware metainfo */
614 silo = xb_silo_new_from_xml (xml, &error);
615 g_assert_no_error (error);
616 g_assert_nonnull (silo);
617 component = xb_silo_query_first (silo, "component", &error);
618 g_assert_no_error (error);
619 g_assert_nonnull (component);
620
621 /* check this passes */
622 task = fu_install_task_new (device2, component);
561623 ret = fu_engine_check_requirements (engine, task,
562624 FWUPD_INSTALL_FLAG_NONE,
563625 &error);
36123674 { 0xffffffff, "18.31.255.65535", FWUPD_VERSION_FORMAT_INTEL_ME },
36133675 { 0x0b32057a, "11.11.50.1402", FWUPD_VERSION_FORMAT_INTEL_ME },
36143676 { 0xb8320d84, "11.8.50.3460", FWUPD_VERSION_FORMAT_INTEL_ME2 },
3677 { 0x226a4b00, "137.2706.768", FWUPD_VERSION_FORMAT_SURFACE_LEGACY },
3678 { 0x6001988, "6.25.136", FWUPD_VERSION_FORMAT_SURFACE },
36153679 { 0, NULL }
36163680 };
36173681 struct {
38133877 g_assert_cmpint (g_bytes_get_size (data_fw), ==, 136);
38143878
38153879 /* get the signed image */
3816 data_sig = fu_firmware_get_image_by_id_bytes (firmware, "signature", &error);
3880 data_sig = fu_firmware_get_image_by_id_bytes (firmware,
3881 FU_FIRMWARE_IMAGE_ID_SIGNATURE,
3882 &error);
38173883 g_assert_no_error (error);
38183884 g_assert_nonnull (data_sig);
38193885 data = g_bytes_get_data (data_sig, &len);
41634229 g_test_add_func ("/fwupd/engine{downgrade}", fu_engine_downgrade_func);
41644230 g_test_add_func ("/fwupd/engine{requirements-success}", fu_engine_requirements_func);
41654231 g_test_add_func ("/fwupd/engine{requirements-missing}", fu_engine_requirements_missing_func);
4232 g_test_add_func ("/fwupd/engine{requirements-parent-device}", fu_engine_requirements_parent_device_func);
41664233 g_test_add_func ("/fwupd/engine{requirements-not-child}", fu_engine_requirements_child_func);
41674234 g_test_add_func ("/fwupd/engine{requirements-not-child-fail}", fu_engine_requirements_child_fail_func);
41684235 g_test_add_func ("/fwupd/engine{requirements-unsupported}", fu_engine_requirements_unsupported_func);
10131013 static gboolean
10141014 fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error)
10151015 {
1016 if (priv->flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) {
1017 g_set_error_literal (error,
1018 FWUPD_ERROR,
1019 FWUPD_ERROR_INVALID_ARGS,
1020 "--allow-older is not supported for this command");
1021 return FALSE;
1022 }
1023
1024 if (priv->flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) {
1025 g_set_error_literal (error,
1026 FWUPD_ERROR,
1027 FWUPD_ERROR_INVALID_ARGS,
1028 "--allow-reinstall is not supported for this command");
1029 return FALSE;
1030 }
1031
10161032 if (g_strv_length (values) > 1) {
10171033 g_set_error_literal (error,
10181034 FWUPD_ERROR,
3232 typedef struct
3333 {
3434 GUdevDevice *udev_device;
35 guint16 vendor;
36 guint16 model;
35 guint32 vendor;
36 guint32 model;
3737 guint8 revision;
3838 gchar *subsystem;
3939 gchar *device_file;
4242 } FuUdevDevicePrivate;
4343
4444 G_DEFINE_TYPE_WITH_PRIVATE (FuUdevDevice, fu_udev_device, FU_TYPE_DEVICE)
45
46 #ifndef HAVE_GUDEV_232
47 #pragma clang diagnostic push
48 #pragma clang diagnostic ignored "-Wunused-function"
49 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
50 #pragma clang diagnostic pop
51 #endif
5245
5346 enum {
5447 PROP_0,
8376 g_signal_emit (self, signals[SIGNAL_CHANGED], 0);
8477 }
8578
86 static guint64
87 fu_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *udev_device, const gchar *name)
88 {
89 return fu_common_strtoull (g_udev_device_get_sysfs_attr (udev_device, name));
90 }
91
92 static guint16
93 fu_udev_device_read_uint16 (const gchar *str)
94 {
95 gchar buf[5] = { 0x0, 0x0, 0x0, 0x0, 0x0 };
96 memcpy (buf, str, 4);
97 return (guint16) g_ascii_strtoull (buf, NULL, 16);
79 static guint32
80 fu_udev_device_get_sysfs_attr_as_uint32 (GUdevDevice *udev_device, const gchar *name)
81 {
82 guint64 tmp = fu_common_strtoull (g_udev_device_get_sysfs_attr (udev_device, name));
83 if (tmp > G_MAXUINT32) {
84 g_warning ("reading %s for %s overflowed",
85 name,
86 g_udev_device_get_sysfs_path (udev_device));
87 return G_MAXUINT32;
88 }
89 return tmp;
90 }
91
92 static guint8
93 fu_udev_device_get_sysfs_attr_as_uint8 (GUdevDevice *udev_device, const gchar *name)
94 {
95 guint64 tmp = fu_common_strtoull (g_udev_device_get_sysfs_attr (udev_device, name));
96 if (tmp > G_MAXUINT8) {
97 g_warning ("reading %s for %s overflowed",
98 name,
99 g_udev_device_get_sysfs_path (udev_device));
100 return G_MAXUINT8;
101 }
102 return tmp;
98103 }
99104
100105 static void
101106 fu_udev_device_dump_internal (GUdevDevice *udev_device)
102107 {
103 #ifdef HAVE_GUDEV_232
104108 const gchar * const *keys;
105109
106110 keys = g_udev_device_get_property_keys (udev_device);
113117 g_debug ("%s=[%s]", keys[i],
114118 g_udev_device_get_sysfs_attr (udev_device, keys[i]));
115119 }
116 #endif
117120 }
118121
119122 void
141144 return TRUE;
142145
143146 /* set ven:dev:rev */
144 priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "vendor");
145 priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "device");
146 priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "revision");
147 priv->vendor = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "vendor");
148 priv->model = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "device");
149 priv->revision = fu_udev_device_get_sysfs_attr_as_uint8 (priv->udev_device, "revision");
147150
148151 /* fallback to the parent */
149152 udev_parent = g_udev_device_get_parent (priv->udev_device);
150153 if (udev_parent != NULL &&
151154 priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0) {
152 priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "vendor");
153 priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "device");
154 priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "revision");
155 priv->vendor = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "vendor");
156 priv->model = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "device");
157 priv->revision = fu_udev_device_get_sysfs_attr_as_uint8 (udev_parent, "revision");
155158 }
156159
157160 /* hidraw helpfully encodes the information in a different place */
159162 priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0 &&
160163 g_strcmp0 (priv->subsystem, "hidraw") == 0) {
161164 tmp = g_udev_device_get_property (udev_parent, "HID_ID");
162 if (tmp != NULL && strlen (tmp) == 22) {
163 priv->vendor = fu_udev_device_read_uint16 (tmp + 10);
164 priv->model = fu_udev_device_read_uint16 (tmp + 18);
165 if (tmp != NULL) {
166 g_auto(GStrv) split = g_strsplit (tmp, ":", -1);
167 if (g_strv_length (split) == 3) {
168 guint64 val = g_ascii_strtoull (split[1], NULL, 16);
169 if (val > G_MAXUINT32) {
170 g_warning ("reading %s for %s overflowed",
171 split[1],
172 g_udev_device_get_sysfs_path (priv->udev_device));
173 } else {
174 priv->vendor = val;
175 }
176 val = g_ascii_strtoull (split[2], NULL, 16);
177 if (val > G_MAXUINT32) {
178 g_warning ("reading %s for %s overflowed",
179 split[2],
180 g_udev_device_get_sysfs_path (priv->udev_device));
181 } else {
182 priv->model = val;
183 }
184 }
165185 }
166186 tmp = g_udev_device_get_property (udev_parent, "HID_NAME");
167187 if (tmp != NULL) {
422442 *
423443 * Since: 1.1.2
424444 **/
425 guint16
445 guint32
426446 fu_udev_device_get_vendor (FuUdevDevice *self)
427447 {
428448 FuUdevDevicePrivate *priv = GET_PRIVATE (self);
440460 *
441461 * Since: 1.1.2
442462 **/
443 guint16
463 guint32
444464 fu_udev_device_get_model (FuUdevDevice *self)
445465 {
446466 FuUdevDevicePrivate *priv = GET_PRIVATE (self);
615635 FuUdevDevicePrivate *priv = GET_PRIVATE (self);
616636
617637 g_return_if_fail (FU_IS_UDEV_DEVICE (self));
618 g_return_if_fail (fd > 0);
619
620638 if (priv->fd > 0)
621639 close (priv->fd);
622640 priv->fd = fd;
648666 FuUdevDeviceClass *klass = FU_UDEV_DEVICE_GET_CLASS (device);
649667
650668 /* open device */
651 priv->fd = g_open (priv->device_file, priv->readonly ? O_RDONLY : O_RDWR);
652 if (priv->fd < 0) {
653 g_set_error (error,
654 G_IO_ERROR,
655 G_IO_ERROR_FAILED,
656 "failed to open %s: %s",
657 priv->device_file,
658 strerror (errno));
659 return FALSE;
669 if (priv->device_file != NULL) {
670 priv->fd = g_open (priv->device_file, priv->readonly ? O_RDONLY : O_RDWR);
671 if (priv->fd < 0) {
672 g_set_error (error,
673 G_IO_ERROR,
674 G_IO_ERROR_FAILED,
675 "failed to open %s: %s",
676 priv->device_file,
677 strerror (errno));
678 return FALSE;
679 }
660680 }
661681
662682 /* subclassed */
720740 g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE);
721741 g_return_val_if_fail (request != 0x0, FALSE);
722742 g_return_val_if_fail (buf != NULL, FALSE);
743 g_return_val_if_fail (priv->fd > 0, FALSE);
723744
724745 rc_tmp = ioctl (priv->fd, request, buf);
725746 if (rc != NULL)
762783
763784 g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE);
764785 g_return_val_if_fail (port != 0x0, FALSE);
786 g_return_val_if_fail (priv->fd > 0, FALSE);
765787
766788 if (pwrite (priv->fd, &data, 1, port) != 1) {
767789 g_set_error (error,
796818 g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE);
797819 g_return_val_if_fail (port != 0x0, FALSE);
798820 g_return_val_if_fail (data != NULL, FALSE);
821 g_return_val_if_fail (priv->fd > 0, FALSE);
799822
800823 if (pread (priv->fd, data, 1, port) != 1) {
801824 g_set_error (error,
3030 const gchar *fu_udev_device_get_device_file (FuUdevDevice *self);
3131 const gchar *fu_udev_device_get_sysfs_path (FuUdevDevice *self);
3232 const gchar *fu_udev_device_get_subsystem (FuUdevDevice *self);
33 guint16 fu_udev_device_get_vendor (FuUdevDevice *self);
34 guint16 fu_udev_device_get_model (FuUdevDevice *self);
33 guint32 fu_udev_device_get_vendor (FuUdevDevice *self);
34 guint32 fu_udev_device_get_model (FuUdevDevice *self);
3535 guint8 fu_udev_device_get_revision (FuUdevDevice *self);
3636 guint fu_udev_device_get_slot_depth (FuUdevDevice *self,
3737 const gchar *subsystem);
1111 #include "fu-usb-device-private.h"
1212
1313 /**
14 * SECTION:fu-device
14 * SECTION:fu-usb-device
1515 * @short_description: a USB device
1616 *
1717 * An object that represents a USB device.
128128 idx = g_usb_device_get_manufacturer_index (priv->usb_device);
129129 if (idx != 0x00) {
130130 g_autofree gchar *tmp = NULL;
131 g_autoptr(GError) error_local = NULL;
131132 tmp = g_usb_device_get_string_descriptor (priv->usb_device,
132 idx, error);
133 if (tmp == NULL)
134 return FALSE;
135 fu_device_set_vendor (device, g_strchomp (tmp));
133 idx, &error_local);
134 if (tmp != NULL)
135 fu_device_set_vendor (device, g_strchomp (tmp));
136 else
137 g_debug ("failed to load manufacturer string for usb device %u:%u: %s",
138 g_usb_device_get_bus (priv->usb_device),
139 g_usb_device_get_address (priv->usb_device),
140 error_local->message);
136141 }
137142 }
138143
141146 idx = g_usb_device_get_product_index (priv->usb_device);
142147 if (idx != 0x00) {
143148 g_autofree gchar *tmp = NULL;
149 g_autoptr(GError) error_local = NULL;
144150 tmp = g_usb_device_get_string_descriptor (priv->usb_device,
145 idx, error);
146 if (tmp == NULL)
147 return FALSE;
148 fu_device_set_name (device, g_strchomp (tmp));
151 idx, &error_local);
152 if (tmp != NULL)
153 fu_device_set_name (device, g_strchomp (tmp));
154 else
155 g_debug ("failed to load product string for usb device %u:%u: %s",
156 g_usb_device_get_bus (priv->usb_device),
157 g_usb_device_get_address (priv->usb_device),
158 error_local->message);
149159 }
150160 }
151161
154164 idx = g_usb_device_get_serial_number_index (priv->usb_device);
155165 if (idx != 0x00) {
156166 g_autofree gchar *tmp = NULL;
167 g_autoptr(GError) error_local = NULL;
157168 tmp = g_usb_device_get_string_descriptor (priv->usb_device,
158 idx, error);
159 if (tmp == NULL)
160 return FALSE;
161 fu_device_set_serial (device, g_strchomp (tmp));
169 idx, &error_local);
170 if (tmp != NULL)
171 fu_device_set_serial (device, g_strchomp (tmp));
172 else
173 g_debug ("failed to load serial number string for usb device %u:%u: %s",
174 g_usb_device_get_bus (priv->usb_device),
175 g_usb_device_get_address (priv->usb_device),
176 error_local->message);
162177 }
163178 }
164179
357372 }
358373
359374 /**
375 * fu_usb_device_get_spec:
376 * @self: A #FuUsbDevice
377 *
378 * Gets the string USB revision for the device.
379 *
380 * Return value: a specification revision in BCD format, or 0x0 if not supported
381 *
382 * Since: 1.3.4
383 **/
384 guint16
385 fu_usb_device_get_spec (FuUsbDevice *self)
386 {
387 #if G_USB_CHECK_VERSION(0,3,1)
388 FuUsbDevicePrivate *priv = GET_PRIVATE (self);
389 g_return_val_if_fail (FU_IS_USB_DEVICE (self), 0x0);
390 if (priv->usb_device == NULL)
391 return 0x0;
392 return g_usb_device_get_spec (priv->usb_device);
393 #else
394 return 0x0;
395 #endif
396 }
397
398 /**
360399 * fu_usb_device_set_dev:
361400 * @device: A #FuUsbDevice
362401 * @usb_device: A #GUsbDevice, or %NULL
3939 FuUsbDevice *fu_usb_device_new (GUsbDevice *usb_device);
4040 guint16 fu_usb_device_get_vid (FuUsbDevice *self);
4141 guint16 fu_usb_device_get_pid (FuUsbDevice *self);
42 guint16 fu_usb_device_get_spec (FuUsbDevice *self);
4243 GUsbDevice *fu_usb_device_get_dev (FuUsbDevice *device);
4344 void fu_usb_device_set_dev (FuUsbDevice *device,
4445 GUsbDevice *usb_device);
251251 }
252252
253253 gchar *
254 fu_util_get_versions (void)
254 fu_util_get_client_version (void)
255255 {
256256 GString *string = g_string_new ("");
257257
258258 g_string_append_printf (string,
259 "client version:\t%i.%i.%i\n",
259 "%i.%i.%i",
260260 FWUPD_MAJOR_VERSION,
261261 FWUPD_MINOR_VERSION,
262262 FWUPD_MICRO_VERSION);
263 #ifdef FWUPD_GIT_DESCRIBE
263 #ifdef FWUPD_DIRTY_VERSION
264264 g_string_append_printf (string,
265 "checkout info:\t%s\n", FWUPD_GIT_DESCRIBE);
265 "-%i-%s",
266 FWUPD_DIRTY_VERSION,
267 FWUPD_COMMIT_VERSION);
266268 #endif
269 return g_string_free (string, FALSE);
270 }
271
272 gchar *
273 fu_util_get_versions (void)
274 {
275 GString *string = g_string_new ("");
276 g_autofree gchar *client_version = fu_util_get_client_version ();
277
278 g_string_append_printf (string, "client version:\t%s\n", client_version);
267279 g_string_append_printf (string,
268280 "compile-time dependency versions\n");
269281 g_string_append_printf (string,
3333 gchar *fu_util_get_user_cache_path (const gchar *fn);
3434 SoupSession *fu_util_setup_networking (GError **error);
3535
36 gchar *fu_util_get_client_version (void);
3637 gchar *fu_util_get_versions (void);
3738
3839 void fu_util_warning_box (const gchar *str,
19131913 static gboolean
19141914 fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error)
19151915 {
1916 if (priv->flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) {
1917 g_set_error_literal (error,
1918 FWUPD_ERROR,
1919 FWUPD_ERROR_INVALID_ARGS,
1920 "--allow-older is not supported for this command");
1921 return FALSE;
1922 }
1923
1924 if (priv->flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) {
1925 g_set_error_literal (error,
1926 FWUPD_ERROR,
1927 FWUPD_ERROR_INVALID_ARGS,
1928 "--allow-reinstall is not supported for this command");
1929 return FALSE;
1930 }
1931
19161932 if (g_strv_length (values) == 0)
19171933 return fu_util_update_all (priv, error);
19181934 if (g_strv_length (values) == 1)
19852001 g_autoptr(FwupdDevice) dev = NULL;
19862002 g_autoptr(FwupdRelease) rel = NULL;
19872003 g_autoptr(GPtrArray) rels = NULL;
2004
2005 if (priv->flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) {
2006 g_set_error_literal (error,
2007 FWUPD_ERROR,
2008 FWUPD_ERROR_INVALID_ARGS,
2009 "--allow-reinstall is not supported for this command");
2010 return FALSE;
2011 }
19882012
19892013 priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED;
19902014 dev = fu_util_get_device_or_prompt (priv, values, error);
22752299 static gboolean
22762300 fu_util_check_daemon_version (FuUtilPrivate *priv, GError **error)
22772301 {
2278 g_autofree gchar *client = g_strdup_printf ("%i.%i.%i",
2279 FWUPD_MAJOR_VERSION,
2280 FWUPD_MINOR_VERSION,
2281 FWUPD_MICRO_VERSION);
2302 g_autofree gchar *client = fu_util_get_client_version ();
22822303 const gchar *daemon = fwupd_client_get_daemon_version (priv->client);
22832304
22842305 if (g_strcmp0 (daemon, client) != 0) {
27212742 #ifdef HAVE_SYSTEMD
27222743 /* make sure the correct daemon is in use */
27232744 if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0 &&
2745 !fwupd_client_get_daemon_interactive (priv->client) &&
27242746 !fu_util_using_correct_daemon (&error)) {
27252747 g_printerr ("%s\n", error->message);
27262748 return EXIT_FAILURE;
5555 </property>
5656
5757 <!--***********************************************************-->
58 <property name='Interactive' type='b' access='read'>
59 <doc:doc>
60 <doc:description>
61 <doc:para>
62 If the daemon is running on an interactive terminal.
63 </doc:para>
64 </doc:description>
65 </doc:doc>
66 </property>
67
68 <!--***********************************************************-->
5869 <property name='Status' type='u' access='read'>
5970 <doc:doc>
6071 <doc:description>
00 [wrap-git]
11 directory = flashrom
2 url = https://github.com/fwupd/flashrom.git
3 revision = wip/hughsie/fwupd
2 url = https://github.com/flashrom/flashrom
3 revision = 2f6936bd926b6d4f21680e2cdc160fc580c3ecb3